Skip to content

Instantly share code, notes, and snippets.

@CoughBall
Last active August 31, 2019 09:12
Show Gist options
  • Save CoughBall/00019343b7adeffb6fe88c5296a31b09 to your computer and use it in GitHub Desktop.
Save CoughBall/00019343b7adeffb6fe88c5296a31b09 to your computer and use it in GitHub Desktop.
My webpack v4 configuration Template I use in my projects (without the comments). Summarized the majority and important parts from webpack v4 official documentation https://webpack.js.org/guides/getting-started/ with explanations and links to discussions from around the web
//https://webpack.js.org/concepts
//webpack requires nodejs to work
// to run webpack manualy and not through npm, with custom config file: "npx webpack --config webpack.config.js"
//how a chunk file is loaded (whether synchronously or asynchronously) is decided by Webpack and you can’t force it to do otherwise
//https://itnext.io/react-router-and-webpack-v4-code-splitting-using-splitchunksplugin-f0a48f110312#1adc
const path = require(`path`);
const HtmlWebpackPlugin = require (`html-webpack-plugin`);
const HtmlWebpackInlineSourcePlugin = require('html-webpack-inline-source-plugin');
const CleanWebPackPlugin = require(`clean-webpack-plugin`);
const webpack = require('webpack');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
module.exports = {
mode: `development`, // change to "production" to minify javascript
devtool: `inline-source-map`, //used for source maps for development and debugging
/*
WEBPACK-DEV-SERVER
used for live reloading and can use hot module replacement with "hot"
when it runs it doesn't write any output files after compiling - so /dist will be empty afterwards !
*/
devServer: {
open: false, //wil not open the browser automatically when starting webpack-dev-server
contentBase: `./dist`, //tells webpack-dev-server to serve files from /dist directory on localhost:8080
hot: true //tell the webpack-dev-server that hot module replacement is used
},
/*starting point for webpack to build dependency graph from for each file, will create a bundle for that file.
in that bundle it will add all its code and the module dependencies it requires
multiple entry points - https://github.com/webpack/webpack/tree/master/examples/multiple-entry-points
used for multi page application
multi-main entry - https://webpack.js.org/concepts/entry-points/
*/
entry: {
main: `./src/index.js`,
},
output: { //output the bundled file name and destination
/*
contenthash vs chunkhash vs hash - https://github.com/neutrinojs/neutrino/issues/844
tldr - use
[contenthash] - creates hash independent for each file from its own content
[chunkhash] - creates unique hash for each file but dependant on the chunk it is in, so if one file changes in the chunk - all the files in it will have its hash changed as well
it shouldnt be used with hot module replacement in development ! it will break the build https://github.com/webpack/webpack/issues/2393#issuecomment-216614060.
instead use [hash]
[hash] - creates the same hash for all files - so if one changes all of them do
[name] will generate a bundle js file for multiple entry js files - in this case we have one named "main"
so if u have app.js and index.js it will create app.bundle.js and index.bundle.js*/
filename: `[name].[contenthash].js`,
chunkFilename: `[name].[contenthash].js`,
path: path.resolve(__dirname, `dist`)
},
/*
Can call each plugin multiple times to create multiple different entries
*/
plugins: [
// new webPack.HotModuleReplacementPlugin(), //hot module replacement
/*
Clears /dist folder of garbage files that are not part of the build
*/
new CleanWebPackPlugin(),
/*
html-webpack-plugin
The plugin creates an index.html file from a template.
useful when you change the entry point name, it changes the index.html reference to it automatically
*/
new HtmlWebpackPlugin({
title: `TODO - change`,
inlineSource: `runtime~.+\\.js`, //option added by HtmlWebpackInlineSourcePlugin plugin, we tell it to embed the runtime js file in the html
filename: 'index.[chunkhash].html' //used for long term caching for when the file is changed - will create a generated html in dist with hashed name - for now cant use contenthash https://github.com/jantimon/html-webpack-plugin/issues/1099
}),
/*html-webpack-inline-source-plugin
The plugins extends HtmlWebpackPlugin by letting it inline any javascript or css files we want within the created html file
by using regex
This plugin needs to come after HtmlWebpackPlugin in the plugins otherwise the build will fail
*/
new HtmlWebpackInlineSourcePlugin(),
/*
Used to extract files (javascript, chunks, css etc...)
Can also be used to extract seperate css files (per js file) from the bundles webpack creates.
otherwise the css will be bundled in the javascript file.
Should replace the loader for css in rules
https://survivejs.com/webpack/styling/separating-css/
*/
new MiniCssExtractPlugin({
filename: '[name].[contenthash].css', //use content hash for css files so if their js file changes in their chunk, the css file hash wont change with them https://survivejs.com/webpack/optimizing/adding-hashes-to-filenames/
chunkFilename: '[name].[contenthash].css' //chunkFilename - the [name] will be replaced the name of the group defined in one of the splitChunks groups
}),
/*
https://developers.google.com/web/fundamentals/performance/webpack/use-long-term-caching#make_module_ids_more_stable
https://webpack.js.org/guides/caching/#module-identifiers
changes module ids from numbers to hashes
*/
new webpack.HashedModuleIdsPlugin({ //should be used in production
hashFunction: 'sha256',
hashDigest: 'hex',
hashDigestLength: 20
})
],
/* LOADERS -
Out of the box, webpack only understands JavaScript and JSON files.
Loaders allow webpack to process other types of files and convert them into valid modules
that can be consumed by your application and added to the dependency graph. (loaders do their work before the bundle)
*/
module: {
rules: [
{
test: /\.css$/, //regex to determine which file the following loaders should transform
//the below is replaced by the MiniCssExtractPlugin to extract css
// use: [ //which loaders should do the transformation for the above files detected by the regex
// `style-loader`, //style-loader - use the above string and injects it as a <style> in the index.html
// `css-loader` //css-loader - converts all css files into one string so we can import them
// ]
use: [
MiniCssExtractPlugin.loader,
'css-loader'
]
},
{
test: /\.m?js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
}
]
},
optimization: {
//runtimeChunk ensures that if we change our js file then the hash for vendors wont change as well, also creates a third file called runtime
//https://developers.google.com/web/fundamentals/performance/webpack/use-long-term-caching
runtimeChunk: {
name: "runtime" //name will be prefix instead of default of the file name with a dot
},
splitChunks: {
chunks: 'all', //chunks all - Reduces file size in case we call a module from two different places, removes duplication of that imported module
/**
* cacheGroups define rules for how Webpack should group chunks into output files
*/
cacheGroups: {
//https://developers.google.com/web/fundamentals/performance/optimizing-javascript/code-splitting#removing_duplicate_code
// Split vendor (3rd party javascript) code to its own one chunk
vendors: {
name: `vendor`,
test: /[\\/]node_modules[\\/]/i,
chunks: `all` // "all" means sync + async chunks will be added to vendor formed chunk https://github.com/webpack-contrib/mini-css-extract-plugin/issues/36
//https://itnext.io/react-router-and-webpack-v4-code-splitting-using-splitchunksplugin-f0a48f110312#7251
//instead you can split each 3rd party vendor to its own chunk
//https://hackernoon.com/the-100-correct-way-to-split-your-chunks-with-webpack-f8a9df5b7758
/*
test: /[\\/]node_modules[\\/]/,
name(module) {
// get the name. E.g. node_modules/packageName/not/this/part.js
// or node_modules/packageName
const packageName = module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1];
// npm package names are URL-safe, but some servers don't like @ symbols
return `npm.${packageName.replace('@', '')}`;
}
*/
},
/*tell webpack to create a new chunk (or use an existing chunk that already imported it using reuseExistingChunk)
if a module is used (imported) by 2 or more chunks/modules https://itnext.io/react-router-and-webpack-v4-code-splitting-using-splitchunksplugin-f0a48f110312#4199
*/
common: {
name: `common`,
minChunks: 2, //if the module is used in at least 2 different places
chunks: `all`,
priority: 10, //priority is less than vendor so vendors wont be part of this chunk
reuseExistingChunk: true,
enforce: true //create this chunk no matter if it doesnt have the minimum needed size or passes max size
}
}
},
//minimizer overrides default minifier of webpack, so javascript wont be minified in production mode, will need to add your own here instead
minimizer: [
new OptimizeCssAssetsPlugin({}) //minifies css
]
},
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment