3.1.0 • Published 6 months ago

@siteone/webpack-config v3.1.0

Weekly downloads
-
License
MIT
Repository
-
Last release
6 months ago

SiteOne Webpack 5 config

This package contains basic webpack configuration for server-generated websites (it is not meant to be used for SPAs). It works best with Craft CMS and twigpack plugin, but it could be used with almost any type of BE frameworks/CMS like wordpress or nette. We don't provide a way how to load your assets in your templates. For Craft CMS we are using twigpack plugin, other than that it's up to you. You can simply use script/style tag or create some automatic solution that parses your manifest.json file and inserts your tags for you.

The goal is to provides webpack configuration that can be updated and maintained from one place and used on multiple projects. It provide basic config that can be used only partially or/and extended to fit your project needs.

It is inspired by nystudio107/annotated-webpack-config and it can be used with Twigpack plugin for Craft CMS

Installation

yarn add webpack webpack-cli @babel/core @siteone/webpack-config --dev

OR

npm install webpack webpack-cli @babel/core @siteone/webpack-config --save-dev

Basic Example

Create webpack.common.js

const {
  buildWebpackConfig,
  createConfigFunctions,
} = require("@siteone/webpack-config");

const settings = {
  js: {
    entries: {
      test: "./templates/_modules/test/test.js",
    },
    output: {
      path: path.resolve(__dirname, "./web/dist/"),
    },
  },
};

const configFunctions = [
  // Common
  createConfigFunctions.createCommonConfig,
  createConfigFunctions.createManifestConfig,
  // Scss
  createConfigFunctions.createMiniCssExtractConfig,
  createConfigFunctions.createCssLoaderConfig,
  createConfigFunctions.createPostCssLoaderConfig,
  createConfigFunctions.createSassLoaderConfig,
  // JS
  createConfigFunctions.createBabelLoaderConfig,
];

const webpackModernProdConfig = buildWebpackConfig(
  settings,
  configFunctions,
  "production"
);

Features

Composition

This configuration is split into small blocks that contain configuration only for a certain plugin, loader, etc. With this approach, you can decide to use or omit any part.

For example, there are separate configurations for:

  • cssLoader
  • sassLoader
  • postCss

So you can decide if you would like to use postCss, Sass, or just simple CSS with no further processing. Every part of this configuration export createConfig function. It accepts settings object and returns partial of webpack configuration object.

Example:

createSassLoaderConfig = (settings) => {
  return {
    module: {
      rules: [
        {
          test: /\.scss$/,
          use: ["sass-loader"],
        },
      ],
    },
  };
};

These partials are then merged with webpack-merge plugin.

const webpackConfig = merge(
  // other createConfig functions
  createMiniCssExtractConfig(settings),
  createCssLoaderConfig(settings),
  createPostCssLoaderConfig(settings),
  createBabelLoaderConfig(settings)
);

This allows you to add your createConfig function and extend your configuration. Or omit any function you don't want to use.

Legacy and modern mode

Inspired by nystudio107/annotated-webpack-config you can exploit the configuration object to create more different webpack configs.

This means we provide two default configurations. Other than that it's up to you which features you would like to use in each mode.

The difference is that legacy config contains other browserslist than modern and this way you can build modern and legacy assets then distribute these assets to different browsers. So old browsers should still work but bundle for modern browsers doesn't have to be compiled to old js. This way you can save some bundle size.

API

buildWebpackConfig(userSettings, createConfigFunctions, webpackMode, [type])

Creates a webpack config based on the given configuration and createConfig functions.

Arguments

  1. userSettings (Object): Partial of settings object

Settings:

keytypeDefault (modern/legacy)Description
assetsobjectsee below
assets.filenamestring"assets/hashquery"webpack custom output filename
jsobjectsee below
js.browserslistarray"> 1%", "last 2 versions", "Firefox ESR" / "last 2 Chrome versions", "not Chrome < 60", "last 2 Safari versions", "not Safari < 10.1", "last 2 iOS versions", "not iOS < 10.3", "last 2 Firefox versions", "not Firefox < 54", "last 2 Edge versions", "not Edge < 15", browserslist array definition
js.outputobjectsee below
js.output.pathstring"./web/dist/"webpack output.path
js.output.publicPathstring"/dist/"webpack output.publicPath
js.output.filenamestring"name.contenthash.js" / "name-legacy.contenthash.js"webpack output.filename
js.entriesstring | objectnullwebpack entry
cssobjectsee below
css.browserslistarray"> 1%", "last 2 versions", "Firefox ESR"browserslist array definition
css.filenamestring"name.contenthash.css"minicssextract filename
css.sassLoaderOptionsobject{}webpack sass-loader options
devServerobjectsee below
devServer.portnumber8080webpack dev-server port
devServer.hoststringlocalhostwebpack dev-server host
devServer.httpsbooleanfalsewebpack dev-server https
devServer.contentBasestring"./templates",webpack dev-server contentBase
devServer.publicstringnullwebpack dev-server public
devServer.publicPathstringnullwebpack dev-server publicPath
devServer.sockHoststringnullwebpack dev-server sockHost
resolveobjectsee below
resolve.aliasesobject{}webpack resolve.alias
resolve.extensionsarray[]webpack resolve.extensions
  1. createConfigFunctions(array): Array of createConfig functions. Order matters.

  2. webpackMode(string): Webpack mode

  3. [type]("modern" | "legacy"): Default is "modern". Determinate which default settings are loaded and merged with your userSettings

Returns

(Object): Returns an object corresponding to partials returned by provided creteConfigFunctions merged together and combined with settings. It should be partial of webpack config (not validated though).

