npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

webpack-spa-config

v1.2.5

Published

Webpack 4 config for SPA

Downloads

17

Readme

Attention

This package is no longer supported. Use webpackon.

Webpack SPA Config

Webpack 4 config for SPA.

This configuration has everything you need to build a SPA. Also this configuration is easy to extend and editing.

🔥In this configuration there is "compatibility" mode. It is a separate build for old and new browsers. Js files size for new browsers is reduced by about 11%.

Full example with output assembly can be seen here - https://github.com/AndTem/webpack-spa-config/tree/master/example.

Installation

npm install --save-dev webpack-spa-config

Minimum config

webpack.config.js
const { createConfig } = require('webpack-spa-config');

const basicParams = {
  entryPath: resolve(__dirname, 'index.js'),
  outputPath: resolve(__dirname, 'dist'),
  templatePath: resolve(__dirname, 'index.html')
};

module.exports = createConfig({ basicParams });
package.json
...
"scripts": {
  "build": "webpack --mode=production --config webpack.config.js",
  "build-dev": "webpack --mode=development --config webpack.config.js",
  "start": "webpack-dev-server --mode=development"
}
...

Don't forget to fill in the browserlist and babel file.

Default features

Development mode

  • dev-server, hot replace (host on local ip);
  • babel-loader (js, jsx, ts, tsx);
  • css-loader
  • image-loader - limit: 60. Default output directory - 'images'. Extensions: png|jpg|jpeg|gif|webp;
  • svg-loader - default output directory - 'images';
  • svg-sprite-loader - in development mode injects in runtime;
  • fonts-loader - formats: .otf, .eot, .ttf, .woff, .woff2. Default output directory - 'fonts';
  • define process.env.NODE_ENV;

Production mode

  • babel-loader (js, jsx);
  • css-loader, postcss (autoprefixer, flexbugs-fixes), minimizes css. Default output directory - 'styles';
  • image-loader - limit: 60. Default output directory - 'images';
  • svg-loader - default output directory - 'images';
  • svg-sprite - in production mode injects in html;
  • default image-webpack-loader minimezes except jpeg (converted to progressive jpeg) and png (optimiztion level - 3);
  • fonts-loader - formats: .otf, .eot, .ttf, .woff, .woff2. Default output directory - 'fonts';
  • minimizes html;
  • split chunks + runtime chunks;
  • removal of the previous assembly before starting a new one in production;
  • checks for duplicate packets (duplicate-package-checker-webpack-plugin)
  • static bundle report (webpack-bundle-analyzer).

Compatibility mode

When using this mode, the build size for new browsers is reduced by 11% Includes all the features for the selected modification (development|production).

  • it is possible to make a separate babel config for old browsers. Specify in the babel configuration everything that is necessary for old browsers and this will not get into the assembly for new browsers (polyfills);
  • it is possible to make a separate babel config for new browsers. Specify in babel config only what is needed for new browser;
  • sets env name for babel.config;
  • separate reports for each assembly (legacy and modern).

Webpack in compatibility mode injects tags with necessary attributes in html.

<!-- for new browsers. Old browsers not support attribute type="module" -->
<script type="module" src="/modern.545dc46f7bbd77968d14.bundle.js"></script>
<!-- for old browsers. New browsers will ignore the script tag with the nomodule attribute  -->
<script src="/legacy.bc624b7b4b14725030b0.bundle.js" nomodule></script>

How to turn on сompatibility mode - Compatibility example.

createConfig API

const { createConfig } = require('webpack-spa-config');

createConfig(params)

Params object is required.

