Rush StackShopBlogEvents
Skip to main content

Webpack plugins

Plugin packages:@rushstack/heft-webpack4-plugin
@rushstack/heft-webpack5-plugin
Plugin names:webpack4-plugin implemented by Webpack4Plugin.ts
webpack5-plugin implemented by Webpack5Plugin.ts
Plugin config file:(none)
heft.json options:IWebpackPluginOptions (Webpack 4)
IWebpackPluginOptions (Webpack 5)

This task invokes the Webpack tool to produce application bundles. It provides features such as:

  • Combining many small .js files into one large file for faster downloads
  • Improving performance by applying various compiler optimizations such as inlining and dead code elimination ("tree shaking")
  • Compressing and obfuscating code by shortening identifiers, using the Terser minifier by default
  • Converting assets such as .css or even images into embedded JavaScript objects

Webpack also has the ability to act as a general purpose build system, for example by invoking a compiler or linter, however Heft does not use it that way. Heft invokes the TypeScript compiler to produce intermediate .js files which become the inputs for other tasks such as Jest or Webpack. This reduces the number of compiler passes, and avoids the need for compiler optimizations to be reimplemented multiple times for different contexts (ts-loader, ts-jest, etc).

The heft-webpack-basic-tutorial sample project illustrates a complete project using Webpack and React.

When to use it

Webpack should be used for projects whose output is a web application bundle. Webpack can also be used to bundle Node.js tools or services, however this is less common.

In these notes, we'll assume you're using Webpack 5. For Webpack 4, substitute @rushstack/heft-webpack4-plugin instead of @rushstack/heft-webpack5-plugin everywhere. Their usage is essentially identical.

package.json dependencies

The simplest way to use Webpack is via @rushstack/heft-web-rig, which provides a standard configuration with a recommended set of plugins and loaders.

Otherwise, if you're not using a rig, you'll need to add the plugin package to your project:

# If you are using Rush, run this shell command in your project folder:
rush add --package @rushstack/heft-webpack5-plugin --dev

The @rushstack/heft-webpack5-plugin package has a peer dependency on webpack. If you're not using a rig, then you must add this dependency as well:

# If you are using Rush, run this shell command in your project folder:
rush add --package webpack --dev

Important: If you are using @rushstack/heft-web-rig, then the peer dependency is satisfied by the rig, so it's not strictly necessarily to add webpack to your project's package.json dependencies. However doing so can be useful, for example to satisfy peer dependencies of project-specific loaders. If you add it, make sure the same SemVer range is the same as the rig's heft-web-rig/package.json to avoid inconsistencies.

You should also add @types/webpack-env to your project, which provides TypeScript typings for the Webpack environment:

# If you are using Rush, run this shell command in your project folder:
rush add --package @types/webpack-env --exact --dev

# Because @types packages don't follow SemVer, it's a good idea to use --exact

Configuration

Since @types/webpack-env defines global APIs (that aren't accessed using regular import statements), it must be be added to your TypeScript configuration like this:

<project folder>/tsconfig.json

{
"extends": "./node_modules/@rushstack/heft-web-rig/profiles/library/tsconfig-base.json",
"compilerOptions": {
"types": [
"webpack-env" // <---- ADD THIS
]
}
}

If Webpack is not already being provided by a rig, your heft.json config file could invoke it like in this example:

<project folder>/config/heft.json

{
"$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json",

"aliasesByName": {
"start": {
"actionName": "build-watch",
"defaultParameters": ["--serve"]
}
},

"phasesByName": {
"build": {
"cleanFiles": [
{ "sourcePath": "dist" },
{ "sourcePath": "lib" },
{ "sourcePath": "lib-amd" },
{ "sourcePath": "lib-commonjs" },
{ "sourcePath": "lib-es6" }
],
"tasksByName": {
"sass": {
"taskPlugin": {
"pluginPackage": "@rushstack/heft-sass-plugin"
}
},
"typescript": {
"taskDependencies": ["sass"],
"taskPlugin": {
"pluginPackage": "@rushstack/heft-typescript-plugin"
}
},
"webpack": {
"taskDependencies": ["typescript"],
"taskPlugin": {
"pluginPackage": "@rushstack/heft-webpack5-plugin"
}
}
. . .
}
},
. . .
}
}

Next, create a webpack.config.js file in your project folder. Here is a rudimentary example:

<project folder>/webpack.config.js

'use strict';

const path = require('path');

const webpackConfig = {
mode: 'development',
resolve: {
// Note: Do not specify '.ts' or '.tsx' here. Heft invokes Webpack as a post-process after the compiler.
extensions: ['.js', '.jsx', '.json']
},
entry: {
app: path.join(__dirname, 'lib', 'index.js')
},
output: {
path: path.join(__dirname, 'dist'),
filename: '[name]_[contenthash].js'
}
};

module.exports = webpackConfig;

If you want to use a slightly different configuration when developing using the localhost dev server, you can optionally create a second file called webpack.dev.config.js.

To start the localhost dev server, use the heft start command, which conventionally is defined as an alias for heft build-watch --serve (see aliasesByName above). Whenever you save a change to a source file, Heft's watch mode will recompile your project, then Webpack hot module reloading should refresh your web browser with the latest build of the app.

Interaction with Jest

Webpack works best with the esnext module format, whereas Jest must use the commonjs module format because its tests are executed by the Node.js runtime. In order to use Webpack and Jest together, you will need to emit both module formats. This is described in the Jest plugin section.

CLI parameters

heft-jest-plugin/heft-plugin.json defines these parameters:

  --serve
Start a local web server for testing purposes using
webpack-dev-server. This parameter is only available
when running in watch mode.