Webpack – Setting Up

Initialising

Webpack is installed using NPM. Initialise a new project, which will create a package.json file. Optionally use the flag -y to accept all defaults when initialising the project.

npm init

Now we can install Webpack and Webpack CLI via NPM using the following. The flag -D is for –save-dev, which adds both packages to our devDependencies.

npm install webpack webpack-cli -D

By default, Webpack 4 will use a default configuration file, so one isn’t necessary to get going. The default configuration values can be found here.

By default, Webpack will look in the folder “src” for the file “index.js”, and output to the folder “dist”, with the javascript file “main.js”. A handy Webpack config generator can be found here.

We can now create a file, index.html in the project root and link to the file “dist/main.js”.

<!doctype html>
<html>
 <head>
   <title>Getting Started</title>
 </head>
 <body>
    <script src="dist/main.js"></script>
 </body>
</html>

For our example, we’ll install Lodash, which is a utility library

npm install lodash --save

Now let’s create the entry point file in “src/index.js”, we’ll import lodash.

import _ from 'lodash';

console.log(_.join(["This", "is", "using", "Lodash"], " "));

This will import the default export from lodash in our local “_” variable. We could use any name of our choosing for this to use locally, however underscore is a convention when using this package.

To build our javascript into the dist directory, we can run

npx webpack

NPX is a tool for executing node packages. It is typically only used for single use commands, such as react-create-app. We’ll supersede its use later for our builds, but it’s useful to use it for this example. Executables which are available for use with NPX are symlinked to the node_modules/.bin directory. Running “NPX with any of the files in here can perform useful functions, e.g. mkdirp which will make directories recursively:

mkdirp /directory1/directory2

Importing Individual Methods

If we didn’t want to use the entire lodash library, we could import individual methods from it using the following:

import {join as _join} from 'lodash'
console.log(_join(["This", "is", "using", "Lodash"], " "));

However, this will still import the entire Lodash library into our project. Instead, we can use the lodash-es module which defines each method as an ES module:

import {join as _join} from 'lodash-es'

console.log(_join(["This", "is", "using", "Lodash"], " "));

This example cuts our dist/main.js size down from ~70KB to ~1KB.

Building with a separate configuration file

If we need to test something using a separate configuration file, we can use NPX to achieve this. We can create a file called webpack.test.config.js in our project’s root with the following:

const path = require('path');

module.exports = {
    entry: './src/index.js',
    output: {
        filename: 'test.js'
    }
};

Note: config files use require to include, which was introduced with Node.js some time ago, and does not use import

And then execute it with NPX:

npx webpack --config webpack.test.config.js

This will bundle our javascript in dist/test.js instead of dist/main.js.

Note that config files are standalone. So if we had a webpack.config.js in our project’s root, any config file passed to Webpack via NPX will not be merged together.

Adding a Script Shortcut

We can assign shortcut’s via NPM’s script facility. At a very basic level, we can setup a build command so that we do not have to rely on NPX. We can do that in our package.json file:

{
...
  "scripts": {
    "build": "webpack"
  },
...
}

We can then add a watch command which will automatically re-build our javascript based on changes to the project:

{
...
  "scripts": {
    "build": "webpack",
    "watch": "webpack  --watch"
  },
...
}

We can also specify other parameters, such as “mode” in our build scripts:

{
...
  "scripts": {
    "build": "webpack --mode production",
    "watch": "webpack --mode development  --watch"
  },
...
}

Note: When watching for changes, the process will have to be broken and re-started when the config file is changed

Setting publicPath

publicPath is used when resolving things like images included in CSS files. It’s prepended to these files. For this example, we’ll set it to the dist folder.

{
...
    output: {
        filename: 'main.js',
        path: path.resolve(__dirname, 'dist'),
        publicPath: 'dist/'
    },
...
}

Source Maps

To allow easier debugging of code, we can set the devtool parameter of our config to one of the sourceMap options. As Webpack itself only deals with Javascript, this will only affect JS SourceMaps, CSS and other loaders will need to be configured in their own right.

By default, setting the config’s mode to ‘development’ will enable SourceMaps, and ‘production’ will disable them, however there are numerous other options which can be useful for both production and development.

Development SourceMaps

These methods generate sourceMaps inline, in the bundled JS files, adding bloat and should not be used in production.

eval

Fast. Files are separated using the original directory structure, but the code generated by Webpack to load modules is present.

cheap-eval-source-map

Pretty Fast. Webpack loading code is removed.

cheap-module-eval-source-map

Medium Speed (but with fast rebuilds). Uses sourcemaps output by defined loaders.

eval-source-map

Slow. Adds column level mappings so inline breakpoints can be set.

Production SourceMaps

none

No SourceMaps are generated. This is the default in production, but leaves code difficult to debug when receiving user reports.

source-map

Source Maps are generated in a separate file. A comment tells dev tools (such as Chrome Dev Tools) where to find them, which are loaded when the dev tools themselves are opened.

hidden-source-map

Source Maps are generated in a separate file, but the comment to tell the browser where to find it is omitted. These can then be Loaded Manually

nosources-source-map

The same as source-map, but only gives the file name and line number. The code itself is not visible to the browser.

Cleaning The Output Folder

When changing Webpack settings, it’s often useful to get rid of old files in the output folder which may be left handing around. To do this, we can use a plugin called Clean Webpack Plugin

Install the plugin

npm install -D clean-webpack-plugin

And then add this to the plugins section of our config file:

module.exports = {
...
    plugins: [
        new CleanWebpackPlugin(['dist'])
    ]
...
}

The option passed into the first parameter of the plugin is an array of paths to be cleaned. This is required, as it does not use Webpack’s output configuration. Supplying a name like above will completely remove that folder, however we can also provide glob strings, such as dist/*.*, which would remove the files within the folder.

This will, by default leave generated files when we’re watching files, so changes will continually generate new files in our dist folder. To re-generate whilst watching, we can use the following option

module.exports = {
...
    plugins: [
        new CleanWebpackPlugin(['dist'], {watch: true})
    ]
...
}