DEV Community

Cover image for Webpack Academy #6: Split your config for dev & prod mode
Code Oz
Code Oz

Posted on • Updated on

Webpack Academy #6: Split your config for dev & prod mode

So from now we manage a lot of things, but we need to divide our config into two parts:

  • Dev part (for developer)

  • Prod part (when we deploy our application on the web)

Until now we just focus on the Prod part!

So in this article, we will split our config into 3 files!

  • Common config webpack

  • Prod config

  • Dev config

Common config webpack

Some properties are common to dev & prod config files, so we can create a file that will contain these fields to avoid repeating code!

Before starting we need to install a package named webpack-merge, which will merge two configs files into one! So we can merge-common file with another file !

After this, we create a common config file πŸ‘‡

const { CleanWebpackPlugin } = require("clean-webpack-plugin")
const HtmlWebpackPlugin = require('html-webpack-plugin')
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
const cdn = require("./cdn")

const config = {
    // Webpack start from this entry point
    entry: {
        myApp: [
            "./src/style.css",
            "./src/main.js",
        ],
    },
    // External lib that will not be put in bundle but use from CDN
    externals: {
        lodash: '_',
    },
    plugins: [
        new CleanWebpackPlugin(),
        new HtmlWebpackPlugin({
            title: 'Webpack academy title',
            template: './src/index.html',
            inject: 'body',
            cdn,
            minify: {
                removeComments: true,
                collapseWhitespace: false
            }
        }),
        new BundleAnalyzerPlugin({
            openAnalyzer: true,
            analyzerMode: 'server',
        })
    ],
}

module.exports = config
Enter fullscreen mode Exit fullscreen mode

In common config we need to use bundle analyser for prod & dev mode, we need also HTML plugin & clean webpack !

We also need to use cdn !

And we create a prod config file !

Prod config file

const commonConfig = require("./webpack.config.common")
const merge = require('webpack-merge')
const MiniCssExtractPlugin = require("mini-css-extract-plugin")

const config = {
    mode: "production",
    module: {
        rules: [
            {
                // Match file extension
                test: /\.css$/,
                // Order of loader from bottom to up
                use: [
                    MiniCssExtractPlugin.loader,
                    'css-loader'
                ],
            }
        ]
    },
    // This is the output of Webpack
    output: {
        // From current folder + dist folder that will contains all bundle
        path: path.resolve(__dirname, "dist/"),
        filename: "[contenthash:8].js"
    },
    optimization: {
        minimize: true,
    },
    plugins: [
        new MiniCssExtractPlugin({
            // Name output by extract
            filename: "style.css",
        }),
    ],
}

// Merge commonConfig with prod config, priority to prod config
module.exports = merge(commonConfig, {
    ...config,
})
Enter fullscreen mode Exit fullscreen mode

In prod mode we need to use hash, extract css & minimize bundle code !

It's almost finished for the prod part, we need to rename cdn file to cdn.prod.js since we will use two separate files for cdn in prod & dev mode !

And we need to edit script file πŸ‘‡

"build": "cross-env --env.NODE_ENV=prod webpack --config webpack.config.prod.js"
Enter fullscreen mode Exit fullscreen mode

And it's finished from now for the prod part !

All things are working since before ! It's a good start to continue and go on the prod part!

Dev config file

Let's start by creating cdn.dev !

Unlike prod cdn, we will NOT use the minify version of library ! We will just use the classic !

module.exports = {
    js: [
        "https://unpkg.com/lodash@4.17.15/lodash.js",
    ],
}
Enter fullscreen mode Exit fullscreen mode

After this we need to install webpack-dev-server, which serves to handle dev service like a dev server for developer !

And create the dev config πŸ‘‡

const path = require("path")
const commonConfig = require("./webpack.config.common")
const merge = require('webpack-merge')

const config = {
    mode: "development",
    devServer: {
        // Show info about dev server
        noInfo: false,
        // Port of dev server
        port: 8080,
        // Asking the server to fallback to index.html in the event that a requested resource cannot be found, need to vue router
        historyApiFallback: true,
        // Allows https in dev server
        // Use this https://stackoverflow.com/questions/35531347/localhost-blocked-on-chrome-with-privacy-error for allow https in localhost directly on chrome
        https: true,
    },
    // This is the output of Webpack
    output: {
        // From current folder + dist folder that will contains all bundle
        path: path.resolve(__dirname, "dist/"),
        filename: "bundle.dev.js"
    },
    module: {
        rules: [
            {
                // Match file extension
                test: /\.css$/,
                // Use multiple loader
                // Order => from bottom to top
                use: [
                    'style-loader',
                    'css-loader'
                ],
            }
        ]
    }
}


