Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Recently, I started learning how to build webpack plugins. I'm trying to build a plugin that will update my source code.

The rules are simple:

  1. If the entry point name has less than 2 as, I have to rename all the variables haha to hehe in all modules in the chunk of the said entry point.
  2. If the entry point name has more than 2 as, I have to rename all the variables haha to hoho of all modules in the chunk of the said entry point.

This is my code:

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')
 }
};

I don't know exactly what the proper way to do that.

At the beginning, I thought that my plugin has to register to a specific hook of the parser, check the name of the current entry point and replace the name of the AST node. The problem is that the module a.js is parsed only once.

The second way I tried is to register to the render hook of the mainTemplate and rename variables via a simple regex. I don't like this method since code replacing via regex is extremely difficult (IMO).

What do you think? What is the proper way to that?

like image 568
Raphael Boukara Avatar asked Sep 23 '18 12:09

Raphael Boukara


1 Answers

Ya right. You can't get entry info in modules. I think you can solve may be in other way not using entry point. As modules are cached once it is loaded, we can make use of inline resource query

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

custom loader -> 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"
        }
    };
like image 189
santy Avatar answered Oct 07 '22 23:10

santy