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

时间:2018-09-23 12:01:07

标签: parsing webpack abstract-syntax-tree webpack-plugin

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

规则很简单:

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

这是我的代码:

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仅解析一次。

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

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

2 个答案:

答案 0 :(得分:1)

是的。您无法在模块中获取条目信息。     我认为您可以解决的方法可能是不使用入口点。     由于模块在加载后即被缓存,     我们可以利用内联资源查询

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"
        }
    };

答案 1 :(得分:0)

我打开了一个issueTobias Koppers的回复:

  

那不可能。

     

这些模块独立于原始入口点。模块   图不包含此信息。除了那个模块   可以在两个入口点中使用,但在这种情况下不能进行两次构建。