These post is the second of a trilogy.
๐ Focus on | ๐ CSS Handling | Parts |
---|---|---|
(Index) | #๏ธโฃ | |
development only | inline CSS | 1๏ธโฃ |
both dev & prod | mini-css-extract-plugin | ๐ |
production only | CSS modules | 3๏ธโฃ |
Example Code ๐
Final Product ๐ค
By completing this starge you will get a good starting point for your personal webpack configuration. In production mode it is better not to inject CSS directly into the bundle because you can get a Flash of Unstyled Content (FOUC) - the inlined CSS it's applied only when the bundle it's executed.
We implement the extraction of CSS in a separate file that is executed at the same time as the rest.
Flow of Thought ๐ฎ
- Add build script
- Download the loader
- Create the loader function
- Connect to useRules
- Add the plugin in webpack.config.js
Implementation ๐ค
- 1 - Add build script
In packages.json
add the build script that will bundle our code and store it in adist
folder.
package.json
{
...
"scripts": {
"start": "webpack-dev-server --env development",
"build": "webpack --env production"
},
...
}
- 2 - Download the loader
In the terminal invoke npm i -D mini-css-extract-plugin
.
- 3 - Create the loader function
Add the package just downloaded in loaders.js
. Then exports a new function named extractCSS - it's almost the sameto the one built in the first phase. The difference stays in the fact that style-loader is is replaced with MiniCssExtractPlugin.loader.
loaders.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
// ... stage one created functions
exports.extractCSS = (config = {}) => {
// basic rule
const rule = {
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, 'css-loader'],
};
return addConfigs(rule, config);
};
- 4 - Connect to useRules
In useRules the implementation is fair simple:
- import the just created function
- add its case in the loaders object
- add the instruction relative to production in instructions object ##### useRules.js
const { loadCSS, extractCSS } = require('./loaders'); //[1]
module.exports = (env) => {
const loaders = {
css: (i) => {
switch (i) {
case 'inline':
return loadCSS();
case 'MCEP': //[2]
return extractCSS();
default:
throw new Error(`The instruction ${i} is not covered`);
}
},
};
// developer interface
const instructions = {
css: {
development: 'inline',
production: 'MCEP', //[3] Mini-Css-Extract-Plugin
},
};
// business logic - already seen in stage one
let message = '[useRules] ';
const rules = Object.entries(instructions).map(([key, value]) => {
const i = instructions[key][env];
message += key + '|' + i;
return loaders[key](i);
});
console.info(message);
return { rules };
};
- 5 - Add the plugin in webpack.config.js
In order to properly work, MiniCssExtractPlugin
need to be imported [1] and loaded [2] in the plugins section in webpack.config.js
:
webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
// [1]
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const useRules = require('./config/useRules');
module.exports = (env) => ({
devServer: {
open: true,
stats: 'errors-only',
},
plugins: [
new HtmlWebpackPlugin({
title: 'Webpack Inline CSS',
}),
new MiniCssExtractPlugin({ // [2]
filename: '[name].[hash].css'
})
],
module: useRules(env),
});
Checking the Outcome ๐
-
npm start
: the web server will start and open up your bundle in a tab. Open devTools and peek in Network section. Reload the page. See? There is no trace of any CSS file - it is installed in the JavaScript. -
npm run build
: adist
folder will be generated. Get into that and serve itcd dist && serve
(you may need tonpm i serve -g
before). Now, the result is the same as before but open again the devTools, get in network. You see that? It's a separate CSS file. No more Flash of Unstyled Content!
In console you should see log such as
[useRules] css|inline
or[useRules] css|MCEP
Upgrade the last-stage ๐
avaiable soon