Contents

Vanilla Webapp with Webpack

Basic Guide to A Vanilla Javascript App with Webpack

This document will walk through setting up a vanilla javascript, html, and css web app with Webpack.

Contents

Install Node.js

Before we get to webpack, we will need to download and install node.js on our machine. Head over to the Node.js website. link

Either download the Latest stable version or the LTS (long term support) version.

If you have a “package manager” installed on your system, you can checkout the supported package managers page here and follow the instructions.

Once done with the installation, confirm that it installed correctly by running node --version in your terminal, and checking the version output:

node --version
v14.16.1  #<-- Example version output

Configure Node Project

We need to setup out project folder/directory to be managed by Node.

Todo this, simply navagate to your project folder in your terminal, and run npm init

This will run the setup wizard, and ask you some questions. It is fine to just hit Enter untill it is done.

This should create a few files.

There should be a package.json and/or a package.json.lock file in your project root directory.

If you open the package.json file it should look like this:

{
  "name": "example-project",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}

Installing Webpack

Once you have verified your Node.js install and configured Node to manage your project folder, we can proceed to install & setup Webpack

In the terminal install the following: webpack, webpack-cli, webpack-dev-server, webpack-merge

npm install --save-dev webpack webpack-cli webpack-dev-server webpack-merge

Note that using --save-dev saves all the packages as dependencies to your package.json file under the devDependencies parameter.

it may look somthing similar to this:

{
  "name": "My Project",
  "version": "1.0.0",
  "description": "",

  "scripts": {
    ... Omitted
  },
  "repository": {
    "type": "git",
    "url": "..."
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^5.33.2",
    "webpack-cli": "^4.6.0",
    "webpack-dev-server": "^3.11.2",
    "webpack-merge": "^5.7.3"
  }
}

Note I have ommitted some config details, we will get to that shortly.

These packages do a few things.

Webpack is the main package and Webpack-cli is for using webpack in the terminal/command line.

Webpack-dev-server helps create and manage, a local deveopment server on port 8080 for viewing our project during development.

Webpack-merge allows for us to have multiple webpack configuration files, or multiple objects with parameters, for easy to read configuration. Merge, then parses and combines these into one file/object.

Project Structure

We should create our project file structure, with our files and folders next.

  • Create src/ and dist/ folders in the main project directory.
  • Create index.html file in the main directory.
  • Create scripts/ and styles/ in the src/ directory.
  • Create index.js file in scripts/ & style.css in styles/.

The Structure/Layout of our project should look like this:

dist/            # Create folder
src/             # Create folder
    scripts/        # Create subfolder in src/
        index.js      # Create file in subfolder scripts/
    styles/         # Create subfolder in src/
        style.css   # Create file in subfolder styles/
index.html      # Create this file
package.json        // Generated by npm init
package-lock.json   // Generated by npm init

Setting up Webpack

Now that our files and folders are structured how we like, we can proceed to setting up Webpack for our project.

In the root directory of the project, create a file called webpack.config.js. You can name it what you want as long as it starts with webpack and ends in .js format. Webpack by default assumes/detects the file name webpack.config.js.

Note: If you name it somthing else your will need to define the config file name in the package.json file with the --config flag and the file name.

Html loader

Before we edit this file, we need to download a plugin to handle the loading of html files. We can do this with html-webpack-plugin.

npm i --save-dev html-webpack-plugin

Once that is installed, the webpack config file and add the following:

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

module.exports = {
  module: {
    // Soon
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, "src", "index.html")
    })
  ]
};

CSS/SASS loader

To handle loading CSS/SCSS and SASS into the Webpack bundle we need to download style-loader, css-loader and sass-loader.

 npm i --save-dev style-loader css-loader sass-loader

Once these are installed, open the webpack config file again and add in the module section the following:

module: {
  rules: [
      {
        test: /\.s[ac]ss$/i,
        use: ["style-loader", "css-loader","sass-loader"]
      },
  },

Important: Make sure that the use line matches the loaders in the above order. Webpack loads from right, to left. It needs to load the file loaders (sass-loader and css-loader) first before it can deal with the styles inside these files.

Image Loader

Now that we have the html and css/sass/scss file loaders, we need to make sure Images are loaded and bundled as well.

Webpack has a built in Image loader, we just need to specify to look for the files in the config.

Add the following lines in the rules section we added previous:

  }, //Previous rule

  {
    test: /\.(png|svg|jpg|jpeg|gif)$/i,
    type: 'asset/resource',
  }