Example

const {
  buildWebpackConfig,
  createConfigFunctions,
} = require("@siteone/webpack-config");

const settings = {
  js: {
    entries: {
      test: "./templates/_modules/test/test.js",
    },
    output: {
      path: path.resolve(__dirname, "./web/dist/"),
    },
  },
};

const configFunctions = [
  // Common
  createConfigFunctions.createCommonConfig,
  createConfigFunctions.createManifestConfig,
  createConfigFunctions.createAssetsConfig,
  createConfigFunctions.createOptimizationConfig,
  // Scss
  createConfigFunctions.createMiniCssExtractConfig,
  createConfigFunctions.createCssLoaderConfig,
  createConfigFunctions.createPostCssLoaderConfig,
  createConfigFunctions.createSassLoaderConfig,
  createConfigFunctions.createCssMinimizerConfig,
  // JS
  createConfigFunctions.createBabelLoaderConfig,
];

const webpackModernProdConfig = buildWebpackConfig(
  settings,
  configFunctions,
  "production"
);

// Config with added dev server configuration
const webpackModernDevConfig = buildWebpackConfig(
  modernSettings,
  [createConfigFunctions.createDevServerConfig, ...configFunctions],
  "development"
);

type createConfig(settings)

The whole configuration is created by these createConfig functions that accept settings object and returns partial of webpack config, that is later merged together in a specified order.

Arguments

  1. settings(object): Settings object read more in buildWebpackConfig section.

Reurns

(object): Return a partial of webpack config object.

Example

const createBabelLoaderConfig = (settings) => {
  return {
    module: {
      rules: [
        {
          test: /\.js$/,
          exclude: /node_modules/,
          use: {
            loader: "babel-loader",
            options: {
              cacheDirectory: true,
              sourceType: "unambiguous",
              presets: [
                [
                  "@babel/preset-env",
                  {
                    modules: false,
                    corejs: {
                      version: 2,
                      proposals: true,
                    },
                    useBuiltIns: "usage",
                    targets: {
                      browsers: settings.js.browserslist,
                    },
                  },
                ],
              ],
              plugins: [
                "@babel/plugin-syntax-dynamic-import",
                "@babel/plugin-transform-runtime",
              ],
            },
          },
        },
      ],
    },
  };
};

Tip

  • You can add your custom settings in the settings object
  • You can create your own set of createConfig functions and save it to your custom package and then use it together with this package

Using with Twigpack

Like it was mentioned before this package was created to be used with Craft CMS and Twigpack plugin. Twigpack takes care of loading assets to your templates, cache busting, etc.

Basic example

package.json

"scripts": {
  "build": "webpack --config webpack.prod.js --progress",
  "dev": "webpack serve --config webpack.dev.js"
},

webpack.common.js - this is where your config lives

const path = require("path");
const {
  buildWebpackConfig,
  createConfigFunctions,
} = require("@siteone/webpack-config");

const commonSettings = {
  js: {
    entries: {
      test: "./templates/_modules/test/test.js",
    },
    output: {
      path: path.resolve(__dirname, "./web/dist/"),
    },
  },
};

const modernSettings = {
  ...commonSettings,
};

const legacySettings = {
  ...commonSettings,
};

const commonConfigFunctions = [
  // Common
  createConfigFunctions.createCommonConfig,
  createConfigFunctions.createManifestConfig,
  createConfigFunctions.createAssetsConfig,
  createConfigFunctions.createOptimizationConfig,
  // Scss
  createConfigFunctions.createMiniCssExtractConfig,
  createConfigFunctions.createCssLoaderConfig,
  createConfigFunctions.createPostCssLoaderConfig,
  createConfigFunctions.createSassLoaderConfig,
  createConfigFunctions.createCssMinimizerConfig,
  // JS
  createConfigFunctions.createBabelLoaderConfig,
];

const webpackModernProdConfig = buildWebpackConfig(
  modernSettings,
  commonConfigFunctions,
  "production"
);

const webpackLegacyProdConfig = buildWebpackConfig(
  legacySettings,
  commonConfigFunctions,
  "production",
  "legacy"
);

const webpackModernDevConfig = buildWebpackConfig(
  modernSettings,
  [createConfigFunctions.createDevServerConfig, ...commonConfigFunctions],
  "development"
);

module.exports = {
  webpackModernProdConfig,
  webpackLegacyProdConfig,
  webpackModernDevConfig,
};

webpack.dev.js

const { webpackModernDevConfig } = require("./webpack.common");

module.exports = webpackModernDevConfig;

webpack.prod.js

const {
  webpackModernProdConfig,
  webpackLegacyProdConfig,
} = require("./webpack.common");

module.exports = [webpackModernProdConfig, webpackLegacyProdConfig];
const {
  webpackModernProdConfig,
  webpackLegacyProdConfig,
} = require("./webpack.common");

module.exports = [webpackModernProdConfig, webpackLegacyProdConfig];

twigpack.php

return [
    '*' => [
        'manifest' => [
            'legacy' => 'manifest-legacy.json',
            'modern' => 'manifest.json',
        ],

        'server' => [
            'manifestPath' => '@webroot/dist/',
            'publicPath' => '/',
        ],

        'devServer' => [
            'manifestPath' => 'http://localhost:8080/dist',
            'publicPath' => 'http://localhost:8080/',
        ],
    ]
];

This config doesn't support critical CSS generated by webpack. In our opinion, it doesn't make sense as it needs running compiled copy of your website and it doesn't exist at build time. So it's up to you to create some script to generate your critical CSS files. We recommend critical js library.