如何更新每个块的模块源代码?

How to update the source code of a module per chunk?

最近,我开始学习如何构建 webpack 插件。我正在尝试构建一个插件来更新我的源代码。

规则很简单:

  1. 如果入口点名称少于2个a,我必须将所有变量haha重命名为hehe所述 入口点 .
  2. 块中的所有模块
  3. 如果入口点名称超过2个a,我必须将所有变量haha重命名为hoho所述 入口点 .
  4. 块中的所有模块

这是我的代码:

a.js

const haha = 'hello';
// will be "const hehe = 'hello';" in the bundle of "aa" entry point
// will be "const hoho = 'hello';" in the bundle of "aaaa" entry point
console.log(haha);
// will be "console.log(hehe);" in the bundle of "aa" entry point
// will be "console.log(hoho);" in the bundle of "aaaa" entry point
export default haha;
// will be "export default hehe;" in the bundle of "aa" entry point
// will be "export default hoho;" in the bundle of "aaaa" entry point

few.js

import haha from 'a'; // will be "import hehe from 'a';" in the bundle
console.log(haha); // will be "console.log(hehe);" in the bundle

lots.js

import haha from 'a'; // will be "import hoho from 'a';" in the bundle
console.log(haha); // will be "console.log(hoho);" in the bundle

webpack.config.js

module.exports = {
 mode: 'development',
 entry: {
    aa: 'few.js',
    aaaa: 'lots.js'
 },
 output: {
    filename: '[name].js',
    path: path.resolve(__dirname, 'dist')
 }
};

我不知道正确的做法是什么。

一开始,我认为我的插件必须注册到解析器的特定钩子,检查当前入口点的名称并替换AST的名称节点。问题是模块 a.js 只被解析了一次。

我尝试的第二种方法是注册到 mainTemplaterender 挂钩并通过简单的正则表达式重命名变量。我不喜欢这种方法,因为通过正则表达式替换代码非常困难 (IMO)。

你怎么看?正确的方法是什么?

我打开了一个issue. Response from Tobias Koppers:

That's not possible.

The modules are independent from the original entrypoint. The module graph doesn't contain this information. In addition to that modules can be in both entrypoints, but are not build twice in this case.

没错。您无法在模块中获取条目信息。 我认为您可以通过不使用入口点的其他方式解决。 由于模块一旦加载就会被缓存, 我们可以利用内联资源查询

a.js

    const haha = 'hello';
    console.log(haha);
    export default haha;

few.js

    import haha from './a?change=e'; // will be "import hehe from 'a';" in the bundle
    console.log(haha); // will be "console.log(hehe);" in the bundle

lots.js

    import haha from './a?change=o'; // will be "import hehe from 'a';" in the bundle
    console.log(haha); // will be "console.log(hoho);" in the bundle

自定义加载器 -> transformer.js

    module.exports = function(source) {
      let queryval = "";
      if (this.resourceQuery && this.resourceQuery.indexOf('change')) {
        queryval = this.resourceQuery.substr(this.resourceQuery.indexOf("change"+ 1));
        // console.log("queryval: ", queryval);
        if (queryval) {
          const replacedCode = source.replace(/[a]/g, queryval); // this replace every thing but need own logic even default -> def_ult _ is query val :P
          console.log("replacedCode: ", replacedCode);
          return replacedCode;
        }
      }
      return source;
    }

webpack.config.js

    const path = require('path');

    module.exports = {
        mode: 'development',
        entry: {
            aa: './src/few.js',
            aaaa: './src/lots.js'
        },
        module: {
          rules: [
            {
              test: /\.js$/,
                oneOf: [
                  {
                    resourceQuery: /change/,
                    use: [
                      {
                        loader: path.resolve('./src/transformer.js'),
                        options: {
                          replaceWith: true
                        }
                      }
                    ],
                  },
                  {
                    loader: path.resolve('./src/transformer.js'),
                  }
                ],
            }
          ]
        },
        output: {
            filename: '[name].js',
            path: path.resolve(__dirname, 'dist')
        },
        optimization: {
          runtimeChunk: "single"
        }
    };