loading ES Modules

ECMAScript loading

Because some newer JS functionality isn’t always supported accross current or older browsers, we need to make sure these new features and compiled/modified to there repective older supported versions.

This tasks can be handled with Babel.

Install the following:

npm i @babel/core babel-loader @babel/preset-env --save-dev

And add the following into webpack config:

  {
    "presets": [
      "@babel/preset-env"
    ]
  }

We can also specify the webpack entry point and build output with the following code in the modules section:

  entry: './src/index.js',
   output: {
    filename: 'bundle.js', path: path.resolve(__dirname, 'dist'),
  }

Complete Webpack config

The complete webpack config file should look like the following:

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

module.exports = {
  entry: './src/index.js',
   output: {
    filename: 'bundle.js', path: path.resolve(__dirname, 'dist'),
  },
  module: {
    rules: [
      {
        test: /\.s[ac]ss$/i,
        use: ["style-loader", "css-loader","sass-loader"]
      },
      {

        test: /\.(png|svg|jpg|jpeg|gif)$/i,

        type: 'asset/resource',

      },
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: ["babel-loader"]
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, "src", "index.html")
    })
  ]
};

Package.json and Webpack

It worth noting before moving on that we should have a nice list of dependancies in our package.json file now, from installing all thoes extra packages.

"devDependencies": {
    "@babel/core": "^7.14.0",
    "@babel/preset-env": "^7.14.1",
    "babel-loader": "^8.2.2",
    "css-loader": "^5.2.4",
    "html-webpack-plugin": "^5.3.1",
    "sass": "^1.32.12",
    "sass-loader": "^11.0.1",
    "style-loader": "^2.0.0",
    "webpack": "^5.36.2",
    "webpack-cli": "^4.6.0",
    "webpack-dev-server": "^3.11.2",
    "webpack-merge": "^5.7.3"
  }

As indicated before, I ommited some parts of the package.json file. This was spicifically the scripts section of the file.

In this section is how we tell node to handle our build/test and other scripts used by packages like Webpack.

It is in this sections that we can define a script to trigger webpack to build/run specific tasks.

Lets configure Webpack to run a live build of our project by the webpack-dev-server. This will allow us to constantly update code, and have Webpack automatically render this to our browser.

Open up package.json, and go to the scripts lines. We are going to create a new script called start which triggers the dev-server to build and deploy to a new tab in our default Web browser.

Edit the scripts section to look like the following:

"scripts": {
  "start": "webpack serve --mode development --open --config webpack.config.js"
}

Now you can trigger this scripts by running the npm start command in the terminal.

To run a build as we develop our project we can add:

  "dev": "webpack --mode development --config webpack.config.js",

We can trigger this by running npm run dev in the terminal.

We can also define a build script before bundling for production:

  "build": "webpack --mode production --config webpack.config.js"

we can run this with a similar command to the dev script. npm run build

Final Package.json

Just for reference the final package.json file should look similar to this:

I removed some config code marked /* … */ for brevity. This code is generated when you run npm init.

{
  "name": /* ... */,
  "version": "1.0.0",
  "description": "",
  "private": true,
  "scripts": {
    "dev": "webpack --mode development --config webpack.config.js",
    "start": "webpack serve --mode development --open --config webpack.config.js",
    "build": "webpack --mode production --config webpack.config.js"
  },
  "repository": {
    "type": "git",
    "url": /* ... */
  },
  "keywords": [ 
    /* ... */
  ],
  "author": /* ... */,
  "license": "ISC",
  "bugs": {
    /* ... */
  },
  "homepage": /* ... */,
  "devDependencies": {
    "@babel/core": "^7.14.0",
    "@babel/preset-env": "^7.14.1",
    "babel-loader": "^8.2.2",
    "css-loader": "^5.2.4",
    "html-webpack-plugin": "^5.3.1",
    "sass": "^1.32.12",
    "sass-loader": "^11.0.1",
    "style-loader": "^2.0.0",
    "webpack": "^5.36.2",
    "webpack-cli": "^4.6.0",
    "webpack-dev-server": "^3.11.2",
    "webpack-merge": "^5.7.3"
  }
}