Splitting Webpacker Alphabetically
A very, very odd way of splitting up your vendor libraries that worked for me.
FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory
Late on a Friday night, I was running into the above error whilst deploying my app to Heroku.
I knew that the reason I was seeing this was that our final bundle was way too large. Sure, I could use webpack-bundle-analyzer
plugin to see what my worst offending libraries were to remove them, but I was going on a train trip so didn't have time.
I needed to quickly deploy a bug fix and head out.
The route I took to quickly bypass the issue was to chunk libraries alphabetically. This took one big file and split it into (MAX) 26 smaller files that loaded very quickly over HTTP/2.
i.e react
and react-dom
would be in r.js
and motion
would be in m.js
.
I placed the following in my environment.js file to make it work:
const { environment } = require('@rails/webpacker');
environment.loaders.delete('nodeModules');
environment.config.optimization = {
runtimeChunk: 'single',
splitChunks: {
chunks: 'all',
maxInitialRequests: Infinity,
minSize: 0,
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name(module) {
// get the name. E.g. node_modules/packageName/not/this/part.js
// or node_modules/packageName
const packageName = module.context.match(
/[\\/]node_modules[\\/](.*?)([\\/]|$)/
)[1];
// npm package names are URL-safe, but some servers don't like @ symbols
// additionally, we group alphabetically to ensure we don't have too many chunks which stops Amazon request issues
return `npm.${packageName.replace('@', '')[0]}`;
},
},
},
},
};
environment.splitChunks();
module.exports = environment;
I haven't come back to optimise this yet, but I'm sure I can make it much better in the future.
Subscribe to my personal updates
Get emails from me about building software, marketing, and things I've learned building products on the web. Occasionally, a quiet announcement or two.