Skip to main content

Webpack

The library provides several tuneable Webpack configs, intended for different kinds of target code (an application or a library), and environments (development or production).

Common for every config variant, the library exposes it as a "config factory function", which generates the actual configuration once called with necessary options. That config can be further customized by the host code, and then passed into Webpack.

For example, one can use the production app config the following way. In the host codebase the /config/webpack/production.js file is created:

/config/webpack/production.js
const { merge } = require('webpack-merge');
const configFactory = require(
'@dr.pogodin/react-utils/config/webpack/app-production',
);

const baseConfig = configFactory({
context: '/path/to/context/folder',
entry: 'relative/path/to/entry/point',
});

module.exports = merge(baseConfig, {
// Additional Webpack config to merge with the base one.
});

Then in the main webpack.config.js file do:

/webpack.config.js
module.exports = function buildConfig(env) {
const config = require(`./config/webpack/${env}.js`);
// Some additional operations on config may happen here.
return config;
}

Application Config

Base

const configFactory = require('@dr.pogodin/react-utils/config/webpack/app-base');

configFactory(options) => object;

This factory function creates the base Webpack config for apps, which includes the setup common for both development and production environments. The options argument is an object with the following valid fields:

  • Required:

    • babelEnv - string - Environment to use for Babel compilation.
    • context - string - Base URL for relative paths resolution.
    • entry - string | string[] - Entry point(s) for the "main" chunk(s). Under the hood the config will prepend them by some polyfills, like babel-polyfill, nodelist-foreach-polyfill, etc.
    • mode - string - Webpack mode.
  • Optional:

    • babelLoaderExclude — Sets exclude option for babel-loader rule. Defaults to [/node_modules/], meaning Babel loader will not act on 3rd-party modules.

    • babelLoaderOptions - object - Overrides default Babel loader options for JSX and SVG files.

    • cssLocalIdent - string - Template for CSS classnames generated by the Webpack's css-loader. The value is passed into the localIdentName option of the loader. It should match corresponding option in the Babel config. Defaults hash:base64:6.

    • dontEmitBuildInfo - boolean - Set true to opt out of writing generated "build info" data to the disk.

    • dontUseProgressPlugin - boolean - Set true to opt out of including the Webpack's ProgressPlugin into the config. This is intended for test scenarious, to avoid polluting test logs with detailed console output from test Webpack builds.

    • fs - object - Alternative filesystem (e.g. memfs) to use instead of the standard Node's filesystem to output artifacts created during the Webpack config generation by the factory (e.g. "build info", etc.).

    • publicPath - string - Public URL of the output directory when referenced in a browser (see Webpack docs for details). The config factory will automatically append / symbol to the end of given value, thus publicPath values should not include it.

      BEWARE

      When used alongside SSR, publicPath value provided into Webpack must match prefixes of asset URLs generated by Babel during SSR. In particular, if you use the standard server-side Babel preset be sure to set its baseAssetsOutputPath to match publicPath.

    • keepBuildInfo - boolean | object - Allows to re-use "build info" data from a previous Webpack build.

      • If an object is provided, it is used as build info.
      • If true value is provided, the factory attempts to read build info data from the .build-info file in the "context" folder of the build, and it falls back to generating from scratch and using a new build info data if .build-info file cannot be read.
    • outputPath - string - Output build path, relative to the context. Defaults to "build/web-public".

    • sitemap - function | string - The path to JS or JSON config for sitemap. It can be relative to the context, and can be a factory, which returns the config. The config should be compatible with sitemap library library, and if provided the Webpack config factory will use it to gererate sitemap.xml file in the output folder, and then serve it from the app root.

      Complex Sitemap Setup

      In case a complex sitemap setup is needed (e.g. a runtime sitemap generation, or serving the sitemap from alternative routes, etc.), instead of this option use onExpressSetup option of the server factory to mount a custom sitemap controller implementing necessary sitemap logic on the desired route(s) of created ExpressJS server.

      • typescriptboolean — Enables TypeScript support.

      • workbox - boolean | object - When set the Workbox's InjectManifest plugin is included into the array of Webpack plugins, and it generates server worker for browser. If the value is an object it is merged into options passed into the plugin, otherwise default options are used:

      {
      "importWorkboxFrom": "local",
      "swSrc": "@dr.pogodin/react-utils/config/workbox/default.js",
      "swDest": "__service-worker.js"
      }

      If the service worker is generated by this option, it will be automatically initiated at the client side by the standard client-side initialization script provided by this library.

      Note that swDest's value cannot be overriden by config options provided via workbox object.

