Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / React

Step by Step Migration - Webpack 3 to Webpack 4

5.00/5 (4 votes)
26 Feb 2019CPOL3 min read 19.5K   25  
This article details the migration steps from Webpack 3 to Webpack 4.

Introduction

Migrating from Webpack 3 to Webpack 4 is a very cumbersome process. I went through many articles and blogs to find a nice, easy and quick way of doing it. However, I could not find one single article that explains everything and lists out the pain points of migration. So, I decided to write something to help other fellow developers who are considering the upgrade in the near future.

Background

The first question is why do we need to upgrade to webpack 4. I am sure there are tons of articles over the internet to explain the benefits. So, I am skipping this part.

I'll explain upgrade of react/angular/other js bundles, less/Scss bundles. I am sure that once you get a handle on these assets, fonts/images are going to be a cakewalk.

Using the Code

Few things to consider before starting the migration are listed below:

  1. Update the npm version. It should be greater than 8.9.0. Run command npm -v to check the current version and to upgrade on Windows machine - just download node msi from here. For mac/linux, visit nodejs site and follow upgrade steps from there.
  2. Start with a new webpack.config.js file. It's always good to start from scratch and gradually do the migration with one asset type at a time. Rename the existing webpack.config.js file to webpack_old.config.js.
  3. Always try to use webpack-bundle-analyzer during migration to visualize which bundle file contains what packages. It helps in deciding which bundle to group in what chunk, therefore helps in optimising the chunks.
  4. Webpack 4 does not use extract-text-css-plugin, common-chunks-plugin, uglify-js-plugin (this works with earlier versions of webpack 4, not with the latest), so just get rid of these plugins. The alternate to these are mini-css-extract-plugin, splitChunksplugin (inbuilt in webpack 4) and terser-webpack-plugin consecutively.
  5. For the sass/scss transformation, you will need to add a postcss.config.js file inside your root folder. I'll attach this file for reference:
    JavaScript
    //
    // postcss.config.js
    // 
    module.exports = {
        plugins: [
            require('autoprefixer')
        ]
    }
  6. Try to start with modifying the package.json file first, then update all the required migration packages.
  7. I got some error related to cosmiconfig. So, I had to include this package inside package.json file.

The package json should have minimum of these packages to run the webpack 4 for js/jsx/css/less/scss files.

Package.json

JavaScript
//
// minimum packages required to start with webpack 4 - define in package.json file
// 
    "autoprefixer": "^9.4.7",
    "babel-core": "^6.26.3",
    "babel-loader": "7.1.2",
    "babel-polyfill": "6.26.0",
    "babel-preset-env": "1.6.1",
    "babel-preset-es2015": "^6.24.1",
    "babel-preset-react": "6.24.1",
    "babel-preset-stage-3": "6.24.1",
    "clean-webpack-plugin": "^0.1.16",
    "cosmiconfig": "4.0.0",
    "less": "^3.9.0",
    "less-loader": "4.1.0",
    "mini-css-extract-plugin": "0.5.0",
    "node-sass": "4.11.0",
    "npm": "^5.8.0",
    "optimize-css-assets-webpack-plugin": "^5.0.1",
    "postcss-loader": "3.0.0",
    "sass-loader": "7.1.0",
    "style-loader": "0.23.1",
    "suppress-chunks-webpack-plugin": "0.0.4",
    "terser-webpack-plugin": "1.1.0",
    "toastr": "^2.1.4",
    "webpack": "4.29.0",
    "webpack-bundle-analyzer": "^3.0.4",
    "webpack-cli": "3.2.3",

Webpack.config.js

Define the const at the top in webpack.config.js file:

JavaScript
'use strict';
const path = require('path');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const SuppressChunksPlugin = require('suppress-chunks-webpack-plugin').default;
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const TerserPlugin = require('terser-webpack-plugin');

//Initialize PLUGINS
const MiniCssPlugin = new MiniCssExtractPlugin({
    filename: 'assets/css/[name].css'
});

// cleans 'dist' folder every time before a new build
//not required but nice to start with clean folder
const CleanPLugin = new CleanWebpackPlugin(
    ['./dist/js', './dist/css'], {
        verbose: false,
        dry: false
    });

Start with webpack module export and then define the config entries inside as follows:

JavaScript
module.exports = (env) => {

    //Define variables
    const isDev = env === 'development';
    const jsIdentifier = './assets/js/[name].js';
    const plugins = isDev ? [CleanPLugin, MiniCssPlugin, 
                    new BundleAnalyzerPlugin()] : [CleanPLugin, MiniCssPlugin];
   
    // build WEBPACK config
    const config = {};
    config.mode = env;
    config.watch = isDev;
    config.resolve = {
        extensions: ['.js', '.jsx']
    };
    config.devtool = 'source-map';
    config.entry =
        {
            'angularapp.min': './angularapp/app.js',
            sassStyle: './assets/scss/main.scss',
            lessStyle: './assets/less/main.less',
            'reactapp.min': './reactapp/index.js'
        };
    config.output = {
        path: __dirname,
        filename: jsIdentifier,
        chunkFilename: jsIdentifier
    };
    // you can get more information about the splitchunks plugin from webpack site.
    // This plugin is very powerful as you can define more than one entry inside cacheGroups
    // and further split the vendor chunks in 
    // as many small bundles as you want depending upon the 'test' value
    config.optimization = {
        splitChunks: {
            cacheGroups: {
                commons: {
                    test: /[\\/]node_modules[\\/]/,
                    name: 'vendor.min',
                    chunks: 'initial'
                }
            }
        },
        minimizer: [
            new TerserPlugin({
                sourceMap: isDev,
                cache: true,
                parallel: true,
                terserOptions: {
                    mangle: false,
                    keep_classnames: true,
                    keep_fnames: true,
                    output: {
                        comments: false
                    }
                }
            }),
            new OptimizeCSSAssetsPlugin({})
        ]
    };
    config.plugins = plugins;config.module = {
        rules: [
            {
                test: /\.(js|jsx)$/, exclude: /node_modules/,
                use: {
                    loader: 'babel-loader',
                    query: {
                        presets: ['es2015', 'react', 'stage-3']
                    }
                }
            },
            {
                test: /\.scss$/,
                use: [MiniCssExtractPlugin.loader,
                    {
                        loader: "css-loader", options: {
                            sourceMap: true
                        }
                    },
                    'postcss-loader',
                    {
                        loader: "sass-loader", options: {
                            sourceMap: true
                        }
                    }]
            },
            { // less loader for webpack
                test: /\.less$/,
                use: [MiniCssExtractPlugin.loader,
                    'css-loader',
                    'less-loader']
            }
        ]
    };
    return config;
};

There are two ways in which you can define the production/development configs in webpack:

  1. One way is using the --mode production (in package json command)
  2. The other, that I have used --env production flag (refer to the attached package.json file build scripts command)

There is no right or wrong approach. It totally depends upon how you want to define the configuration inside webpack.config.js file.

And that is all you have to change to migrate to webpack 4. I have attached the package.json and webpack.config.js file for reference.

Points of Interest

You can learn more about Webpack 4 configuration here.

History

  • 25th February, 2019: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)