Webpack: Part-3
Tags: webpack, javascript, beginners, webdev
Published: 2020-06-13 16:20:08

<!-- wp:paragraph -->
<p>In&nbsp;<a href="http://blog.suprabha.me/tools/webpack-part-2/">previous blog</a>, we have discussed on Cache Busting and plugins, Splitting dev and production.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>In this blog, we will learning interesting part of webpack here as:</p>
<!-- /wp:paragraph -->

<!-- wp:list {"ordered":true} -->
<ol><li>Html-loader</li><li>File-loader</li><li>Clean-webpack</li><li>Multiple Entrypoints &amp; Vendor.js</li><li>Extract CSS &amp; Minify HTML/CSS/JS</li></ol>
<!-- /wp:list -->

<!-- wp:heading {"level":3} -->
<h3><span class="has-inline-color has-vivid-red-color"><b>HTML Loader:</b></span></h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>For images, when we use same img file structure for dev and prod. We will get issue as the images are not loading in prod well. To fix that we need&nbsp;<a href="https://github.com/webpack-contrib/html-loader">HTML loader.</a></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Install&nbsp;<strong>Html-loader</strong>:</p>
<!-- /wp:paragraph -->

<!-- wp:codemirror-blocks/code-block {"mode":"javascript","mime":"text/javascript","theme":"duotone-light"} -->
<div class="wp-block-codemirror-blocks-code-block code-block"><pre>$ npm install —save-dev html-loader</pre></div>
<!-- /wp:codemirror-blocks/code-block -->

<!-- wp:paragraph -->
<p><strong>webpack.config.js:</strong></p>
<!-- /wp:paragraph -->

```js
// include in module rules

{
  test: /\.html$/,
  use: ["html-loader"] 
}
```

<!-- wp:paragraph -->
<p>When we run&nbsp;<strong><em>npm run prod</em>,&nbsp;</strong>we get error as:</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><span style="color:#ff0004" class="has-inline-color">unexpected token, you may need an appropriate loader to handle this file type.</span></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Now, Here we need<strong>&nbsp;file-loader.</strong></p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3><strong><span class="has-inline-color has-vivid-red-color">File-loader:</span></strong></h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>To Install&nbsp;<a href="https://github.com/webpack-contrib/file-loader">File loader</a>:</p>
<!-- /wp:paragraph -->

<!-- wp:codemirror-blocks/code-block {"mode":"javascript","mime":"text/javascript","theme":"duotone-light"} -->
<div class="wp-block-codemirror-blocks-code-block code-block"><pre>$ npm install –save-dev file-loader</pre></div>
<!-- /wp:codemirror-blocks/code-block -->

<!-- wp:paragraph -->
<p><strong>webpack.config.js:</strong></p>
<!-- /wp:paragraph -->

```js
const path = require("path")
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = 
  { 
    entry: "./src/index.js",
    plugins: [
      new HtmlWebpackPlugin({ 
template: "./src/main.html"
       })
    ],
    module: 
       { 
         rules: [ 
           { 
  // files which ends with .css use the below loader 
   test: /\.scss$/,
   use: [
     "style-loader", // 3rd. style loader inject styles into DOM
     "css-loader", // 2nd. CSS loader turns css into common JS
     "sass-loader" //1st. SASS loader which turns sass into CSS
     ]},
   {
     test: /\.html$/,
     use: ["html-loader"] 
   },	
   {
      test: /\.(svg|png|jpg|gif)$/,
      use: { 
        loader: "file-loader",
        options: { 
        name: "[name].[hash].[ext]",
        outputPath: "images" 
      }
   }}
 }}
```
<!-- wp:paragraph -->
<p>Now run&nbsp;<strong><em>npm run prod</em>,</strong></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>It will create&nbsp;<strong>images</strong>&nbsp;as&nbsp;<strong>folder</strong>&nbsp;inside dist and all jpg/png/svg.. files will be copied there.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3><strong><span class="has-inline-color has-vivid-red-color">Clean-webpack:</span></strong></h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Whenever we do some changes in file, it will create new hash file. We will install&nbsp;<a href="https://webpack.js.org/guides/output-management/#cleaning-up-the-dist-folder">clean-webpack&nbsp;</a>plugin which will delete dist directory everytime we build.</p>
<!-- /wp:paragraph -->

<!-- wp:codemirror-blocks/code-block {"mode":"javascript","mime":"text/javascript","theme":"duotone-light"} -->
<div class="wp-block-codemirror-blocks-code-block code-block"><pre>$ npm install –save-dev clean-webpack-plugin</pre></div>
<!-- /wp:codemirror-blocks/code-block -->

<!-- wp:paragraph -->
<p>Use it in production file, for dev its not needed.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><strong>webpack.prod.js:</strong></p>
<!-- /wp:paragraph -->