The config factory returns a config object which

  • Bundles font assets (EOF, OTF, SVG, TTF, WOFF, WOFF2 files) from the src/assets/fonts folder of source code and emits them into the [PUBLIC_PATH]/fonts folder.

  • Bundles image assets (GIF, JPEG, JPG, PNG files) from any folder of source code and emits them into the [PUBLIC_PATH]/images folder.

  • Bundle SCSS files from any folder of source code, beside node_modules and its subfolders. The files are compiled, bundled, and extracted into [PUBLIC_PATH]/[CHUNK_NAME].css chunks.

  • Bundles CSS files from any folder of source code. The files are bundled and extracted into [PUBLIC_PATH]/[CHUNK_NAME].css chunks.

  • Aggregates source maps from dependencies, using source-map-loader.

  • Bundles .cjs, .js, .jsx, .svg files + if typescript option is enabled, .ts and .tsx files.

    All these files are compiled using babel-loader with Babel config for Webpack, and with Babel environment specified in the factory options. The outputs are bundled and emitted into [PUBLIC_PATH]/[CHUNK_NAME].js chunks, .

  • Automatically configures the following path aliases for the compilation (relative paths starting with these segments are resolved relative to the corresponding folders):

    • assets for [CONTEXT]/src/assets;
    • components for [CONTEXT]/src/shared/components;
    • fonts for [CONTEXT]/src/assets/fonts;
    • styles for [CONTEXT]/src/styles.
  • resolve.symlinks Webpack option is set false to avoid problems with resolution of assets from packages linked with npm link.

  • These global variables are automatically eemulated inside the output JS bundle:

    • BUILD_RNDKEY - A random 32 bit key that can be used for encryption, it is set just as a global variable accessible in the code;
    • BUILD_TIMESTAMP - UTC timestamp of the beginning of the build;
    • FRONT_END - It is set *true inside the bundle, so that shared code can use it to determine that it is executed at the client side.
  • The config opts to polyfill the __dirname global variable, and to ignore imports of the fs Node package;

  • By default the config factory also generates and emits "build info" data.

Development

const configFactory = require('@dr.pogodin/react-utils/config/webpack/app-development');

configFactory(options) => object;

This factory function creates Webpack configuration for development environment. It accepts the same options as the base app config, and does the same stuff, with the following differences.

  • It accepts additional options:

    • dontUseHmr - boolean - Set true to opt out of including HMR-specific bits into the generated config. It is intended for test scenarious, where without additional efforts, a code bundled with development config would trigger HMR failure warnings.

    • dontUseReactGlobalStateDebugging - boolean - Set true to opt out of injecting true value into REACT_GLOBAL_STATE_DEBUG global variable in development environment. This variable would enable debug logging related to the React Global State, and disabling that is intended for test scenarious, where these debug logs would unnecessary pollute test logs.

    • cssExtractionOptionsobject — Optional. Customizes settings of MiniCssExtractPlugin (it emits CSS assets from the build), which is included into the config with the following configuration:

      {
      chunkFilename: '[id].css',
      filename: '[id].css',
      ...ops.cssExtractionOptions,
      }
  • It also:

    • Enforces development Babel environment, and sets its cssLocalIdent argument equal [path][name]___[local]___[hash:base64:6] to generate verbose classnames for CSS modules, which are handy for debug purposes.
    • Adds webpack-hot-middleware/client?reload=true to entrypoints, which is necessary for HMR (Hot Module Reloading) setup.
    • Emulates the following environment variables:
      • BABEL_ENV and NODE_ENV are both set equal development.
      • DEV_TOOLS is set equal true.
      • REACT_GLOBAL_STATE_DEBUG is set equal true.
    • Adds the following plugins:

Production

const configFactory = require('@dr.pogodin/react-utils/config/webpack/app-production');

configFactory(options) => object;

The factory function creates Webpack configuration for production environment. It accepts the same options as the base app config, and does the same stuff, then on top of that it:

  • Changes default value of babelLoaderExclude option to [], to ensure that Babel re-compiles all 3rd-party modules, to ensure compatibility of bundled code with requested target environments.

    It also defaults compact option of Babel config to true, to avoid warnings about Babel resetting code layout style of 3rd party modules.

  • Accepts additional options:

    • cssExtractionOptionsobject — Optional. Customizes settings of MiniCssExtractPlugin (it emits CSS assets from the build), which is included into the config with the following configuration:
      {
      chunkFilename: '[contenthash].css',
      filename: '[contenthash].css',
      ...ops.cssExtractionOptions,
      }
  • It also:

Build Info