params: required <Object>

  • basicParams: required <Object>

    • entryPath: required <String>;
    • outputPath: required <String>;
    • templatePath: required <String>. Path to html;
    • publicPath: <String> Default value: '/'. https://webpack.js.org/configuration/output/#outputpublicpath
    • imagesOutputDirectoryName: <String> Default value: 'images'. Names of output images files.;
    • excludeImages: <Regexp>. Exclude images for images loader;
    • svgSpriteRegExp: <Regexp>.
  • addToAllConfigs: <({ mode, compatibility }) => PartConfig>:

    • mode: required <production | development>. The current mode will be transmitted;
    • compatibilityMode: required <legacy | modern>. The current compatibility mode will be transmitted;
    • PartConfig: required <Object>. Part of the configuration that will extend the configurations for all modes.
  • addToDevConfig: <({ mode }) => PartConfig>:

    • mode: required <production | development>. The current mode will be transmitted;
    • compatibilityMode: required <legacy | modern>. The current compatibility mode will be transmitted;
    • PartConfig: required <Object>. Part of the configuration that will extend the configurations for dev mode.
  • addToProdConfig: <({ mode }) => PartConfig>:

    • mode: required <production | development>. The current mode will be transmitted;
    • compatibilityMode: required <legacy | modern>. The current compatibility mode will be transmitted;
    • PartConfig: required <Object>. Part of the configuration that will extend the configurations for prod mode.

Extending/changing the basic configuration

To expand/change the basic configuration, you must use the following functions: addToAllConfigs, addToDevConfig, addToProdConfig. For configurations there is a deep merge except for loaders and plugins.

For loaders (config.module.rules) and plugins (config.plugins) there is a rough replacement. Loaders are replaced using the test field. Plugins are replaced using the constructor name.

Merging configurations will occur in the following order:

  • For dev mode:
    1. merge the basic configuration with the object returned by addToAllConfigs
    2. merge the config received in the first step with the object that the addToDevConfig function returned
  • For prod mode:
    1. merge the basic configuration with the object returned by addToAllConfigs
    2. merge the config received in the first step with the object that the addToProdConfig function returned

There are also ready loaders.

Svg sprite

Using this configuration, you can generate svg and inject it inside html. See how to do it here. Full example - https://github.com/AndTem/webpack-spa-config/tree/master/example.

Loaders

Ready-made loaders can be used.

const { babelLoader } = require('webpack-spa-config');

All loaders are functions and everyone takes the following general parameters:

{
  mode: 'development' | 'production';
  test?: RegExp;
  exclude?: RegExp | string[];
}

For all loaders you can change the parameters described above

Scripts loaders

babelLoader({ mode, test, exclude, options })

Params:

{
  mode: 'development' | 'production';
  test?: RegExp;
  exclude?: RegExp | string[];
  // (babel-loader options)
  options?: Object;
}

Default test extensions - js, jsx, ts, tsx. Runs in a separate thread.

Styles Loaders

cssLoader({ mode, test, exclude })

Params:

{
  mode: 'development' | 'production';
  test?: RegExp;
  exclude?: RegExp | string[];
}

Contains: style-loader, css-loader, postcss-loader (autoprefixer). In production minify.

sassLoader({ mode, test, exclude })

Params:

{
  mode: 'development' | 'production';
  test?: RegExp;
  exclude?: RegExp | string[];
}

Contains: style-loader, css-loader, postcss-loader (autoprefixer), sass-loader. In production minify.

Images Loaders

imagesLoader({ mode, test, exclude, optimizationOptions, outputDirectoryName })

Params:

{
  mode: 'development' | 'production';
  // image-webpack-loader optinos
  optimizationOptions?: Object;
  outputDirectoryName?: string;
  test?: RegExp;
  exclude?: RegExp | string[];
}

Contains: url-loader, image-webpack-loader.

Default test RegExp - /.(png|jpg|jpeg|gif|webp)$/i

Converts images to base64 if file size <= 60.

In production minify images. Default optimizationOptions:

{
  mozjpeg: {
    progressive: true,
    quality: 90
  },
  optipng: {
    optimizationLevel: 3
  },
  pngquant: {
    enabled: false
  }
}

svgLoader({ mode, test, exclude, optimizationOptions, outputDirectoryName })

Params:

{
  mode: 'development' | 'production' | 'legacy' | 'modern';
  // image-webpack-loader optinos
  optimizationOptions?: Object;
  outputDirectoryName?: string;
  test?: RegExp;
  exclude?: RegExp | string[];
}

Contains: file-loader, image-webpack-loader. In production minify svg. (default image-webpack-loader options).

svgSpriteLoader({ mode, test, exclude, extractInProd, options, optimizationOptions })

Params:

{
  mode: 'development' | 'production' | 'legacy' | 'modern';
  // svg-sprite-loader optinos
  options?: Object;
  // image-webpack-loader optinos
  optimizationOptions?: Object;
  test?: RegExp;
  exclude?: RegExp | string[];
}

Contains: svg-sprite-loader, image-webpack-loader. Adds a satisfying "test" regExp svg to sprite. In production minify svg. (default image-webpack-loader options).

Don't forget to add excludeSvg param in commomConfigParams, SpriteLoaderPlugin in prodOptions and inject to html template code as in the example.

Fonts Loaders

fontsLoader({ mode, test, exclude, outputDirectoryName })

Params:

{
  mode: 'development' | 'production' | 'legacy' | 'modern';
  outputDirectoryName?: string;
  test?: RegExp;
  exclude?: RegExp | string[];
}

Contains: files-loader.

Mode utils

There are ready-made utils for working with modes.

const { isProduction, isDevelopment, isLegacyMode, isModernMode } = require('webpack-spa-config');
  • isProduction(mode)
  • isDevelopment(mode)
  • isLegacyMode(compatibilityMode)
  • isModernMode(compatibilityMode)

Example of expansion/change of configuration

webpack.config.js
const { resolve } = require('path');
const { createConfig, sassLoader } = require('webpack-spa-config');

const scriptsPath = resolve(__dirname, 'src', 'scripts');
const publicFilesPath = resolve(__dirname, 'public');
const outputPath = resolve(__dirname, 'build');
const imagesPath = resolve(publicFilesPath, 'images');

const basicParams = {
  entryPath: resolve(scriptsPath, 'index.jsx'),
  outputPath,
  templatePath: resolve(publicFilesPath, 'index.html')
};

const addToAllConfigs = ({ mode }) => ({
  module: {
    rules: [
      sassLoader({ mode }),
      // replace default cssLoader ()
      {
        test: /\.css$/,
        use: [
          'style-loader',
          { loader: 'css-loader', options: { importLoaders: 1 } },
          'postcss-loader'
        ]
      }
    ]
  },
  resolve: {
    alias: {
      src: resolve(scriptsPath),
      images: imagesPath,
      sprite: resolve(imagesPath, 'sprite')
    }
  }
});

const addToDevConfig = () => ({
  // merge with default dev config
  devServer: {
    open: false
  },
  // output
  //   devServer: {
  //     contentBase: outputPath,
  //     host: '0.0.0.0',
  //     open: false,
  //     hot: true,
  //     useLocalIp: true,
  //     historyApiFallback: true
  //   },
  plugins: [
    new webpack.DefinePlugin({
      'process.env.IS_PRODUCTION': JSON.stringify(false)
    })
  ]
});

const addToProdConfig = () => ({
  devtool: 'source-map',
  plugins: [
    new webpack.DefinePlugin({
      'process.env.IS_PRODUCTION': JSON.stringify(true)
    })
  ]
});

module.exports = createConfig({
    basicParams,
    addToAllConfigs,
    addToDevConfig,
    addToProdConfig
  });

Example with svg sprite

In this example, svg-sprite in prod mode is loaded from the browser as a separate file.

webpack.config.js
const { resolve } = require('path');
const SpriteLoaderPlugin = require('svg-sprite-loader/plugin');
const { createConfig, svgSpriteLoader } = require('webpack-spa-config');

