Webpack 4 : Quick Start Guide
Tags: webpack, javascript, webapps, es6
Published: 2020-03-27 06:59:37

Webpack is one of most commonly used module bundlers available now. It eases the developer's job and provides blazing fast performance coupled with amazing features. From the days of task runners like Grunt and Gulp to Module Bundlers , front-end application development has never been so easier and engaging as today.

><i>"Webpack is a static module bundler for modern JavaScript applications. When webpack processes your application, it internally builds a dependency graph which maps every module your project needs and generates one or more bundles"</i>
<a href="https://webpack.js.org/concepts/" target="_blank" style="font-size: 14px;">Read the core concepts from here</a>

Please note that the sole purpose of this article is to help to quickly build a neat webpack build configuration for a webapps. If you are more interested in learning the basics/core concepts of webpack please refer the above mentioned link to get to know about core concepts of webpack. 

<b>Let's Dive in</b>

1. Create a directory
   <pre>mkdir webpack101 && cd webpack101</pre>
2. Use NPM or Yarn for package management
   <pre>npm init</pre>
            OR
   <pre>yarn init</pre>
   It will generate the `package.json` file. Yarn is my favorite , so throughout 
   in this guide yarn will be used.
3. Install webpack locally(recommended)
   <pre>yarn add --dev webpack webpack-cli </pre>
   You can see the webpack being added as dev dependencies in package.
