How to cope with “broken modules” in webpack
When you’re writing a web application, you will always come to the point where you want to include some third-party code.
Then, you go on npm, search for the module, install it and everything works out-of-the-box.
This… will hopefully be the case when everyone is using the same module system and we have solved the puzzle how to distribute re-usable web components that bring their own HTML, CSS and images. Until then, we will need to cope with the current mess.
webpack 1 already supported two of the most common module formats out-of-the-box: CommonJS and AMD. webpack 2 will also understand the official ES2015 module syntax which enables webpack to remove unused code more efficiently. But there’s still a lot of code that has been written with no module system at all or in a pretty unusual style.
In this post, I’m going to give you some tips how I usually try to include third-party scripts. It was originally posted on Stack Overflow, but since I still get positive feedback, I think it might also be valuable for you.
Tip 1: Prefer unminified source over dist
Most modules link the pre-bundled dist version in the main field of their package.json. While this is useful for developers without a module bundler, for webpack users it is better to alias the source version. This avoids the usual module system overhead of pre-bundled files. However, in most cases the dist version works just fine as well.
Tip 2: Use the ProvidePlugin to inject implicit globals
Most legacy modules rely on the presence of specific globals, like jQuery plugins do on $ or jQuery. In this scenario, you can configure webpack to prepend var $ = require(“jquery”) everytime it encounters the global $ identifier:
The ProvidePlugin is a good way to “teach” legacy dependencies, that they should import everything they need instead of relying on the presence of a global variable.
Tip 3: Use the imports-loader to configure `this`
Some legacy modules rely on this being the window object. This becomes a problem when the module is executed with webpack where this equals module.exports (in the style of CommonJS). In this case, you can override this with the imports-loader.
Since all loaders are not included in webpack core, you need to run npm i imports-loader — save-dev first and then:
The imports-loader puts code before the actual module. It can be used to bootstrap it if there are any problems. For instance, it can also be used to manually inject variables of all kinds. But most of the time the ProvidePlugin is more useful when it comes to implicit globals.
Tip 4: Fix a module style with the imports-loader and exports-loader
Some dependencies use a module style in an unusual way that may conflict with webpack. In this case it may help to fool the third-party code that there is no module system at all. Most modules will then fall back to a global variable which you can export using the exports-loader. We are working on this to make it easier in future webpack versions.
Tip 5: Use the script-loader to import scripts globally
If you don’t care about global variables and just want legacy scripts to work, you can also use the script-loader. It executes the module in a global context, just as if you had included them via <script> tag.
In this case, require() will not return something meaningful. Just access the global variable afterwards:
Tip 6: Use `noParse` to include large dists
When there is no source version of the module and you want to include the dist, you can flag this file as noParse. In this case, webpack will just include the file without parsing it, which can be used to improve the build time.
But be careful: This also means that any feature requiring the AST, like the ProvidePlugin, will not work inside this file. webpack just takes the source code without looking at it.