Currently, I am working on enhancing the splitChunks
configuration in a multi-page application that utilizes Webpack 5, with a PHP backend and a Vue frontend.
To optimize the vendor file size, I have started customizing the test function of the vendor cacheGroup
to exclude certain libraries.
test(module /* , chunk */) {
if (module.context) {
// only include node_modules
const isNodeModule = module.context.includes('node_modules');
// excluding specific node_modules
const isToBundleSeparately = [
'marked', // used in one component only
'braintree-web', // for payment page
'bootstrap/js',
].some(str => module.context.includes(str));
if (isNodeModule && !isToBundleSeparately) {
return true;
}
}
return false;
},
This approach ensures that libraries not required in all pages are imported only when necessary by components linked via dynamic imports, which are then extracted into separate chunks.
While this method has been effective thus far, I recently encountered an unusual behavior involving one particular chunk and library (BootstrapVue).
When I add 'bootstrap-vue'
to the list of excluded libraries, I notice that two components from the library, BTab
and BTabs
, get bundled into a significantly large chunk along with the entire code for the payment page and all libraries utilized on that page.
https://i.sstatic.net/PnbXu.png
The identified file starts with "init-initPaymentGateway", as shown in the screenshot.
Subsequently, all pages dependent on those two BootstrapVue components load this oversized file, including the product page and other pages requiring only these small BootstrapVue components.
Here's an example showcasing the chunk import in the product page:
https://i.sstatic.net/3Mz4y.png
Considering my current configuration, I expected these two components to be allocated into a separate chunk or duplicated if too small. Strangely enough, while Webpack Bundle Analyzer displays very small files and duplicated library files, this behavior does not extend to these specific components. For instance, the BootstrapVue BAlert
component, similar in size, gets duplicated across various components.
I suspect the issue arises from these small components, although setting minSize
to 0
(or 10
) should ideally eliminate any minimum size restrictions for chunk creation.
Included below are the imports within the payment page:
import { BTab, BTabs } from 'bootstrap-vue';
import dataCollector from 'braintree-web/data-collector';
(Which consequently leads to inner components importing further files from braintree-web
).
Additionally, the following snippet illustrates the import in a product page component:
import { BTabs, BTab } from 'bootstrap-vue';
Finally, here's the full splitChunks
configuration provided (with irrelevant excluded libraries omitted from the test function):
splitChunks: {
chunks: 'all',
minSize: 10,
minChunks: 1,
maxAsyncRequests: 30,
maxInitialRequests: 30,
enforceSizeThreshold: 50000,
name(module, chunks /* , cacheGroupKey */) {
const allChunksNames = chunks
.filter(item => item.name !== null)
.map(item => item.name.replace('View', ''))
.join('~');
return allChunksNames.slice(0, 30);
},
cacheGroups: {
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true,
},
defaultVendors: {
name: 'vendor',
priority: -10,
chunks: 'all',
minChunks: 1,
reuseExistingChunk: true,
test(module /* , chunk */) {
if (module.context) {
// only include node_modules
const isNodeModule = module.context.includes('node_modules');
// excluding specific node_modules
const isToBundleSeparately = [
'marked', // used in one component only
'bootstrap-vue',
'braintree-web',
'bootstrap/js',
].some(str => module.context.includes(str));
if (isNodeModule && !isToBundleSeparately) {
return true;
}
}
return false;
},
},
},
},
To rectify the issue, I opted to remove 'bootstrap-vue'
from the exclusion list in the test function. However, I am keen on improving my configuration or understanding the rationale behind this peculiar behavior.