4. Now lets create a sample project with our usual stuffs.You can find the source files [here](https://github.com/SaileshSubramanian/webpackGuide)

   Now the project structure is ready let's bring in the main player 
   `webpack.config.js`. Create the `webpack.config.js` in the root.

6. Now that the initial configuration is ready,lets modify our `package.json` to 
   add the build command.
7. Now let's run the build command
   <pre>yarn build</pre>
8. We now have a `bundle.js` inside the dist folder.For the sake of cache busting 
   , include `[chunkhash]` in the output js file configuration of webpack. 
   So each time the generated js file will be in the format 
  `bundle.[chunkhash].js`. 

Naturally our `dist` folder will be cluttered with many files. So we need to add 
`clean-webpack-plugin`.
   ```javascript
     const { CleanWebpackPlugin } = require('clean-webpack-plugin');
      ......

      plugins: [
         new CleanWebpackPlugin(),
         ....
      ]
   ```

But that does not the serve the whole purpose. So let's add more to the    `webpack.config.js`.

**Working with ES6**
Let's modify our `index.js` and add some behaviour using ES6. Since the code is in ES6 we need to transpile it so that the browser can understand. Here loaders come for the rescue, and do the code transformation for us.

9. Adding Babel to the project. We specify the rules in the module section to add 
   the each loaders in  `webpack.config.js`. 
   <i>The `test` property identifies which file or files should be transformed.
   The `use` property indicates which loader should be used to do the 
   transforming.</i>
   <pre>yarn add --dev babel-loader @babel/core @babel/preset-env</pre>
Modify the our `webpack.config.js` as below.
   ```javascript
    module:{
        rules: [
            {
              test: /\.(js|jsx)$/,
              exclude: /(node_modules)/,
              use: {
                loader: 'babel-loader',
                options: {
                  presets: ["@babel/preset-env"]
                }
              }
            }
        ]
    }
   ```
10. Add a `.babelrc` file with contents as below.
   ```javascript
     {
        "presets": [
           "@babel/preset-env"
         ]
      }
   ```
But how do we see the magic happening? So let's add the `webpack-dev-server` to run the project locally.
     <pre>yarn add --dev webpack-dev-server</pre>
Also modify the package.json the script to run the dev server and then run     `yarn serve`.

   ```javascript
    "serve": "webpack-dev-server --open --config webpack.config.js"
   ```
11. With the css preprocessors taking the significant role in the web development   
    these days , lets create sass files and add loaders to transform and bundle 
    it.
    <pre>yarn add --dev style-loader css-loader node-sass sass-loader</pre>
The `mini-css-extract-plugin` helps us to extract all styles and bundle it in our  dist directory. Use `MiniCssExtractPlugin.loader` instead of style-loader if you need a separate `bundle.css` file as the style-loader injects all the styles in the `head` element of your html.
    <pre>yarn add --dev mini-css-extract-plugin</pre>
 Add the loaders to our `webpack.config.js` as below.
   ```javascript
        const MiniCssExtractPlugin = require('mini-css-extract-plugin');
        ......
         plugins: [
                new MiniCssExtractPlugin({
                    filename:"bundle.[chunkhash].css"
                }),
                ....
          ]

         .....

        {
                test: /\.(sa|sc|c)ss$/,
                use: [
                    
                    {
                        loader: MiniCssExtractPlugin.loader
                    },
                    {
                        loader: "css-loader"
                    },
                    {
                        loader: "sass-loader"
                    }
                ]
            }         
  ```
Now comes the role of plugins. We need to modify our HTML files, copy some of the assets to build folder and so on and to do that we need to add certain webpack plugins.

12. Adding `HtmlWebpackPlugin` , it generates an HTML file with generated bundle 
    files,both js & css, integrated in the `script` and `link` tags. We can even 
    specify the template as well.
    <pre> yarn add --dev html-webpack-plugin</pre>
 Now modify our `webpack.config.js`to add the plugin.
   ```javascript
    var HtmlWebpackPlugin = require('html-webpack-plugin');
     .............

     plugins: [new HtmlWebpackPlugin(
        {
          title: 'My App',
          template:'./src/index.html',
          'meta': {
              'viewport': 'width=device-width, initial-scale=1, user-scalable=no'
           }   
       }
     )]

   ```
 What about assets like fonts, images..Let's add `copy-webpack-plugin`. The 
 reason why `file-loader` was not used because it loads on those assets 
 referenced in our modules.
    <pre>yarn add --dev copy-webpack-plugin</pre>
Add the configurations for the plugin as well inside `webpack.config.js`.
   ```javascript 
   const CopyPlugin = require('copy-webpack-plugin');

   new CopyPlugin([
           { from:'./src/assets', to:'assets'   }
        ])

   ```
 And finally all our `assets` are copied to build directory. 

 <b>Preparing for Different environments</b>

 We could actually maintain separate webpack comfiguration files for 
 development and production deployment, with production files having 
 production configurations included.

 Let's create `webpack.common.config.js`. Remove all the contents from the 
 current `webpack.config.js` and paste it in the new file.Change the output path 
 options as `path:path.resolve(__dirname, '../dist'),`

 Add the below script in the `webpack.config.js` to configure different 
 environments.

   ```javascript
    const webpackMerge = require('webpack-merge');
    const commonConfig = require('./webpack.common.config.js');
    module.exports = ({ env }) => {
      const envConfig = require(`./webpack.${env}.config.js`);
      return webpackMerge(commonConfig, envConfig);
      };
   ```
 Make sure you have the `webpack-merge` yarn added as dev-dependency. 
 Now we can to create `webpack.dev.config.js` and `webpack.prod.config.js`. 
 Include the development specific feature config in the `webpack.dev.config.js` 
 as below.If they existed in your `webpack.common.config`  remove it to avoid 
 unexpected results.
   ```javascript
      module.exports={
        mode:"development",
        devServer:{
          port:3000,
          hot: true,
          contentBase:'./dist'
       },
       devtool:"inline-source-map"
      }
   ```
 Same for the `webpack.prod.config.js`. I leave up to you if you require source- 
 map in prod mode.
   ```javascript
     module.exports={
       mode:"production",
       devtool:"source-map"
     }
   ```
 Modify the scripts to run for different environment in `package.json` to look 
 more meaningful.
   ```javascript
     "scripts": {
     "serve": "webpack-dev-server --open --config build-config/webpack.config.js 
              --env.env=dev",
     "build:dev": "webpack --config build-config/webpack.config.js 
                  --env.env=dev",
     "build:prod": "webpack --config build-config/webpack.config.js 
                  --env.env=prod"
      }
   ```
 You can again go for optimization techniques available with other webpack 
 plugins in the production mode. Since v4 webpack does the optimization for 
 you based on the `mode`. But you can override those with your own 
 configurations. `uglify-js` , `optimise-css-assets` are most popular.

 Thanks for reading.I hope that was informative .If you have any corrections or 
 suggestion, please let me know in the comments section.  Happy Coding !!