W3cubDocs

/webpack 2

Shimming

webpack as a module bundler can understand modules written as ES2015 modules, CommonJS or AMD. But many times, while using third party libraries, we see that they expect dependencies which are global, AKA $ for jquery. They might also be creating global variables which need to be exported. Here we will see different ways to help webpack understand these broken modules.

Prefer unminified CommonJS/AMD files over bundled dist versions.

Most modules link the dist version in the main field of their package.json. While this is useful for most developers, for webpack it is better to alias the src version because this way webpack is able to optimize dependencies better. However in most cases dist works fine as well.

// webpack.config.js

module.exports = {
    ...
    resolve: {
        alias: {
            jquery: "jquery/src/jquery"
        }
    }
};

ProvidePlugin

The ProvidePlugin makes a module available as a variable in every other module required by webpack. The module is required only if you use the variable. 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”) every time it encounters the global $ identifier.

module.exports = {
  plugins: [
    new webpack.ProvidePlugin({
      $: 'jquery',
      jQuery: 'jquery'
    })
  ]
};

This plugin is also capable of providing only a certain export of a module by configuring it with an array path using this format: [module, child, ...children?] The following configuration will correctly import function __assign from TypeScript's tslib package, and provide it wherever it's invoked.

module.exports = {
  plugins: [
    new webpack.ProvidePlugin({
      __assign: ['tslib', '__assign'],
      __extends: ['tslib', '__extends'],
    })
  ]
};

imports-loader

imports-loader inserts necessary globals into the required legacy module. For example, Some legacy modules rely on this being the window object. This becomes a problem when the module is executed in a CommonJS context where this equals module.exports. In this case you can override this using the imports-loader.

webpack.config.js

module.exports = {
  module: {
    rules: [{
      test: require.resolve("some-module"),
      use: 'imports-loader?this=>window'
    }]
  }
};

There are modules that support different module styles, like AMD, CommonJS and legacy. However, most of the time they first check for define and then use some quirky code to export properties. In these cases, it could help to force the CommonJS path by setting define = false:

webpack.config.js

module.exports = {
  module: {
    rules: [{
      test: require.resolve("some-module"),
      use: 'imports-loader?define=>false'
    }]
  }
};

exports-loader

Let's say a library creates a global variable that it expects its consumers to use; In this case, we can use exports-loader, to export that global variable in CommonJS format. For instance, in order to export file as file and helpers.parse as parse:

webpack.config.js

module.exports = {
  module: {
    rules: [{
      test: require.resolve("some-module"),
      use: 'exports-loader?file,parse=helpers.parse'
      // adds below code the file's source:
      //  exports["file"] = file;
      //  exports["parse"] = helpers.parse;
    }]
  }
};

script-loader

The script-loader evaluates code in the global context, just like you would add the code into a script tag. In this mode, every normal library should work. require, module, etc. are undefined.

The file is added as string to the bundle. It is not minimized by webpack, so use a minimized version. There is also no dev tool support for libraries added by this loader.

Assuming you have a legacy.js file containing …

GLOBAL_CONFIG = {};

… using the script-loader

require('script-loader!legacy.js');

… basically yields:

eval("GLOBAL_CONFIG = {};");

noParse option

When there is no AMD/CommonJS version of the module and you want to include the dist, you can flag this module as noParse. Then webpack will just include the module without parsing it, which can be used to improve the build time.

Any feature requiring the AST, like the ProvidePlugin, will not work.
module.exports = {
  module: {
    noParse: /jquery|backbone/
  }
};

© 2012–2016 Tobias Koppers
Licensed under the Creative Commons Attribution License 4.0.
https://webpack.js.org/guides/shimming/