Webpack: Part-3

Suprabha - Jun 13 '20 - - Dev Community

In previous blog, we have discussed on Cache Busting and plugins, Splitting dev and production.

In this blog, we will learning interesting part of webpack here as:

  1. Html-loader
  2. File-loader
  3. Clean-webpack
  4. Multiple Entrypoints & Vendor.js
  5. Extract CSS & Minify HTML/CSS/JS

HTML Loader:

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 HTML loader.

Install Html-loader:

$ npm install —save-dev html-loader

webpack.config.js:

// include in module rules

{
  test: /\.html$/,
  use: ["html-loader"] 
}
Enter fullscreen mode Exit fullscreen mode

When we run npm run prodwe get error as:

unexpected token, you may need an appropriate loader to handle this file type.

Now, Here we need file-loader.

File-loader:

To Install File loader:

$ npm install –save-dev file-loader

webpack.config.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" 
      }
   }}
 }}
Enter fullscreen mode Exit fullscreen mode

Now run npm run prod,

It will create images as folder inside dist and all jpg/png/svg.. files will be copied there.

Clean-webpack:

Whenever we do some changes in file, it will create new hash file. We will install clean-webpack plugin which will delete dist directory everytime we build.

$ npm install –save-dev clean-webpack-plugin

Use it in production file, for dev its not needed.

webpack.prod.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() ]
})
Enter fullscreen mode Exit fullscreen mode

Multiple Entrypoints & Vendor.js:

If we want to have multiple entry point then we can do it with below following steps:

Create a file in src folder.

Example: vendor.js

Change Output section in both dev and prod.js:

webpack.dev.js:

output: {
    filename: "[name].bundle.js"
}
Enter fullscreen mode Exit fullscreen mode

webpack.prod.js:

output: {
    filename: "[name].[constentHash].bundle.js"
}
Enter fullscreen mode Exit fullscreen mode

webpack.config.js:

module.exports = {
  entry: {
     main: "./src/index.js",
     vendor: "./src/vendor.js"
  }
}
Enter fullscreen mode Exit fullscreen mode

Now check by running npm start and npm run prod. It will create two file name as main.bundle.js and vendor.bundle.js.

Extract CSS & Minify HTML/CSS/JS:

Extract CSS:

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.

Install mini-css-extract-plugin

$ npm install —save-dev mini-css-extract-plugin

webpack.prod.js:

// Add into the plugins:

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

Enter fullscreen mode Exit fullscreen mode

We have to make sure, that we are using above snippet instead of style loader in webpack.config.js

webpack.dev.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
   ]}
  }
})
Enter fullscreen mode Exit fullscreen mode

webpack.prod.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
             ]
           }
     }
})

Enter fullscreen mode Exit fullscreen mode

webpack.config.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"
           }
         }
        }
     }
}
Enter fullscreen mode Exit fullscreen mode

Now, by running npm run prod, we will get css file as well in dist folder.

Minify CSS:

To minify the css we used the plugin called optimize-css-assets-webpack-plugin

Install it:

$ npm install —save-dev optimize-css-assets-webpack-plugin

(we just need to minify the CSS in production)

webpack.prod.js:

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

By default the JS will be optimized, but when we run npm run prod here the CSS will get optimised and JS will not be optimised longer. It’s because we are overwriting the optiomization above.

To fix that we have to add optimization for JS as well.

Minify JS:

For JS minifier we are using TerserPlugin, which has installed by default.

To enter this in webpack.prod.js:

const TerserPlugin = require('terser-webpack-plugin');
optimization: {
    minimizer: [new OptimizeCssAssestsPlugin(), newTerserPlugin()]
}
Enter fullscreen mode Exit fullscreen mode

Minify HTML:

We are not going to use any new plugin here.

webpack.config.js:

Remove HTMLWebpackPlugin from plugins.

webpack.dev.js:

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

plugins: [
    new HtmlWebpackPlugin ({template: "./src/template.html"})
]
Enter fullscreen mode Exit fullscreen mode

webpack.prod.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
         ]}
     }
})
Enter fullscreen mode Exit fullscreen mode

Now, run npm run prod and we can see in dist index.html, we don’t have any comments and white spaces. The code will get minified.

I hope you found this blog helpful ♥️, If you have any question please reach out to me on @suprabhasupi 😋

🌟 Twitter 👩🏻‍💻 Suprabha.me 🌟 Instagram
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .