The styles are inlined in development mode by default, this means styles are kept as a part of a javascript chunk, and are included on page in the style
tag. In production mode (on older versions of ScandiPWA), the styles are compiled by Webpack into separate stylesheets, that are later added to the page using the link
tag. Usage of link
tags forces the browser to make a new request. Making a additional request is always slower than not making it.
For example, consider such code within the page HTML:
<link rel="stylesheet" href="/static/frontend/scandipwa/theme/en_US/Magento_Theme/static/css/main_style.02e68462.chunk.css">
This will cause the site to have a following timeline:
As you can see, the time when we could show placeholders / draw something is delayed by styles being downloaded. Off-course, the size of styles is tiny, but the major delay is actually coming from TTFB (time it takes to reach the server), which could be up to 500ms on slower connections.
Inlining of styles would result in a better loading experience, but a similar (in terms of overall length) timeline. The link
tags would be replaced by style
tags, for example:
<style>body{padding:0}</style>
Resulting in the following timeline:
The inline of styles does not affect the critical chain in a major way. However, it improves the loading times for pages generated by crawler and overall page loading experience. To achieve it:
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?
<aside>
🧠ScandiPWA is based off the CRA. By default it extracts styles into separate files, instead of shipping them inside of the JavaScript chunks. Inline styles, means shipping styles along the JavaScript chunk, such that it is injected as <style>
to the page.
</aside>
Inside of a build configuration plugin, add the following logic:
const { isFound: isStyleLoaderFound, match: styleLoader } = getLoader(
webpackConfig,
loaderByName('style-loader')
);
if (isStyleLoaderFound) {
// Configure loader to inject styles
styleLoader.loader = {
loader: styleLoader.loader,
options: { injectType: 'styleTag' }
};
}
const { isFound: isMiniCssLoaderFound } = getLoader(
webpackConfig,
loaderByName('mini-css-extract-plugin')
);
if (isMiniCssLoaderFound) {
addBeforeLoaders(
webpackConfig,
loaderByName('mini-css-extract-plugin'),
{
loader: require.resolve('style-loader', { paths: [process.cwd()] }),
options: { injectType: 'styleTag' }
}
);
removeLoaders(
webpackConfig,
loaderByName('mini-css-extract-plugin')
);
}
// remove mini css extract plugin
webpackConfig.plugins = webpackConfig.plugins.filter((plugin) => {
const isMini = plugin.constructor.name === 'MiniCssExtractPlugin';
return !isMini;
});
Provide the following import, to satisfy the function requirements:
<aside>
🧠You can avoid specifying the @tilework/mosaic-craco
in your extension package dependencies, as it is shipped along the core ScandiPWA app.
</aside>
const {
getLoader,
loaderByName,
removeLoaders,
addBeforeLoaders
} = require('@tilework/mosaic-craco');
<aside> 🎉 This is how you inline styles!
</aside>