【问题标题】:How can I replace variable names on the fly using webpack?如何使用 webpack 动态替换变量名?
【发布时间】:2021-06-30 00:05:29
【问题描述】:

我遇到了为我们的前端管道构建插件的困境,我将首先解释我们想要实现的目标,然后是问题。首先,我们有一组必须在构建时用“true”或“false”替换的变量,然后是一组必须重命名的变量名和一些其他自定义。我举个例子吧。

  • 每个DCE_HAS_MODULE_PRE_ORDERS 都必须替换为false
  • 任何出现的/ST__[A-Z_]+/g (ST__MODULE_SETTING) 都将被重命名为ST1ST53,无论在何处使用。

到目前为止,我们已经读取了 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


    【解决方案1】:

    对于任何寻求答案的人,我是这样做的:

    compiler.hooks.thisCompilation.tap('STs&DCEs', (compilation) => {
        compilation.hooks.processAssets.tap(
            {
                name: 'STs&DCEs',
                stage: Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE,
            },
            () => {
                // Get main file
                const file = compilation.getAsset('index.bundle.js');
                let payload = file.source.source();
    
                // Step 1/2
                payload = prependStorefrontDCE(payload);
    
    
                // Update the file
                compilation.updateAsset(
                    'index.bundle.js',
                    new sources.RawSource(payload),
                );
            },
        );
    });
    

    您也可以将它用于多个资产。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多