```js
const path = require("path")
const HtmlWebpackPlugin = require('html-webpack-plugin');
const common = require('./webpack-config');
const merge = require('webpack-merge');
const {CleanWebpackPlugin} = require("clean-webpack-plugin");

module.exports = 
  merge(common, { 
    mode : "production",
    output: 
      { 
         filename: "hello.[contentHash].js", 
         path.resolve(__dirname, "New_folder_name") } }
      },
    plugins: [ new CleanWebpackPlugin() ]
})
```

<!-- wp:heading {"level":3} -->
<h3><strong><span class="has-inline-color has-vivid-red-color">Multiple Entrypoints &amp; Vendor.js:</span></strong></h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>If we want to have multiple entry point then we can do it with below following steps:</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Create a file in&nbsp;<strong>src</strong>&nbsp;folder.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Example: vendor.js</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Change Output section in both dev and prod.js:</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><strong>webpack.dev.js:</strong></p>
<!-- /wp:paragraph -->

```js
output: {
	filename: "[name].bundle.js"
}
```

<strong>webpack.prod.js:</strong>
```js
output: {
	filename: "[name].[constentHash].bundle.js"
}
```
<strong>webpack.config.js:</strong>
```js
module.exports = {
  entry: {
     main: "./src/index.js",
     vendor: "./src/vendor.js"
  }
}
```

<!-- wp:paragraph -->
<p>Now check by running<strong><em>&nbsp;npm start</em></strong>&nbsp;and&nbsp;<em><strong>npm run prod</strong></em>.&nbsp;It will create two file name as&nbsp;<strong>main.bundle.js</strong>&nbsp;and&nbsp;<strong>vendor.bundle.js</strong>.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3><strong><span class="has-inline-color has-vivid-red-color">Extract CSS &amp; Minify HTML/CSS/JS:</span></strong></h3>
<!-- /wp:heading -->

<!-- wp:heading {"level":3} -->
<h3><strong><span style="text-decoration: underline;">Extract CSS:</span></strong></h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>It will be great we can have separate js file and css file in production. Currently everything is happening by js only. In production obviously we need CSS to load first. As JS may take some second to load. It can be doable using plugin called mini-css-extract-plugin.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Install&nbsp;<strong>mini-css-extract-plugin</strong></p>
<!-- /wp:paragraph -->

<!-- wp:codemirror-blocks/code-block {"fileName":"\u003cem\u003e$ npm install —save-dev mini-css-extract-plugin\u003c/em\u003eJavaScript","mode":"javascript","mime":"text/javascript","theme":"duotone-light"} -->
<div class="wp-block-codemirror-blocks-code-block code-block"><pre>$ npm install —save-dev mini-css-extract-plugin</pre></div>
<!-- /wp:codemirror-blocks/code-block -->

<!-- wp:paragraph -->
<p><strong>webpack.prod.js:</strong></p>
<!-- /wp:paragraph -->

```js
// Add into the plugins:

const MiniCssExtractPlugin = require("mini-css-extract-plugin")
plugins: [ 
    new MiniCssExtractPlugin({
        filename: "[name].[chunkHash].css"
    })
    new CleanWebpackPlugin()
],

```

<!-- wp:paragraph -->
<p>We have to make sure, that we are using above snippet instead of style loader in webpack.config.js</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><strong>webpack.dev.js:</strong></p>
<!-- /wp:paragraph -->

```js
const path = require("path")
const HtmlWebpackPlugin = require('html-webpack-plugin');
const common = require('./webpack-config');
const merge = require('webpack-merge');

module.exports = 
 merge(common ,{ 
    mode : "development",
    output: 
      { 
         filename: "[name].bundle.js",
         path.resolve(__dirname, "New_folder_name") } }
      },
    module: 
       { 
         rules: [ 
           { 
  // files which ends with .css use the below loader 
   test: /\.scss$/,
   use: [
    "style-loader", // 3rd. style loader inject styles into DOM
    "css-loader", // 2nd. CSS loader turns css into common JS
    "sass-loader" //1st. SASS loader which turns sass into CSS
   ]}
  }
})
```
<strong>webpack.prod.js:</strong>

```js
const path = require("path")
const HtmlWebpackPlugin = require('html-webpack-plugin');
const common = require('./webpack-config');
const merge = require('webpack-merge');
const CleanWebpackPlugin = require("clean-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin")

module.exports = 
  merge(common, { 
    mode : "production",
    output: 
      { 
         filename: "[name].[constentHash].bundle.js",
         path.resolve(__dirname, "New_folder_name") } }
      },
    plugins: [ 
       new MiniCssExtractPlugin({
         filename: "[name].[chunkHash].css"
       })
       new CleanWebpackPlugin() 
    ],
    module: 
       { 
         rules: [ 
           { 
             // files which ends with .css use the below loader 
             test: /\.scss$/,
             use: [
               "MiniCssExtractPlugin.loader", // 3rd. Move CSS into files
               "css-loader", // 2nd. CSS loader turns css into common JS
               "sass-loader" //1st. SASS loader which turns sass into CSS
             ]
           }
     }
})

```