While creating a Webpack config for app builds, the base app config factory generates a "build info" object with the following fields:

  • key - string - A random 32-bit encryption key.

    BEWARE

    This key is not secure, as it is send to the client side within the JS bundle. During the runtime it is only used to encrypt at the server side, and then decrypt at the client side internal app's config and data injected into the initial HTML markup during SSR. This way we avoid sending these data as plain text within HTML, but apparently anybody having both HTML and JS bundle at hands (e.g. client browser) is able to easily decrypt these data.

  • publicPath - string - A copy of build's publicPath value.

  • useServiceWorker - boolean - A flag indicating whether service worker should be used by the app.

This object is made accessible to the app during the runtime both at the client side (it is injected into the bundled JS code), and at the server side (see isomorphy.getBuildInfo()). The config factory writes this object into the "context" folder of the build, as .build-info file (it can be opted out by dontEmitBuildInfo option of the config factory, also fs option can be used to output the file into a virtual filesystem).

The keepBuildInfo option of the base app config factory allows to reuse old "build info" data, which is inteded for development and test scenarious.

Changelog
  • In the library versions v1.17.2 ÷ v1.17.4 the "build info" object was also exposed via the .buildInfo field attached to the standard config factories after each build. This was dropped in v1.17.5 in favour of passing it via a virtual filesystem (see fs option of the config factory).

Library Config

Base

const configFactory = require('@dr.pogodin/react-utils/config/webpack/lib-base');

configFactory(options) => object;

This factory function creates base Webpack config for libraries, which contains the core setup common for development and production library targets. The options argument is an object with the following valid fields:

  • Required:

    • babelEnv - string - Babel environment.
    • context - string - Base URL for resolution of relative config paths.
    • entry - string | string[] - Entry point(s). The config may prepend them by necessary polyfills.
    • library - string - Library name. It is important for proper resolution of library assets.
  • Optional:

    • babelLoaderOptions - object - Overrides default Babel options for JSX and SVG loading.

    • cssLocalIdent - string - The template for CSS classnames generated by Webpack's css-loader. It should match the corresponding setting in Babel config. Defaults to hash:base64:6.

    • dontUseProgressPlugin - boolean - Set true to opt out of including the Webpack's ProgressPlugin into the config. This is intended for test scenarious, to avoid polluting test logs with detailed console output from test Webpack builds.

    • cssExtractionOptionsobject — Customizes settings of MiniCssExtractPlugin (it emits CSS assets from the build), which is included into the config with the following configuration:

      {
      filename: 'style.css',
      ...ops.cssExtractionOptions,
      }
    • mode - string - Webpack mode.

    • outputPath - string - Build output path. Defaults build.

The generated config does the following:

  • References to font asset (EOF, OTF, SVG, TTF, WOFF, WOFF2) files located in the src/assets/fonts folder of the library's source code are rewritten to to LIBRARY_NAME/src/assets/fonts/FILENAME.FILE_EXTENSION so that the host package of the library is able to find and bundle them.

  • Bundle SCSS files from any folder of source code, beside node_modules and its subfolders. The files are compiled, bundled and extracted into the build/{type}/style.css chunks.

  • Aggregates source maps from dependencies, using source-map-loader.

  • Bundles JS, JSX, and SVG files; they are compiled into build/{type}/web.bundle.js chunks, using the Babel environment specified in the factory options, and client-side Babel config.

  • Sets The following path aliases (relative paths starting with these segments are resolved relative to the corresponding folders):

    • assets for [CONTEXT]/src/assets.
    • components for [CONTEXT]/src/shared/components.
    • fonts for [CONTEXT]/src/assets/fonts.
    • styles for [CONTEXT]/src/styles.
  • Sets resolve.symlinks Webpack option to false to avoid problems with resolution of assets from packages linked with npm link.

  • Declares the following packages as externals:

    • @babel/runtime
    • @dr.pogodin/react-global-state
    • @dr.pogodin/js-utils
    • @dr.pogodin/react-themes
    • @dr.pogodin/react-utils
    • axios
    • cookie
    • dayjs
    • lodash
    • node-forge
    • qs
    • react
    • react-dom
    • react-helmet
    • react-router-dom
    • uuid

Development

const configFactory = require('@dr.pogodin/react-utils/config/webpack/lib-development');

configFactory(options) => object;

Extends and tunes the base library config for development environment. This factory function accepts the same options, and does the same stuff. On top of that it modifies the template for generated classnames to equal [path][name]___[local]___[hash:base64:6] which is handy for debug purposes, and does some other small modifications of config.

Production

const configFactory = require('@dr.pogodin/react-utils/config/webpack/lib-production');

configFactory(options) => object;

Extends and tunes the base library config for production environment. This factory function accepts the same options, and does all the same stuff, and on top of that slightly modifies the resulting config as required for production needs.