简体   繁体   中英

How to load dynamic chunk without vendors splitting

Quick Summary

How can I dynamically import NPM modules without generating extra vendors~ -prefixed chunks?

Details

Setup

webpack.config.js

const path = require("path");

module.exports = [{
    mode: "development",
    entry: path.resolve(__dirname, "js/index.js"),
}];

index.js

__webpack_public_path__ = "dist/";

loadMoment();

function loadMoment() {
    return require.ensure(
        "moment-timezone",
        require => {
            console.log("moment loaded");
            window.MY_GLOBAL = {
                moment: require("moment-timezone"),
            };
        },
        () => {},
        "lib/moment",
    );

    /*
    // Working on an existing project with an older version of ESLint, so the preferred import()
    // trips up the linter. Using the older require.ensure to avoid linter errors, but I tested
    // with async/await and import() and I get the same result.
    window.MY_GLOBAL = {
        moment: await import(
            /* webpackChunkName: "lib/moment" * /
            "moment-timezone"
        ),
    };
    */
}

Results

This is the undesired result I'm currently getting:

dist/
  lib/
    moment.js
  vendors~lib/
    moment.js

Note that there are 2 moment.js files!

  • lib/moment.js is 16 kb and, when I examine it, contains only the ./node_modules/moment/locale module
  • vendors~lib/moment.js is 938kb and, when I examine it, contains over 130 modules. So, basically, all of the moment and moment-timezone modules.

The desired result:

dist/
  lib/
    moment.js

I would like to keep all of my NPM modules and whatever else I might want to load in a single chunk, named as I've specified, without any automatic prefixes.

More background

I'm working on an older project that previously copy/pasted the entire minified moment and moment-timezone libraries into a JS resource named "lib/moment.js". I'd like to remove them from our codebase and generate the "lib/moment.js" file via a dynamic import. It's important to preserve the existing file name and folder structure.

The dynamic import code seemed simple enough ( webpack documentation ), but I haven't been able to find any explanation for the vendors~ prefix or how to remove it. I can see it in the examples, of course, but that prefix is, as best I can tell, never directly addressed.

If I can't get rid of the prefix and bundle everything into just the lib/moment chunk, then I'm going to have to abandon this approach and just continue with the minified libraries stored in lib files (which is not ideal).

TL;DR

In short, you need to disable the defaultVendors cache group (or vendors prior to webpack 5):

webpack.config.js

const path = require("path");

module.exports = [{
    mode: "development",
    entry: path.resolve(__dirname, "js/index.js"),

    // ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼
    optimization: {
      splitChunks: {
        cacheGroups: {
            defaultVendors: false,
            // prior to webpack 5:
            //vendors: false,
        },
      },
    },
    // ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲
}];

The what-now?

Webpack provides a default configuration for the optimization.splitChunks property which includes a simple "defaultVendors" rule (or "vendors" in v4 ) which splits NPM modules into a separate chunk:

cacheGroups: {
    defaultVendors: {
        test: /[\\/]node_modules[\\/]/,
        priority: -10,
        reuseExistingChunk: true,
    },
},

According to the docs, if you do not want to use these default cache groups, then you have to explicitly set them to false :

To disable any of the default cache groups, set them to false .

To disable the vendors cache group, simply set it to false in your webpack config:

cacheGroups: {
    defaultVendors: false,
},

Result

dist/
  lib/
    moment.js

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM