使webpack解析以下类型的上下文依赖项:require(someVariable)



我试图绑定一个nestjs应用程序以在lambda中运行它。但是放弃了。过了一段时间,我尝试使用一个新创建的连接到mysqlnestjs应用程序来执行同样的操作。问题是sequelize以这种方式需要mysql2

require(moduleName);

嗯,它需要我要求它使用的方言,但在这种情况下,它是mysql2。显然,webpack自己对此无能为力,只好退出。我按照他们的建议解决了这个问题。但后来我想;我想知道webpack是否可以替换特定文件中的特定行"或者更确切地说,假装它不同。假设它读取的不是require(moduleName),而是require('mysql2')

还有一个类似的问题,但我特别针对nodejs。我担心的是webpack-speak中的上下文依赖。请求是表达式而不是字符串的依赖项。

这里不能应用ContextReplacementPlugin,因为对于单个标识符,请求总是.(这样的请求是不可区分的(。NormalReplacementPlugin不适用,因为这是一个上下文依赖项。DefinePlugin似乎不能胜任这项任务,因为它不允许您替换任何您喜欢的东西,特别是局部变量和函数参数。

如果您对捆绑nodejs应用程序感兴趣,您可能想看看这个问题。这里我关注的是webpack和上下文依赖关系。

附言:虽然我找到了一个不需要解决上下文依赖关系的解决方案,但我可能会在以后遇到它。或者其他人。

UPD这里有一个无法像nestjs+sequelize+mysql2那样解决的案例。sequelize-typescript在运行时加载模型:

https://github.com/RobinBuschmann/sequelize-typescript/blob/v2.1.1/src/sequelize/sequelize/sequelize-service.ts#L51

免责声明。所提供的实现可能不适用于您。您可能需要对其进行修改以使用您的webpack版本。此外,我的目标是nodejs(而不是浏览器(,因此我忽略了源映射。

假设您有src/index.js:

const mysql2 = require('whatever');

以及以下软件包:

{
"dependencies": {
"mysql2": "2.3.3",
"webpack": "5.64.2",
"webpack-cli": "4.9.1"
}
}

webpack.config.js:

const path = require('path');
const RewriteRequirePlugin = require('./rewrite-require-plugin');
module.exports = {
mode: 'development',
target: 'node',
module: {
rules: [
// {test: path.resolve('src/index.js'),
// use: [
//     {loader: path.resolve('rewrite-require-loader.js'),
//     options: {
//         search: "'whatever'",
//         replace: JSON.stringify('mysql2'),
//     }},
// ]}
],
},
plugins: [
// new RewriteRequirePlugin([
//     [path.resolve('src/index.js'),
//         "'whatever'",
//         JSON.stringify('mysql2')],
// ])
],
stats: {
modulesSpace: Infinity,
groupModulesByPath: false,
}
};

它不会建立。但是如果你取消对插件或加载程序的注释,它会的。

rewrite-require-loader.js:

// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping
function escapeRegExp(string) {
return string.replace(/[.*+?^${}()|[]\]/g, '\$&'); // $& means the whole matched string
}
function processFile(source, search, replace) {
const re = `require\(${escapeRegExp(search)}\)`;
return source.replace(
new RegExp(re, 'g'),
`require(${replace})`);
}
module.exports = function(source) {
const options = this.getOptions();
return processFile(source, options.search, options.replace);
};

rewrite-require-plugin.js:

const path = require('path');
const NormalModule = require('webpack/lib/NormalModule');
// https://github.com/webpack/loader-runner/blob/v4.2.0/lib/LoaderRunner.js#L9-L16
function utf8BufferToString(buf) {
var str = buf.toString("utf-8");
if(str.charCodeAt(0) === 0xFEFF) {
return str.substr(1);
} else {
return str;
}
}
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping
function escapeRegExp(string) {
return string.replace(/[.*+?^${}()|[]\]/g, '\$&'); // $& means the whole matched string
}
function processFile(source, search, replace) {
source = Buffer.isBuffer(source) ? utf8BufferToString(source) : source;
const re = `require\(${escapeRegExp(search)}\)`;
return source.replace(
new RegExp(re, 'g'),
`require(${replace})`);
}
class RewriteRequirePlugin {
constructor(rewrites) {
this.rewrites = rewrites.map(r => [path.resolve(r[0]), r[1], r[2]]);
}
apply(compiler) {
compiler.hooks.compilation.tap('RewriteRequirePlugin', compilation => {
// https://github.com/webpack/webpack/blob/v5.64.2/lib/schemes/FileUriPlugin.js#L36-L43
const hooks = NormalModule.getCompilationHooks(compilation);
hooks.readResource
.for(undefined)
.tapAsync("FileUriPlugin", (loaderContext, callback) => {
const { resourcePath } = loaderContext;
loaderContext.addDependency(resourcePath);
loaderContext.fs.readFile(resourcePath, (err, data) => {
if (err) return callback(err, data);
callback(
err,
this.rewrites.reduce(
(prev, cur) =>
resourcePath == cur[0]
? processFile(data, cur[1], cur[2])
: data,
data));
});
});
});
}
};
module.exports = RewriteRequirePlugin;

相关内容

最新更新