Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write Webpack plugin which adds modules to the bundle on the fly based on other modules?

I have a problem with writing a Webpack plugin for a translation service.

The goal is to:

  1. Get names (and source code) of all required modules during compilation. I need to be able to scan the included source code for special t() function usage but I want to scan only those modules which will be included in the bundle (which, depending on build configuration, can be a subset of all project modules).
  2. Based on the gathered modules, I want to create additional modules (with translations) on the fly and add them to the bundle. Those modules need to be able to import their own dependencies.

An additional requirement is that the Webpack's code splitting feature should work with the modules created on the fly (I want to extract them to separate files – e.g. bundle.[lang].js). Also, which may be out of the scope of this question, I must make those chunks with translations optional (so you don't have to load all languages, but just one).

More details can be found in https://github.com/ckeditor/ckeditor5/issues/387.

I've been trying multiple solutions, but Webpack 2's documentation is not very helpful. I can get all the modules by listening to module resolution hooks (before-resolve), but I don't know when all the dependencies are resolved and I don't know if I can add more modules after that (and how to do that – is addEntry ok and when I can use it?).

I was also thinking on connecting Webpack plugin and Webpack loader (because the feature I need is pretty similar to Webpack's style-loader), but from the plugin level I can only add path to the loader, not the loader itself, so I can't pass the config object as a parameter – am I wrong?

PS. I use Webpack 2. If the requirements seem strange to you, please see https://github.com/ckeditor/ckeditor5/issues/387 :).

like image 663
Maciej Bukowski Avatar asked Jan 26 '17 08:01

Maciej Bukowski


People also ask

Does webpack bundle Node_modules?

Webpack allows you to define externals - modules that should not be bundled. When bundling with Webpack for the backend - you usually don't want to bundle its node_modules dependencies. This library creates an externals function that ignores node_modules when bundling in Webpack.

Does webpack automatically minify?

Webpack v4+ will minify your code by default in production mode .

Can webpack have multiple entry points?

webpack.config.jsWe can also pass an array of file paths to the entry property which creates what is known as a "multi-main entry". This is useful when you would like to inject multiple dependent files together and graph their dependencies into one "chunk".

How do I bundle files with webpack?

You can bundle your JavaScript using the CLI command by providing an entry file and output path. Webpack will automatically resolve all dependencies from import and require and bundle them into a single output together with your app's script.


1 Answers

This is a really complex question, but I can show how you can add additional dependencies to specific modules as if those were required from that module. This ensures that your added modules will be in the correct chunks and will also be removed if the parent module is removed from the bundle.

const CommonJsRequireDependency = require("webpack/lib/dependencies/CommonJsRequireDependency")  class MyPlugin {   apply(compiler) {     compiler.plugin("compilation", compilation => {       compilation.plugin("succeed-module", module => {         // this will be called for every successfully built module, but before it's parsed and         // its dependencies are built. The built source is available as module._source.source()         // and you can add additional dependencies like so:         module.dependencies.push(new CommonJsRequireDependency("my-dependency", null))       }     }   } } 

This is just one part of it. You'll also likely need to write your own loader to actually generate the translations (you can replace my-dependency above with my-loader!path/to/module to invoke it immediately) and some step after the chunks are created to perhaps extract them into a new asset and load them since they aren't actually required anywhere.

like image 134
Gunchars Avatar answered Sep 18 '22 11:09

Gunchars