Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to convert Webpack 4 plugin to Webpack 5

How do I convert this plugin that worked on Webpack 4 to Webpack 5?

More specifically, the plugin() function no longer works. How do I replace this to support Webpack 5?

const ConstDependency = require('webpack/lib/dependencies/ConstDependency');
const NullFactory = require('webpack/lib/NullFactory');

class StaticAssetPlugin {
  constructor(localization, options, failOnMissing) {
    this.options = options || {};
    this.localization = localization;
    this.functionName = this.options.functionName || '__';
    this.failOnMissing = !!this.options.failOnMissing;
    this.hideMessage = this.options.hideMessage || false;
  }

  apply(compiler) {
    const { localization } = this;
    const name = this.functionName;

    compiler.plugin('compilation', (compilation, params) => {
      compilation.dependencyFactories.set(ConstDependency, new NullFactory());
      compilation.dependencyTemplates.set(ConstDependency, new ConstDependency.Template());
    });

    compiler.plugin('compilation', (compilation, data) => {
      data.normalModuleFactory.plugin('parser', (parser, options) => {
        // should use function here instead of arrow function due to save the Tapable's context
        parser.plugin(`call ${name}`, function staticAssetPlugin(expr) {
          let param;
          let defaultValue;
          switch (expr.arguments.length) {
            case 1:
              param = this.evaluateExpression(expr.arguments[0]);
              if (!param.isString()) return;
              defaultValue = param = param.string;
              break;
            default:
              return;
          }
          let result = localization(param);

          const dep = new ConstDependency(JSON.stringify(result), expr.range);
          dep.loc = expr.loc;
          this.state.current.addDependency(dep);
          return true;
        });
      });
    });
  }
}

module.exports = StaticAssetPlugin;

Are there any migration guides for plugin creation that I can follow? Any help would be greatly appreciated.

Thanks.

like image 734
Mohammad Dohadwala Avatar asked Oct 27 '25 22:10

Mohammad Dohadwala


1 Answers

You can find suitable environment details needed to run the plugin here. Along with this, you must care about how to access event hooks

compiler.hooks.someHook.tap('MyPlugin', (params) => {
  /* ... */
});

You can get more about it here


Converting your existing plugin to Webpack 5, you can tap a specific event hook and get it done. If you try to run the plugin with the above code with Webpack 5, you will get the below error.

plugin-console-error

Many articles will suggest you update webpack-cli which is not enough.

const ConstDependency = require('webpack/lib/dependencies/ConstDependency');
const NullFactory = require('webpack/lib/NullFactory');

const PLUGIN_NAME = 'StaticAssetPlugin';

class StaticAssetPlugin {
  constructor(localization, options, failOnMissing) {
    this.options = options || {};
    this.localization = localization;
    this.functionName = this.options.functionName || '__';
    this.failOnMissing = !!this.options.failOnMissing;
    this.hideMessage = this.options.hideMessage || false;
  }
  
  apply(compiler) {
    const { localization } = this;
    const name = this.functionName;
    
    compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation, params) => {
      compilation.dependencyFactories.set(ConstDependency, new NullFactory());
      compilation.dependencyTemplates.set(ConstDependency, new ConstDependency.Template());
    });
    
    compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation, data) => {
      data.normalModuleFactory.hooks.parser.for('javascript/auto').tap(PLUGIN_NAME, (parser, options) => {
        parser.hooks.expression.for('this').tap(PLUGIN_NAME, function staticAssetPlugin(expr) {
          let param;
          let defaultValue;
          switch (expr.arguments.length) {
            case 1:
            param = this.evaluateExpression(expr.arguments[0]);
            if (!param.isString()) return;
            defaultValue = param = param.string;
            break;
            default:
            return;
          }
          let result = localization(param);
          
          const dep = new ConstDependency(JSON.stringify(result), expr.range);
          dep.loc = expr.loc;
          this.state.current.addDependency(dep);
          return true;
        });
      })
    });
  }
}

module.exports = StaticAssetPlugin;

Importantly you have to decide which event hook you need to access from compiler and parser. You will get a list of popular hooks here, for the compiler for parser.

You can get a complete list of hooks just by accessing hooks.

for compiler

console.log(compiler.hooks);

for parser

console.log(parser.hooks);

You can choose accordingly.

like image 52
MORÈ Avatar answered Oct 29 '25 13:10

MORÈ