<aside> 🧑🎓 The critical request chain is necessary to learn what chunks must be preload. Learn more how to identify it:
How to identify critical request chain?
</aside>
To preload critical chunks, means to add preload links for chunks necessary to render each page. Consider the following request chain (unoptimized):2

Preloading chunks will have the following effect:

To achieve this effect, following actions are required:
<aside> 🧠 Webpack comes pre-loaded with Magic Comments feature. It allows hinting Webpack how to name the chunk group and what strategy use to load it. It looks as follows:
import(
/* webpackMode: "lazy", webpackChunkName: "cms" */
'./CmsPage.component'
);
</aside>
Lookup the critical request chains (i.e. for homepage, PLP, PDP), note the chunks loading for each page. For example, these could be: cms, product, category chunks (based on optimized critical request chains).
Create a next extension, declare a build configuration plugin inside. It is possible to use an exiting extension too. Follow these instructions:
How to build configuration plugins?
Create a new file preload.js along the build configuration plugin, with following content (do not forget cacheGroupWhitelist with desired names from step 1):
<aside>
🧠 By adding new entries to cacheGroupWhitelist the named chunk group will be added to a list of pre-loaded ones. Add chunk groups
</aside>
const path = require('path');
class PreloadPlugin {
addPreloadConfig(compilation, htmlPluginData) {
const stats = compilation.getStats().toJson({ all: false, chunkGroups: true });
// vvv Update with desired cache groups from step 1
const cacheGroupWhitelist = ['cms', 'product', 'category'];
const localeCacheGroup = Object.keys(stats.namedChunkGroups).filter((cacheGroup) => /[a-z]{2}_[A-Z]{2}/.test(cacheGroup));
const preloadData = [
...cacheGroupWhitelist,
...localeCacheGroup
].reduce((acc, cacheGroup) => {
return {
...acc,
[cacheGroup]: stats.namedChunkGroups[cacheGroup]?.assets.map(
(asset) => process.env.PUBLIC_URL
? path.join(process.env.PUBLIC_URL, asset)
: `/${asset}`
)
};
}, {});
const scriptHtml = `<script>window.preloadData = ${JSON.stringify(preloadData)};</script>`;
htmlPluginData.html = htmlPluginData.html.replace('<head>', `<head>${scriptHtml}`);
return htmlPluginData;
}
apply(compiler) {
compiler.hooks.compilation.tap(
this.constructor.name,
compilation => {
// This is set in html-webpack-plugin pre-v4.
let hook = compilation.hooks.htmlWebpackPluginAfterHtmlProcessing;
if (!hook) {
const [HtmlWebpackPlugin] = compiler.options.plugins.filter(
(plugin) => plugin.constructor.name === 'HtmlWebpackPlugin');
console.log('Unable to find an instance of HtmlWebpackPlugin in the current compilation.');
hook = HtmlWebpackPlugin.constructor.getHooks(compilation).beforeEmit;
}
hook.tapAsync(
this.constructor.name,
(htmlPluginData, callback) => {
try {
callback(null, this.addPreloadConfig(compilation, htmlPluginData));
} catch (error) {
callback(error);
}
}
);
}
);
}
}
module.exports = { PreloadPlugin };
<aside>
🧠 This plugin uses Webpack stats to retrieve information about files included in specified named chunk groups. It then inlines this information right after the head element into the HTML document template.
</aside>
Inject the plugin into Webpack configuration, inside of a build configuration plugin:
webpackConfig.plugins.push(new PreloadPlugin());