Initialise node environment and install webpack as a dev dependency
$ npm init && npm install -D webpack webpack-cli webpack-dev-server

<dist> is the directory where built files are stored and <src/index.js> serves as the default entry file

In package.json "scripts", for the "build" script,
"scripts": {
	"build": "webpack",
	"dev": "webpack serve",
    "watch": "webpack --watch"

$ npm run build - to build

Create a config file <webpack.config.js>. 
Install the HTML plugin as a dev dependency: $ npm i -D html-webpack-plugin
Install babel loader to maintain backwards compatibility with older browser versions: 
$ npm i -D babel-loader @babel/core @babel/preset-env
Install css loaders: $ npm i -D css-loader mini-css-extract-plugin
For sass: $ npm i -D sass-loader

const path = require "path";
const HtmlWebpackPlugin = require("html-webpack-plugin")
const MiniCssExtractPlugin = require("mini-css-extract-plugin")

module.exports = {
  mode: "development", /* The environment. Other options include production */
  entry: {
    bundle: path.resolve(__dirname, "src/index.js"), /* The main file to be bundled */
  output: {
    path: path.resolve(__dirname, "dist"),
    filename: "[name][contenthash].js", /* The created output file. By default <main.js>. The output file name depends on the property provided to "entry". Hence in this example, the output file will be called bundle.js. This file is served to the HTML file as a script. Adding the contentash will create a new output file after every build so */
    clean: true, /* Do not duplicate output files on each build. Maintain one file with changing hashes */
    assetModuleFilename: "[name][ext]" //Maitain filename after bundling
  devtool: "source-map", /* Add source maps for debugging purposes */
  devServer: {
    static: {
      directory: path.resolve(__dirname, "dist"),
      port: 3000,
      open: true, //Open browser automatically on running $ npm run dev
      hot: true, //Hot reloading
      compress: true, //Enable gzip compression
      historyApiFallback: true,
  module: {
    rules: [
      /* The value of the test property refers to the file extension to be focused on, e.g. scsss, js, ts, etc. and the the value of the "use" property refers to the loaders needed to enable implementation of the specified files with the target extension */
        test: /\s?.css$/i, //case insensitive
        use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"] //Read from LTR
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader",
          options: {
            presets: ["@babel/preset-env"]
        test: /\.(png|svg|jpg|jpeg|gif)$/i, //case-insensitive
        type: "asset/resource"
  plugins: [
    new HtmlWebpackPlugin ({
    	title: "<Insert title of webapp>",
    	filename: "index.html",
      	template: "src/<insert template filename here>.html"
    }), /* Creates the HTML file with the necessary features based on the config. The template file serves as a boilerplate over which the plugin adds the other tags such as the title and script. The template is stored in the src directory */
    new MiniCssExtractPlugin()
downloadDownload PNG downloadDownload JPEG downloadDownload SVG

Tip: You can change the style, width & colours of the snippet with the inspect tool before clicking Download!

Click to optimize width for Twitter