const scriptsPath = resolve(__dirname, 'src', 'scripts');
const publicFilesPath = resolve(__dirname, 'public');
const outputPath = resolve(__dirname, 'build');

const svgSpriteRegExp = /sprite\/*\/.*\.svg$/i;

const basicParams = {
  entryPath: resolve(scriptsPath, 'index.jsx'),
  outputPath,
  templatePath: resolve(publicFilesPath, 'index.html'),
  svgSpriteRegExp
};

const addToAllConfigs = ({ mode }) => ({
  module: {
    rules: [
      // in prod mode extract: true
      svgSpriteLoader({ mode, test: svgSpriteRegExp })
    ]
  }
});

const addToProdConfig = () => ({
  plugins: [new SpriteLoaderPlugin()]
});

module.exports = createConfig({
    basicParams,
    addToAllConfigs,
    addToProdConfig
  });

Use url param for load svg-sprite file.

import twitterIcon from '../public/images/sprite/twitter.svg';
// => {id string, width: string, height: string, viewBox: string, url: string}

const TwitterIcon = ({ url, viewBox, width, height }) => (
  <svg
    fill="currentColor"
    viewBox={twitterIcon.viewBox}
    width={twitterIcon.width}
    height={twitterIcon.height}
  >
    <use xlinkHref={twitterIcon.url} />
  </svg>
);

Other examples: https://github.com/JetBrains/svg-sprite-loader/tree/master/examples.

Compatibility example

package.json
...
"scripts": {
  "build:compatibility:dev": "COMPATIBILITY=true webpack --mode=development --config webpack.config.js",
  "build:compatibility:prod": "COMPATIBILITY=true webpack --mode=production --config webpack.config.js",
}
...
webpack.config.js
const { resolve } = require('path');
const FaviconsWebpackPlugin = require('favicons-webpack-plugin');
const { createConfig, isModernMode } = require('webpack-spa-config');

const scriptsPath = resolve(__dirname, 'src', 'scripts');
const publicFilesPath = resolve(__dirname, 'public');
const outputPath = resolve(__dirname, 'build');

const basicParams = {
  entryPath: resolve(scriptsPath, 'index.jsx'),
  outputPath,
  templatePath: resolve(publicFilesPath, 'index.html')
};

const addToAllConfigs = ({ compatibilityMode }) => {
  const configPart = {
    devtool: 'source-map'
  };

  if (isModernMode(compatibilityMode)) {
    configPart.plugins = [
      new FaviconsWebpackPlugin({
        logo: 'favicon.png',
        prefix: `favicons${sep}`,
        emitStats: false,
        inject: true
      })
    ]
  }

  return configPart;
};

module.exports = createConfig({
    basicParams,
    addToAllConfigs
  });
babel.config.js
module.exports = {
  env: {
    // This is the config we'll use to generate bundles for legacy browsers.
    legacy: {
      presets: [
        [
          "@babel/preset-env", {
            useBuiltIns: "usage"
          }
        ],
        "@babel/preset-react"
      ],
      plugins: [
        "@babel/plugin-transform-runtime",
        "@babel/plugin-syntax-dynamic-import"
      ]
    },
    // This is the config we'll use to generate bundles for modern browsers.
    modern: {
      presets: [
        [
          "@babel/preset-env", {
            targets: {
              // This will target browsers which support ES modules.
              esmodules: true
            }
          }
        ],
        "@babel/preset-react"
      ],
      plugins: [
        "@babel/plugin-transform-runtime",
        "@babel/plugin-syntax-dynamic-import"
      ]
    }
  },
  // default config (development or production mode)
  presets: [
    [
      '@babel/preset-env',
      {
        targets: {
          // This will target browsers which support ES modules.
          esmodules: true
        }
      }
    ],
    '@babel/preset-react'
  ]
};
.browserslistrc
chrome >= 55
firefox >= 52
opera >= 42
edge >= 18
ie >= 9