Since the release of Webpack 4, extract-text-webpack-plugin is completely broken. A lot of people are complaining about their builds failing after upgrading to Webpack 4. The future of this plugin is uncertain after contributors made it clear that they won’t be fixing problems with ETWP and CSS extraction support will be moved to MCEP plugin.

In this tutorial, we’ll see how to use MCEP plugin to extract CSS from Javascript files. Initialize a new package.json file with npm init and add these dependencies to it.

{ "name": "extract-webpack", "version": "1.0.0", "main": "index.js", "license": "MIT", "scripts": { "dev": "webpack --config webpack.config.js" }, "devDependencies": { "babel-core": "^6.26.3", "babel-loader": "^7.1.4", "babel-preset-es2015": "^6.24.1", "babel-preset-react": "^6.24.1", "css-loader": "^0.28.11", "mini-css-extract-plugin": "^0.4.0", "node-sass": "^4.9.0", "sass-loader": "^7.0.1", "style-loader": "^0.21.0", "webpack": "^4.8.1", "webpack-cli": "^2.1.3" }, "dependencies": { "react": "^16.3.2", "react-dom": "^16.3.2", "react-router-dom": "^4.2.2" } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 { "name" : "extract-webpack" , "version" : "1.0.0" , "main" : "index.js" , "license" : "MIT" , "scripts" : { "dev" : "webpack --config webpack.config.js" } , "devDependencies" : { "babel-core" : "^6.26.3" , "babel-loader" : "^7.1.4" , "babel-preset-es2015" : "^6.24.1" , "babel-preset-react" : "^6.24.1" , "css-loader" : "^0.28.11" , "mini-css-extract-plugin" : "^0.4.0" , "node-sass" : "^4.9.0" , "sass-loader" : "^7.0.1" , "style-loader" : "^0.21.0" , "webpack" : "^4.8.1" , "webpack-cli" : "^2.1.3" } , "dependencies" : { "react" : "^16.3.2" , "react-dom" : "^16.3.2" , "react-router-dom" : "^4.2.2" } }

In this example, we’ll use sass-loader to transpile SASS to CSS and then extract it to a dedicated file.

const path = require('path'); const MiniCssExtractPlugin = require("mini-css-extract-plugin"); const devMode = process.env.NODE_ENV !== 'production'; module.exports = { entry : './src/app.js', output : { filename : 'bundle.js', path : path.resolve(__dirname, 'dist') }, module : { rules : [ { test: /\.s?[ac]ss$/, use: [ MiniCssExtractPlugin.loader, { loader: 'css-loader', options: { url: false, sourceMap: true } }, { loader: 'sass-loader', options: { sourceMap: true } } ], }, { test: /\.js$/, exclude: /node_modules/, use: "babel-loader" } ] }, devtool: 'source-map', plugins: [ new MiniCssExtractPlugin({ filename: "style.css" }) ], mode : devMode ? 'development' : 'production' }; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 const path = require ( 'path' ) ; const MiniCssExtractPlugin = require ( "mini-css-extract-plugin" ) ; const devMode = process . env . NODE_ENV !== 'production' ; module . exports = { entry : './src/app.js' , output : { filename : 'bundle.js' , path : path . resolve ( __dirname , 'dist' ) } , module : { rules : [ { test : / \ . s ? [ ac ] ss $ / , use : [ MiniCssExtractPlugin . loader , { loader : 'css-loader' , options : { url : false , sourceMap : true } } , { loader : 'sass-loader' , options : { sourceMap : true } } ] , } , { test : / \ . js $ / , exclude : / node_modules / , use : "babel-loader" } ] } , devtool : 'source-map' , plugins : [ new MiniCssExtractPlugin ( { filename : "style.css" } ) ] , mode : devMode ? 'development' : 'production' } ;

We’re running babel-loader against Javascript files and css-loader and sass-loader for our SASS and SCSS files. Now let’s create a react component under src directory along with its style file and require it in your app.js entry file.

require('./components/Root'); 1 require ( './components/Root' ) ;

import React from "react"; require('./root.scss'); class Root extends React.Component{ render(){ return ( <div>Lorde</div> ); } } export default Root; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 import React from "react" ; require ( './root.scss' ) ; class Root extends React . Component { render ( ) { return ( < div > Lorde < / div > ) ; } } export default Root ;

body{ background-color :red; #root{ background-color : 'black'; color:white; } } 1 2 3 4 5 6 7 8 body { background-color : red ; #root { background-color : 'black' ; color : white ; } }

Now run yarn run dev from the terminal. Webpack will create bundle.js and style.css under dist folder along with source map files.

$ webpack --config webpack.config.js Hash: 86a4482ea33a6a995896 Version: webpack 4.8.1 Time: 862ms Built at: 2018-05-11 03:11:08 Asset Size Chunks Chunk Names style.css 138 bytes main [emitted] main bundle.js 64.7 KiB main [emitted] main style.css.map 333 bytes main [emitted] main bundle.js.map 70.3 KiB main [emitted] main Entrypoint main = style.css bundle.js style.css.map bundle.js.map [./src/app.js] 44 bytes {main} [built] + 12 hidden modules Child mini-css-extract-plugin node_modules/css-loader/index.js??ref--4-1!node_modules/sass-loader/lib/loader.js??ref--4-2!src/components/root.scss: Entrypoint mini-css-extract-plugin = * 2 modules Done in 1.43s. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 $ webpack -- config webpack .config .js Hash : 86a4482ea33a6a995896 Version : webpack 4.8.1 Time : 862ms Built at : 2018 - 05 - 11 03 : 11 : 08 Asset Size Chunks Chunk Names style .css 138 bytes main [ emitted ] main bundle .js 64.7 KiB main [ emitted ] main style .css .map 333 bytes main [ emitted ] main bundle .js .map 70.3 KiB main [ emitted ] main Entrypoint main = style .css bundle .js style .css .map bundle .js .map [ . / src / app .js ] 44 bytes { main } [ built ] + 12 hidden modules Child mini - css - extract - plugin node_modules / css - loader / index .js ? ? ref -- 4 - 1 ! node_modules / sass - loader / lib / loader .js ? ? ref -- 4 - 2 ! src / components / root .scss : Entrypoint mini - css - extract - plugin = * 2 modules Done in 1.43s.

I’ve set up an example repository, clone and play with it. For more configuration options, check MCEP repository.