<b>webpack.config.js:</b>
```js
const path = require("path")
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = 
  { 
    entry: "./src/index.js",
    plugins: [
      new HtmlWebpackPlugin({ 
        template: "./src/main.html"
      })
    ],
    module: 
    { 
      rules: [ 
       { 
         test: /\.html$/,
         use: ["html-loader"] 
       },	
       {
	 test: /\.(svg|png|jpg|gif)$/,
 	 use: { 
           loader: "file-loader",
           options: { 
             name: "[name].[hash].[ext]",
             outputPath: "images"
           }
         }
        }
     }
}
```

<!-- wp:paragraph -->
<p>Now, by running&nbsp;<strong><em>npm run prod,</em></strong>&nbsp;we will get css file as well in dist folder.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3><strong><span class="has-inline-color has-vivid-red-color">Minify CSS:</span></strong></h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>To minify the css we used the plugin called&nbsp;<strong>optimize-css-assets-webpack-plugin</strong></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Install it:</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>$<em>&nbsp;npm install —save-dev optimize-css-assets-webpack-plugin</em></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><strong>(</strong>we just need to minify the CSS in production<strong>)</strong></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><strong>webpack.prod.js:</strong></p>
<!-- /wp:paragraph -->

```js
// (To compile CSS)
const OptimizeCssAssestsPlugin = require('optimize-css-assets-webpack-plugin');
// we add new property here called optimization
optimization: {
    minimizer: new OptimizeCssAssestsPlugin()
}
```

<!-- wp:paragraph -->
<p>By default the JS will be optimized, but when we run&nbsp;<em><strong>npm run prod</strong></em>&nbsp;here the CSS will get optimised and JS will not be optimised longer. It’s because we are overwriting the optiomization above.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>To fix that we have to add optimization for JS as well.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3><strong><span class="has-inline-color has-vivid-red-color">Minify JS:</span></strong></h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>For&nbsp;<strong>JS minifier</strong>&nbsp;we are using&nbsp;<strong>TerserPlugin</strong>, which has installed by default.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>To enter this in&nbsp;<strong>webpack.prod.js:</strong></p>
<!-- /wp:paragraph -->

```js
const TerserPlugin = require('terser-webpack-plugin');
optimization: {
    minimizer: [new OptimizeCssAssestsPlugin(), newTerserPlugin()]
}
```

<!-- wp:heading {"level":3} -->
<h3><strong><span class="has-inline-color has-vivid-red-color">Minify HTML:</span></strong></h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>We are not going to use any new plugin here.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><strong>webpack.config.js:</strong></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Remove HTMLWebpackPlugin from plugins.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><strong>webpack.dev.js:</strong></p>
<!-- /wp:paragraph -->

```js
const HtmlWebpackPlugin = require('html-webpack-plugin');
// add plugins here as:

plugins: [
    new HtmlWebpackPlugin ({template: "./src/template.html"})
]
```

<b>webpack.prod.js:</b>
```js
const path = require("path");
const HtmlWebpackPlugin = require('html-webpack-plugin');
const common = require('./webpack-config');
const merge = require('webpack-merge');
const CleanWebpackPlugin = require("clean-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const TerserPlugin = require('terser-webpack-plugin');

module.exports = 
  merge(common, { 
    mode : "production",
    output: 
      { 
         filename: "[name].[constentHash].bundle.js",
         path.resolve(__dirname, "New_folder_name") } }
      },
      optimization: {
        minimizer: [new OptimizeCssAssestsPlugin(), newTerserPlugin(),
         new HtmlWebpackPlugin ({
           template: "./src/template.html",
           minify: {
             removeAtrributeQuotes: true,
             collapseWhiteSpace: true,
             removeComments: true
           }
        })
       ]
     },
      plugins: [ 
       new MiniCssExtractPlugin({
        filename: "[name].[chunkHash].css"
       }),
       new CleanWebpackPlugin() 
     ],
     module: 
       { 
         rules: [ 
           { 
           // files which ends with .css use the below loader 
           test: /\.scss$/,
           use: [
             "MiniCssExtractPlugin.loader", // 3rd. Move CSS into files
             "css-loader", // 2nd. CSS loader turns css into common JS
             "sass-loader" //1st. SASS loader which turns sass into CSS
         ]}
     }
})
```

<!-- wp:paragraph -->
<p>Now, run&nbsp;<em><strong>npm run prod</strong></em>&nbsp;and we can see in dist <code>index.html</code>, we don’t have any comments and white spaces. The code will get minified.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>I hope you found this blog helpful ♥️, If you have any question please reach out to me on <strong><a href="https://twitter.com/suprabhasupi">@suprabhasupi</a> 😋</strong></p>
<!-- /wp:paragraph -->

<table>
  <tbody>
    <tr>
      <td>
        🌟 <a href="https://twitter.com/suprabhasupi"> Twitter</a>
      </td>
      <td>
        👩🏻‍💻 <a href="https://www.suprabha.me/"> Suprabha.me</a>
      </td>
<td>
        🌟 <a href="https://www.instagram.com/suprabhasupi/"> Instagram</a>
      </td>
    </tr>
  </tbody>
</table>