martijnboland
martijnboland

Reputation: 413

Dynamically require vendor module with webpack

Normally, with static requires or imports (CommonJS/ES imports), webpack can require any module from /node_modules/, for example:

var vendorModule = require('vendor-module');

But I want to dynamically load a module from /node_modules/ like:

var vendorModuleId = 'vendor-module';

...

var vendorModule = require(vendorModuleId);

This doesn't work because webpack can't determine the dependency at compile time and it's obviously insane to include all of /node_modules/ in the bundle just in case we might want to dynamically load some vendor module.

I'm looking for a way to trick webpack into resolving these modules dynamically. Preferably by telling webpack which modules in /node_modules/ should be included in the bundle via the webpack config file.

Some people say the ContextReplacementPlugin can be useful for these situations, but I can't understand how.

Anybody have any idea how to accomplish this? Thanks in advance!

Upvotes: 8

Views: 4220

Answers (3)

givanse
givanse

Reputation: 14943

Webpack now supports dynamic loading, example:

// js
const _ = await import(/* webpackChunkName: "lodash" */ 'lodash')

// webpack.config.js
output: {
  filename: '[name].bundle.js',
  chunkFilename: '[name].bundle.js',
  path: path.resolve(__dirname, 'dist')
},

That snippet is assuming you also have the Syntax Dynamic Import Babel Plugin.

Upvotes: 1

cantera
cantera

Reputation: 24985

You can reference a module path dynamically using dynamic loading:

// module.js
export default {
  init: () => console.log('module.init'),
};

// index.js
const id = 'module';
import(`./${id}.js`).then(obj => obj.default.init());

Upvotes: 0

Dmitry  Yaremenko
Dmitry Yaremenko

Reputation: 2570

You can make a file for import and export needed modules via loaders.

  1. Create an empty file "./vendors.js";
  2. npm install exports-loader imports-loader --save-dev
  3. In webpack.config.js:

    // config needed vendor modules
    var vendorModules = [
        'one', 'two', 'three', 'vendor-module'
    ];
    
    ...
    
    module.exports = {
    ...
        loaders: [{ // Add loader
            include: require.resolve('./vendors.js'),
            loader: 'imports-loader?' + vendorsModules.map(function(module, index) {
                return 'dep' + index + '=' + module;
            }).join(',') + '!exports-loader?' + vendorsModules.map(function(module, index) {
                return module + '=dep' + index;
            }).join(',')
        },...]
        ...
    }
    
  4. In module where you need to require vendor:

    // import * as vendorsModules from './vendors';
    var vendorsModules = require('./vendors');
    
    var vendorModuleId = 'vendor-module';
    ...
    var vendorModule = vendorsModules[vendorModuleId];
    console.log('module', vendorModule);
    

It will adds configured vendors to your bundle. If you need to lazy load these modules, you need to do more complex modules factory using require.resolve and promise-like interface for getting needed module.

Upvotes: 3

Related Questions