【发布时间】:2021-06-30 00:05:29
【问题描述】:
我遇到了为我们的前端管道构建插件的困境,我将首先解释我们想要实现的目标,然后是问题。首先,我们有一组必须在构建时用“true”或“false”替换的变量,然后是一组必须重命名的变量名和一些其他自定义。我举个例子吧。
- 每个
DCE_HAS_MODULE_PRE_ORDERS都必须替换为false - 任何出现的
/ST__[A-Z_]+/g(ST__MODULE_SETTING) 都将被重命名为ST1或ST53,无论在何处使用。
到目前为止,我们已经读取了 webpack 的输出文件,替换,然后再次写入磁盘,它可以工作。但这并不允许我们使用 webpack 的全部功能,所以我们想利用 webpack 的内在力量来实现它。
这是解决问题的代码。
function prependStorefrontDCE() {
let currentSTIdx = 1;
const files = fs.readdirSync(outputDirPath).filter((e) => e.endsWith('.js'));
files.forEach((filename) => {
const filePath = outputDirPath + '/' + filename;
let payload = fs.readFileSync(filePath, 'utf8');
// @TODO: allow a way to define custom DCEs
// set custom DCEs to false
payload = payload.replace(/DCE_HAS_MODULE_PRE_ORDERS/g, 'false');
{
// Collect unique settings variables
let stVariables = new Set(payload.match(/ST__[A-Z_]+/g));
// Define a unique id for each one
let stUniqueIds = {};
stVariables.forEach(st => {
stUniqueIds[st] = `ST${currentSTIdx++}`;
});
// Declare settings in upper scope
stVariables = Array.from(stVariables).map(st => `let ${st} = null;`);
stVariables.push('let DCE = null;');
stVariables.push('ST__MODULES = {1: {}, 46: {}, 53: {}};');
stVariables.push('let URL_HTTP_HOST = "";');
let dceJS = stVariables.join('');
// add closure JS
payload = dceJS + payload;
console.log(dceJS);
// obfuscation for settings variables using the unique id
payload = payload.replace(/ST__[A-Z_]+/g, (match) => stUniqueIds[match]);
}
{
// Collect unique settings variables
let stVariables = new Set(payload.match(/DCE_[A-Z_]+/g));
// Define a unique id for each one
let stUniqueIds = {};
stVariables.forEach(st => {
stUniqueIds[st] = `DCE${currentSTIdx++}`;
});
// Declare settings in upper scope
stVariables = Array.from(stVariables).map(st => `let ${st} = true;`);
let dceJS = stVariables.join('');
// add closure JS
payload = dceJS + payload;
// obfuscation for settings variables using the unique id
payload = payload.replace(/DCE_[A-Z_]+/g, (match) => stUniqueIds[match]);
}
// remove DCE from CSS
payload = payload.replace(dceInCssRegex, '');
// set all DCE booleans to true
payload = payload.replace(dceHasRegex, 'true');
payload = payload.replace(dceRequireRegex, 'true');
// write file
fs.writeFileSync(filePath, payload);
});
}
这就是我们使用它的方式。
compiler.hooks.afterEmit.tap('after-build', async () => {
if (IS_PRODUCTION) {
// step 1/2
mangleProps();
}
// step 2/2
prependStorefrontDCE();
});
但是为了在 webpack 模块中进行替换,我尝试了很多方法,但似乎没有一种方法能按预期工作。我查看了很多插件并尝试了钩子和方法,但没有任何结果。 DefinePlugin 似乎满足了一半的要求,但它不允许根据正则表达式查找变量并用自定义替换它们。
这是我尝试过的一部分。
compiler.hooks.run.tapAsync(
'DCEs', (compilation) => {
compilation.hooks.processAssets.tap(() => {
// Get the assets of webpack
const assets = compilation.getAssets();
// When processing assets, use the function to replace variable name
assets.forEach(asset => {
console.log('\n UpdateAsset', asset.name, '\n');
compilation.updateAsset(asset.name, (source) => {
return prependStorefrontDCE(source.source());
});
});
});
},
);
【问题讨论】:
标签: node.js algorithm web webpack pipeline