00:00
10:57

React Intermediate: Upgrade to Webpack 4 - [012]

In this episode we will show you how to upgrade an existing webpack 3 application to webpack 4. We'll use frontojs/template as our reference.

Updating the Package.json

We'll need to move some dependencies around for package.json. This is what we have.

{  "name": "frontojs",  "version": "1.0.0",  "main": "dist/index.js",  "author": "Zack Siri",  "license": "MIT",  "scripts": {    "dev": "NODE_ENV=development webpack-dev-server --progress --hot --inline --config ./config/development.js",    "build": "NODE_ENV=production webpack --progress --config ./config/production.js",    "test": "BABEL_ENV=test jest"  },  "dependencies": {    "@babel/runtime": "^7.2.0",    "animate.css": "^3.5.2",    "classnames": "^2.2.5",    "fronto-api": "^1.0.2",    "fronto-connect": "^1.0.8",    "fronto-localize": "^1.0.0",    "mobx": "^5.6.0",    "mobx-react": "^5.4.2",    "purecss": "^1.0.0",    "react": "^16.6.0",    "react-dom": "^16.6.0",    "react-loadable": "^5.3.1",    "react-router5": "^5.3.1",    "router5": "^5.6.0"  },  "devDependencies": {    "@babel/core": "^7.0.0",    "@babel/plugin-proposal-class-properties": "^7.0.0",    "@babel/plugin-proposal-decorators": "^7.0.0",    "@babel/plugin-proposal-do-expressions": "^7.0.0",    "@babel/plugin-proposal-export-default-from": "^7.0.0",    "@babel/plugin-proposal-export-namespace-from": "^7.0.0",    "@babel/plugin-proposal-function-bind": "^7.0.0",    "@babel/plugin-proposal-function-sent": "^7.0.0",    "@babel/plugin-proposal-json-strings": "^7.0.0",    "@babel/plugin-proposal-logical-assignment-operators": "^7.0.0",    "@babel/plugin-proposal-nullish-coalescing-operator": "^7.0.0",    "@babel/plugin-proposal-numeric-separator": "^7.0.0",    "@babel/plugin-proposal-optional-chaining": "^7.0.0",    "@babel/plugin-proposal-pipeline-operator": "^7.0.0",    "@babel/plugin-proposal-throw-expressions": "^7.0.0",    "@babel/plugin-syntax-dynamic-import": "^7.0.0",    "@babel/plugin-syntax-import-meta": "^7.0.0",    "@babel/plugin-transform-runtime": "^7.2.0",    "@babel/preset-env": "^7.1.0",    "@babel/preset-react": "^7.0.0",    "autoprefixer": "^7.1.6",    "babel-loader": "^8.0.4",    "node-sass": "^4.6.0",    "babel-plugin-lodash": "^3.3.2",    "babel-plugin-module-resolver": "^3.0.0",    "babel-plugin-react-css-modules": "^3.3.2",    "clean-webpack-plugin": "^0.1.17",    "css-loader": "^0.28.7",    "file-loader": "^2.0.0",    "glob": "^7.1.2",    "html-webpack-plugin": "^3.2.0",    "lodash-webpack-plugin": "^0.11.4",    "mini-css-extract-plugin": "^0.4.3",    "postcss-loader": "^2.0.8",    "resolve-url-loader": "^2.3.0",    "sass-loader": "^6.0.6",    "style-loader": "^0.19.0",    "sugarss": "^1.0.1",    "uglifyjs-webpack-plugin": "^2.0.1",    "webpack": "^4.28.1",    "webpack-cli": "^3.1.2",    "webpack-dev-server": "^3.1.14"  }}

Upgrading Webpack Config

For webpack we have 2 configuration files config/development.js and config/production.js.

// config/development.jsconst webpack = require('webpack')const path = require('path')const { sync } = require('glob')const entry = require('./entry')const output = require('./output')const resolve = require('./resolve')output.filename = 'javascripts/[name].js'output.chunkFilename = 'javascripts/[name].chunk.js'const loaders = {  babel: require('./loaders/babel'),  css: require('./loaders/css'),  assets: require('./loaders/assets')}const css = require('./styles/css')const postcss = require('./styles/postcss')const sass = require('./styles/sass')const config = {  entry,  output,  resolve,  mode: 'development',  module: {    rules: [      loaders.babel, loaders.assets, loaders.css, {      test: /\.(scss|sass)$/i,      use: [{ loader: 'style-loader' }, css, postcss, sass]    }]  },  plugins: [    require(path.resolve(__dirname, 'template')),  ],  devtool: 'source-map',  devServer: {    hot: true,    inline: true,    watchOptions: {      ignored: /node_modules/    },    historyApiFallback: true,    proxy: {      "/v1": "http://localhost:3000"    }  }}module.exports = config

Below is the configuration for production.js

// config/production.jsconst webpack = require('webpack')const path = require('path')const { sync } = require('glob')const UglifyJSPlugin = require('uglifyjs-webpack-plugin')const MiniCssExtractPlugin = require('mini-css-extract-plugin')const CleanWebpackPlugin = require('clean-webpack-plugin')const LodashModuleReplacementPlugin = require('lodash-webpack-plugin')const loadersDir = path.join(__dirname, 'config', 'loaders')const entry = require('./entry')const output = require('./output')const resolve = require('./resolve')const loaders = {  babel: require('./loaders/babel'),  assets: require('./loaders/assets')}const css = require('./styles/css')const postcss = require('./styles/postcss')const sass = require('./styles/sass')const config = {  entry,  output,  resolve,  mode: 'production',  module: {    rules: [      loaders.babel, loaders.assets, {        test: /\.css$/i,        use: [          MiniCssExtractPlugin.loader,          'css-loader'        ]      }, {        test: /\.(scss|sass)$/i,        use: [          MiniCssExtractPlugin.loader,          css,          postcss,          'resolve-url-loader',          sass        ]      }    ]  },  plugins: [    require(path.resolve(__dirname, 'template')),    new CleanWebpackPlugin(['dist'], {       root: path.resolve(__dirname, '..')    }),    new webpack.LoaderOptionsPlugin({      minimize: true    }),    new LodashModuleReplacementPlugin,    new UglifyJSPlugin({}),    new MiniCssExtractPlugin({      filename: 'stylesheets/[name].[hash].css', allChunks: true    })  ]}module.exports = config

We also need to update the config/output.js

// config/output.jsconst { resolve } = require('path');module.exports = {  filename: 'javascripts/[name].[hash].js',  chunkFilename: 'javascripts/[name].[hash].chunk.js',  publicPath: '/',  path: resolve(__dirname, '..', 'dist')};

Updating Babel Config

We also need to update the babel config

// .babelrc{  "presets": [    [      "@babel/env",      {        "modules": false,        "targets": {          "browsers": "last 2 versions"        },        "useBuiltIns": "entry"      }    ],    "@babel/react"  ],  "plugins": [    "lodash",    "@babel/plugin-transform-runtime",    "@babel/plugin-syntax-dynamic-import",    [      "@babel/plugin-proposal-decorators",      {        "legacy": true      }    ],    [      "module-resolver",      {        "root": "./src",        "alias": {          "config": "./config",          "vendor": "./vendor"        }      }    ],    [      "@babel/plugin-proposal-class-properties",      {        "loose": true      }    ],    [      "react-css-modules",      {        "webpackHotModuleReloading": true,        "filetypes": {          ".sass": {            "syntax": "sugarss",            "plugins": [              "autoprefixer"            ]          }        }      }    ]  ]}

That's pretty much it! Our application should be able to successfuly build.