// Merge commonConfig with prod config, priority to prod config
module.exports = merge(commonConfig, {
    ...config,
})
Enter fullscreen mode Exit fullscreen mode

For css part we need to use style-loader since we need to inject style in the DOM !

We use some properties like port, https etc... (check comment above)

But on thing is very interesting and I should explain you πŸ”₯

historyApiFallback:

When you use a framework like Vuejs or React, you will choose between two things -> Use Router in front part or back part.

If you use vuejs for example and you need to use VueRouter (handling routing of your app in the Front part).

You will need to inform the current server that hosts your app (in my case webpack server) that you handle route by the front and not by the server (back).

But why ?

For example if you use router front and you will try this URL πŸ‘‡

https://toto.com/test
Enter fullscreen mode Exit fullscreen mode

The server will try to access to /test file from the server files, and it will get nothing since it's not an existing file (because you handle routing by front). And you will get a 404 !

To avoid this behavior in our case, we need to tell the server -> If you have a 404, access to the root file (main file) and not looking for /test file

And after this you can enter any URL and your project will works !

So this options historyApiFallback is just an option to prevent this if you use Router in the front part, you should put true ! Else put false !

We almost finish πŸ’ͺ

Create the command to run our app in dev mode

"dev": "cross-env --env.NODE_ENV=dev webpack serve --hot --config webpack.config.dev.js",
Enter fullscreen mode Exit fullscreen mode

webpack serve --hot: Command to run webpack server in hot reload mode (when a file is changed, we reload our project automatically)

Source map

We will not get in details about this, if you want to check this URL -> https://blog.teamtreehouse.com/introduction-source-maps

To be short, in dev mode we will need to debug some files, if we don't use source map, we will have some files that are a little weird, for example, our main.js πŸ‘‡

lodash__WEBPACK_IMPORTED_MODULE_1___default().cloneDeep({})
console.log(_three__WEBPACK_IMPORTED_MODULE_0__.three)

document.getElementById("button").addEventListener("click", function() {
    jsonObjectImport().then(jsonObject => console.log(jsonObject.default))
})
Enter fullscreen mode Exit fullscreen mode

Here it's not a problem, but with big files we can have some trouble to debug this !

So source map is our hero ! πŸ¦Έβ€β™‚οΈ

devtool: 'eval-cheap-source-map',
Enter fullscreen mode Exit fullscreen mode

(You have a lot of choices about source map, for me the best to use in dev is 'eval-cheap-source-map'), check at this URL to have more information: https://webpack.js.org/configuration/devtool/

When you want to debug the main.js, you will see another file like main.js?56d7 and this is this file that we will need to debug ! Open it and πŸ‘‡

import { three } from './three'
import _ from 'lodash'
const jsonObjectImport = async () => import(/* webpackChunkName: "myChunkName" */ "./big-object.json")

_.cloneDeep({})
console.log(three)

document.getElementById("button").addEventListener("click", function() {
    jsonObjectImport().then(jsonObject => console.log(jsonObject.default))
})
Enter fullscreen mode Exit fullscreen mode

It's like our original main.js file !

To summarise source map :

When we bundle our code with Webpack, it will compile our original file into another special file (can be weird), so if we want to debug our code, we will have this special file that is different from the original file code.

To fix this we can use source map that will keep track of our original file (each original file has a special hash). So if we need to debug code we can find the file like the original file !

Well done ! πŸ’ͺπŸ”₯

We made it ! We manage to split the original config into two parts !

We almost finish the webpack academy!

I hope you like this, You can check the source code at this commit

πŸ“ Note: We create two more commands for bundle analyzer, in prod and dev mode if we need to check bundle size in both cases


I hope you like this reading!

🎁 You can get my new book Underrated skills in javascript, make the difference for FREE if you follow me on Twitter and MP me 😁

Or get it HERE

🎁 MY NEWSLETTER

β˜•οΈ You can SUPPORT MY WORKS πŸ™

πŸƒβ€β™‚οΈ You can follow me on πŸ‘‡

πŸ•Š Twitter : https://twitter.com/code__oz

πŸ‘¨β€πŸ’» Github: https://github.com/Code-Oz

And you can mark πŸ”– this article!

Top comments (0)