Reputation: 25810
How can I dynamically import NPM modules without generating extra vendors~
-prefixed chunks?
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"
),
};
*/
}
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
modulevendors~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.
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).
Upvotes: 0
Views: 2540
Reputation: 25810
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,
},
},
},
// ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲
}];
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,
},
dist/
lib/
moment.js
Upvotes: 3