This article is also published on personal blog clloz.com, welcome to exchange.
preface
Spent a few days to learn the usage of Webpack in detail, basically common configuration and some of the main loader and plugin usage and configuration have learned a lot, but really have to start from the beginning of their own configuration and a little confused feeling. Learning is like this. Seeing is one thing, doing is another. It is only through constant practice that mistakes, corrections, and repetition can be truly mastered. After learning the basic knowledge of Webpack, it is necessary to constantly repeat manual configuration and understanding principle, plus the learning and practice of optimization, to truly master this powerful tool.
This article puts together a generic WebPack configuration template as a practical exercise to go through the process of creating folders, installing packages, and writing configuration files for a project, as well as reviewing esLint and Prettier configurations before it.
Various webpack related articles on the Internet are very rough, many details are not said, as a novice to read a headache, and because of WebPack 5 also came out, some of the plug-ins mentioned in the previous articles have not been maintained or recommended to use. My configuration file is very detailed annotation, and almost all the functions I know are configured, if you are also new, I believe that there will be some help, if you have questions, you can email me to discuss.
If you are not familiar with Webpack, you can take a look at my Webpack study Notes
The installation
All the code in this article is on Github, all configuration functions have been tested, you can learn to see.
NPM install installs the package
The NPM run DLL generates the pre-compiled modules tested in this example with react and Vue
NPM run dev runs the package configuration of the development environment, enabling hot updates
NPM run build runs the production environment’s packaging configuration, enables cache compression, and so on, depending on the configuration file
Webpack.base.conf. js is the base configuration, webpack.dev.conf.js is the development configuration, and webpack.prod.conf.js is the production configuration. All are merged using webpack-merge, the last one is wepback.dll.conf.js, which uses dllPlugin to precompile modules.
In this example, the webpack version is 5.4.0, webpack-CLI version is 4.2.0, and webpack-dev-server is 3.11.0.
Configuration function
- Multi-entry multi-environment configuration
- Detached style file
mini-css-extract-plugin
- Use small images and fonts
base64
Packed intoHTML
- Clear unused
CSS
:purgecss-webpack-plugin
- use
html-webpack-plugin
: Generates an entry file and compresses it - use
friendly-errors-webpack-plugin
Optimize command line output - use
stylelint-webpack-plugin
forCSS
Code review - use
html-webpack-tags-plugin
forhtml-webpack-plugin
The enhancements help us at the entranceHTML
inserttag
- use
thread-loader
Enable multi-threaded compilation - open
babel-loader
The cache - more
loader
Set respectivelypublicPath
- add
eslint-loader
Check the code, and have detailedeslint
和prettier
configuration - use
postcss-loader
和autoprefixer
In combination withbrowserslist
forCSS
Automatically adds browser prefixes - use
DLLPlugin
和DLLReferencePlugin
Perform module precompilation and invocation - use
splitChunks
Extract common modules - Enable hot module update for the development environment
- Turn on the production environment
TerserPlugin
Parallel compression and turn off the generation of open source certificate files - use
CssMinimizerPlugin
forCSS
The parallel compression of - use
CleanWebpackPlugin
Clean up the package directory - use
raw-loader
Introduce the file as a string - use
html-loader
将html, js
in-line - A variety of packaging efficiency check tools, refer to the package below
Packages to install
Here is a list of the packages that need to be installed for different parts, so that it is more clear, to help clarify the logic of the entire build, but also convenient review. Not all packages need to be installed, so I’ve listed some that might be used.
Webpack related
- webpack
- webpack-cli
- webpack-dev-server
webpack loader
- CSS
style-loader
: Puts the style into astyle
Tag inserted intohead
In, you can set the style sheet inlinecss-loader
: Handle stylesheet dependencies and hand them over when donestyle-loader
postcss-loader
: a plug-in carrier, can cooperate with the plug-in to achieve many functions, such asautoprefixer
, requires installationpostcss
less-loader
: parsingless
, requires installationless
sass-loader
parsingsass
, requires installationsass
stylus-loader
: parsingstylus
, requires installationstylus
.stylus
The support is not very good, you can refer toUse stylelint to detect the Stylus code in vUEpx2rem-loader
: transformCSS
To the unit ofrem
In order to realize the adaptive of different devicesstyle-resouces-loader
: We can put the global style in a single file, theloader
Can help us inject other style files at the time of packaging, without us in every style file@import
.vue-cli-style-resources-loader
: same as above
- image & file
- file-loader
- url-loader
JavaScript
thread-loader
: Multi-threaded packaging- Babel-loader: parse conversion
ES6+
code eslint-loader
: Code reviewcache-loader
: Cache followsloader
The processing results of,webpack 5
No longer needed because of the built-in cache configuration, addcache
For details, refer to the official document
HTML
html-loader
: Used to achieveHTML
和JavaScript
Inline, you can output the file as a stringraw-loader
: Outputs the file as a string
- Vue –
vue-loader
webpack plugin
- CSS
mini-css-extract-plugin
: Separate style files. Do not use them in a development environment. Styles cannot be hot updatedautoprefixer
: Automatically adds the vendor prefix aspostcss
The plug-inpostcss-preset-env
: Use newer onesCSS
Characteristic, aspostcss
The plug-inpostcss-import
: Support various@import
Import it directly as textwebpack 5
Built in to@import
The processing of this plug-in can be done without opening it@import
The introduction ofCSS
Insert directly into currentCSS
中postcss-url
Can:url()
The path in the function is configured in various ways (the specific usage is not studied out, the official documentation is not given inwebpack
和postcss.config.js
Configuration in)stylelint
: Style code checking tool, need to be installedstylelint-config-standard
cssnano
:CSS
compressoroptimize-css-assets-webpack-plugin
: callcssnano
For code compression, separate style files are required, and WebPack 5 recommends the following insteadcss-minimizer-webpack-plugin
css-minimizer-webpack-plugin
:webpack 5
It is recommended to use this plug-inCSS
The compression oflib-flexible
: is not a plug-in, but an adaptive tool that needs to be added to the production environment and is inline toHTML
On, notice that the plug-in will be inbody
Set onfont-size
, so don’tbody
Set font on. At present, the library is no longer maintained, and is officially not recommended for use, but recommendedvm
To achieve adaptive, not expanded here, you can refer toAdaptive schemehtml-inline-css-webpack-plugin
: can be used to implementCSS
inlinepurgecss-webpack-plugin
: Erase unusedCSS
- HTML
html-webpack-plugin
: generate entryHTML
, support multi-entry and compression functions,webpack 5
The installationhtml-webpack-plugin@next
JavaScript
terser-webpack-plugin
:JavaScript
Code compression, support for parallel compression, and recommended to enable.splitChunks
: Built-in plug-in for code segmentationhtml-webpack-tags-plugin
: Separate the base libraryhtml-webpack-externals-plugin
: Separate the base librarydefinePlugin
: Configures global variablesprovidePlugin
: Configures the global moduleDLLPlugin
: precompile resource modules, including global modules such asreact
.react-dom
General-purpose libraries and components are subcontracted to generatemanifast.json
File, which is a description of the detached packageDLLReferencePlugin
Through:manifast.json
Reference the detached package
- The efficiency of tool
HotModuleReplacementPlugin
: Hot replacement of the modulehard-source-webpack-plugin
: module cache,webpack 5
No longer needed because of the built-in cache configuration, addcache
For details, refer to the official documentclean-webpack-plugin
: Automatically clears the package directorycross-env
: Sets environment variableswebpack-bundle-analyzer
: Generate a representation module composition diagram to help us analyzebundle
Constitute abundlesize
: Automated volume monitoring tool, required inpackage.json
configureModuleConcatenationPlugin
:scope hoisting
Reduce the anonymous function of the wrapping module, thus reducing the packaging volume,production
Mode is enabled by default.friendly-errors-webpack-plugin
: Optimizes packaged command line outputcopy-webpack-plugin
: used to copy a single file or entire directory to a new folder, usually when we are packing, to put some files in the specified folderwebpack-dashboard
: Visualizes packaging information in the consolespeed-measure-webpack-plugin
: Analyze the construction process in eachloader
和plugin
The amount of time spent on
Note that if you use WebPack 5, almost all cache-related plug-ins are not needed, because WebPack 5 has a field cache to set the cache. Caching is enabled by default in development mode and disabled in production mode. You can also configure it yourself. Refer to official documentation.
Other Webpack tools
corss-env
: Sets environment variableswebpack-merge
: multi-environment configuration file merge tool
babel
- @babel/cli
- @babel/core
- @babel/preset-env
- @babel/plugin-transform-runtime: used to help us automatically import the transformation module used in
ES6+
Functions required by the code (functions are usually in plug-ins) - @babel/plugin-syntax-dynamic-import
- @babel/polyfill: contains the following two items (now
@babel/polyfill
Deprecated, officially recommendedcore-js
)@babel/plugin-transform-regenerator
Support:generator
和async
@babel/runtime-corejs3
@babel/plugin-syntax-jsx
- React
@babel/preset-react
- Vue
@vue/babel-plugin-transform-vue-jsx
@vue/babel-helper-vue-jsx-merge-props
Code review and formatting
- eslint
eslint-config-airbnb-base
: Optionaleslint
One of the configurations, usednpx install-peerdeps --dev eslint-config-airbnb-base
To installeslint-config-airbnb
: If requiredreact
I’m going to use this. I’m going to usenpx install-peerdeps --dev eslint-config-airbnb
To install
- eslint-plugin-html
- eslint-plugin-prettier
- eslint-config-prettier
- prettier
- stylelint
- stylelint-config-standard
- babel-eslint
- Vue
eslint-plugin-vue
@vue/cli-plugin-eslint
- React
- Eslint plugin – react: in
extends
addeslint:recommended
- Eslint plugin – react: in
Vue
vue-cli
vue
vue-router
vue-template-compiler
React
create-react-app
react
react-dom
react-router-dom
The configuration file
webpack.base.conf.js
webpack.dev.conf.js
webpack.prod.conf.js
webpack.dll.conf.js
.eslintrc.js
.prettierrc.js
babel.config.js
stylelint.config.js
postcss.config.js
.browserlistrc
The directory structure
The configuration file
I suggest you go to Github and pull the project down. This is just to post the configuration
webpack.base.conf.js
const path = require('path');
const webpack = require('webpack');
const glob = require('glob');
const PurgeCSSPlugin = require('purgecss-webpack-plugin'); // Clear unused CSS
const HtmlWebpackPlugin = require('html-webpack-plugin'); // Automatically generate entry HTML according to the template, features are very rich, such as multi-entry, HTML compression, etc., refer to the official documentation, webpack 5 installation html-webpack-plugin@next
const FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin'); // Optimize packaged command line output
const StyleLintPlugin = require('stylelint-webpack-plugin'); The stylelint needs to be installed and configured. For the configuration of stylelint, refer to the official document
const HtmlWebpackTagsPlugin = require('html-webpack-tags-plugin'); // The HtmlWebpackPlugin is enhanced by adding some public resources as tags to the entry HTML
const PATHS = {
src: path.join(__dirname, '.. /src'),};// Generate entry and html-webpack-plugin configurations from the SRC directory
const setMPA = () = > {
const entry = {};
const htmlWebpackPlugins = [];
const entryFiles = glob.sync(path.join(__dirname, '.. /src/app/*/index.js'));
Object.keys(entryFiles).forEach(index= > {
const entryFile = entryFiles[index];
const match = entryFile.match(/src\/app\/(.*)\/index\.js/);
const pageName = match && match[1];
entry[pageName] = entryFile;
htmlWebpackPlugins.push(
new HtmlWebpackPlugin({
inlineSource: '.css$'.template: path.join(__dirname, `.. /src/app/${pageName}/index.html`),
filename: `${pageName}.html`.chunks: [pageName], // It seems that this must be an array, otherwise all chunks will be packaged into each HTML
excludeChunks: ['common'].// An unsolved problem is that splitChunk chunks are added to all entries, even if the module is not used in that entry
inject: true.minify: {
html5: true.collapseWhitespace: true.preserveLineBreaks: false.minifyCSS: true.minifyJS: true.removeComments: false,}})); });return {
entry,
htmlWebpackPlugins,
};
};
const { entry, htmlWebpackPlugins } = setMPA();
module.exports = {
// Live reloading & HMR cannot be enabled when browserslist is configured for webpack-dev-server
target: process.env.NODE_ENV === 'development' ? 'web' : 'browserslist',
entry,
module: {
rules: [{test: /\.js$/,
exclude: /node_modules/.// Exclude the node_modules folder
use: [
{
loader: 'thread-loader'.// Run the following loader in a worker pool to achieve a multi-threaded build.
options: {
workers: 3.// Set the number of workers for thread-loader}, {},loader: 'babel-loader'.options: {
cacheDirectory: true.// Enable the babel-loader cache}},'eslint-loader'.// Configure ESLint for code checking],}, {test: /\.(png|jpg|jpeg|gif|svg)$/,
loader: 'url-loader'.options: {
limit: 4000.// Images less than 4000 Bytes are base64 packed and inserted into HTML
name: 'images/[name][hash:8].[ext]'.// publicPath: '/images/', // Many loaders can set publicPath separately}, {},test: /\.(woff|woff2|eot|otf|ttf)$/,
loader: 'url-loader'.options: {
limit: 3000.// A font smaller than 4000 Bytes will be base64 packed to insert HTML
name: 'fonts/[name].[hash:8].[ext]',},},],},plugins: [
new PurgeCSSPlugin({
paths: glob.sync(`${PATHS.src}/app/**/*`, { nodir: true }),
// paths: globAll.sync([
// `${PATHS.src}/app/index/*`,
// `${PATHS.src}/app/page1/*`,
// `${PATHS.src}/app/page2/*`,
// ]),
}),
// Check the CSS with the stylelint
new StyleLintPlugin({
context: path.join(__dirname, '.. /src'),
files: ['**/*.{html,vue,css,sass,scss}'].fix: false.cache: true.emitErrors: true.failOnError: false,}).// Optimize packaged command line output
new FriendlyErrorsWebpackPlugin(),
// Call the processed DLL package, you can configure more than one
new webpack.DllReferencePlugin({
manifest: require('.. /dll/vue.json'), // eslint-disable-line
}),
new webpack.DllReferencePlugin({
manifest: require('.. /dll/react.json'), // eslint-disable-line
}),
// Insert the base library directly, in the form of CDN
new HtmlWebpackTagsPlugin({
append: false.// If true, insert at the end
scripts: [
/ / {path: 'http://127.0.0.1:8080/react4099a463c42053c458c2.dll.js'},
/ / {path: 'http://127.0.0.1:8080/vue31be234e8395380e3d75.dll.js'},
{ path: '.. /dll/react4099a463c42053c458c2.dll.js' },
{ path: '.. /dll/vue31be234e8395380e3d75.dll.js' },
{ path: '.. /node_modules/lib-flexible/flexible.js' },
],
}),
].concat(htmlWebpackPlugins),
optimization: {
// Code split
splitChunks: {
chunks: 'all'.minSize: 30000.minRemainingSize: 0.minChunks: 2.maxAsyncRequests: 5.maxInitialRequests: 3.automaticNameDelimiter: '~'.usedExports: true.cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors'.minChunks: 2.priority: -10.reuseExistingChunk: true,},common: {
minChunks: 2.priority: -20.name: 'common'.reuseExistingChunk: true.minSize: 0,},},},},// stats: 'errors-only', // outputs only errors, simplifying packaged command line output
};
Copy the code
webpack.dev.conf.js
const path = require('path');
const webpack = require('webpack');
const { merge } = require('webpack-merge');
const baseConfig = require('./webpack.base.conf');
const devConfig = {
mode: 'development'.output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js',},module: {
rules: [{test: /\.css$/,
use: [
'style-loader'.'css-loader'.'postcss-loader',
{
loader: 'px2rem-loader'.options: {
remUnit: 75.remPrecision: 8,},},],}, {test: /\.scss$/,
use: [
'style-loader'.'css-loader',
{ loader: 'postcss-loader'.options: { sourceMap: true}}, {loader: 'sass-loader'.options: { sourceMap: true}},],}, {test: /\.less$/,
use: [
'style-loader'.'css-loader',
{ loader: 'postcss-loader'.options: { sourceMap: true}}, {loader: 'less-loader'.options: { sourceMap: true}}, {loader: 'style-resources-loader'.options: {
patterns: [path.resolve(__dirname, 'src/assets/style/global.less')].injector: 'append',},},],},// Enable module hot update
plugins: [new webpack.HotModuleReplacementPlugin()],
/ / configuration devserver
devServer: {
contentBase: '/'.// devServer startup directory must end with /, because it needs to be a directory, generally do not need to be opened
// publicPath: '.. // Public /', // tell devServer what your static resource path is, mainly so that we can access static resources in the development environment when we set output.publicPath
host: '127.0.0.1'.port: '8082'.hot: true.open: true.stats: 'errors-only',},/ / open source - the map
devtool: 'source-map'};module.exports = merge(baseConfig, devConfig);
Copy the code
webpack.prod.conf.js
const path = require('path');
const { merge } = require('webpack-merge');
const TerserPlugin = require('terser-webpack-plugin'); // Code compression tool, support parallel compression
const { CleanWebpackPlugin } = require('clean-webpack-plugin'); // Clean up the package directory
const MiniCSSExtractPlugin = require('mini-css-extract-plugin'); // Separate the CSS generation file instead of inserting it with the style tag
// A CSS compression tool prior to WebPack 5
// const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
// const cssnano = require('cssnano');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin'); Webpack 5 is a recommended CSS compression tool that supports parallelism
// const HardSourceWebpackPlugin = require('hard-source-webpack-plugin'); // Module cache webpack 5 is no longer needed because of the built-in cache configuration, just add 'cache' field, refer to the official documentation for details
// Some efficiency tools, of your choice
// const BundleAnalyzer = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; // Generate images to visually display packaging information
const DashboardPlugin = require('webpack-dashboard/plugin'); // Graphical command line package output
// const Bundlesize = require('bundlesize'); // Automatic volume monitoring tool, which needs to be configured in 'package.json'
// const SpeedMeasurePlugin = require('speed-measure-webpack-plugin'); // Analyze the time spent on the various' loaders' and 'plugins' during the build process
const baseConfig = require('./webpack.base.conf');
const prodConfig = {
// mode: 'none', //test tree shaking
mode: 'production'.output: {
path: path.resolve(__dirname, '.. /dist'),
filename: '[name][chunkhash:8].js'.// publicPath sets the prefix of the resource when accessed by the browser,
For example, if you package a file MMM. JPG, if you set publicPath, the actual url will be /public/ MMM. JPG, which means you need to put the image in the corresponding public directory to access it.
// So this is a configuration for setting up static resources, because static resources may not be deployed according to the development path during project deployment, and need to be used for unified modification
// When using html-webpack-plugin to package HTML files, the path to import JS files is publicPath + package path
// Set the relative path relative to the entry HTML. If you set/start the path relative to the server root, start the Web server, or use the absolute path, such as CDN
publicPath: '/'.Dist: /dist: / http-server: /dist: / http-server: /dist: /
chunkFilename: '[name][chunkhash:8].js'.// Set the name of the non-import chunk
},
module: {
rules: [{test: /\.css$/,
use: [
MiniCSSExtractPlugin.loader,
'css-loader'.'postcss-loader',
{
loader: 'px2rem-loader'.options: {
remUnit: 75.remPrecision: 8,},},],}, {test: /\.scss$/,
use: [
MiniCSSExtractPlugin.loader,
'css-loader',
{ loader: 'postcss-loader'.options: { sourceMap: true}}, {loader: 'sass-loader'.options: { sourceMap: true}},// style-resources-loader currently does not work in Webpack 5
{
loader: 'style-resources-loader'.options: {
patterns: [path.resolve(__dirname, './src/assets/style/globa.scss'],},},],}, {test: /\.less$/,
use: [
MiniCSSExtractPlugin.loader,
'css-loader',
{ loader: 'postcss-loader'.options: { sourceMap: true}}, {loader: 'less-loader'.options: { sourceMap: true}},// style-resources-loader currently does not work in Webpack 5
{
loader: 'style-resources-loader'.options: {
patterns: '.. /src/assets/style/globa.less',},},],},Cache is enabled only in development mode by default. There are two types of cache: memery and Filesystem. For details, refer to the documentation
cache: {
type: 'memory',},plugins: [
// Extract the CSS file
new MiniCSSExtractPlugin({
filename: '[name]_[contenthash:8].css'.chunkFilename: '[name].[contenthash].css',}).new CleanWebpackPlugin(), // Clean up the package directory
// The CSS MinimizerPlugin used before WebPack 5 is recommended after WebPack 5
// new OptimizeCSSAssetsPlugin({
// assetsNameRegExp: /\.css$/g,
// cssProcessor: cssnano,
// }),
// new HardSourceWebpackPlugin(), // Module cache webPack 5 is no longer needed because of the built-in cache configuration, add 'cache' field, refer to the official documentation for details
new DashboardPlugin(),
// new SpeedMeasurePlugin(),
// new Bundlesize(),
// new BundleAnalyzer(),].optimization: {
minimize: true.minimizer: [
new TerserPlugin({
parallel: true.// Enable parallel compression
extractComments: false.// License.text is not generated
}),
Webpack 5 CSS compression tool
new CssMinimizerPlugin({
parallel: true.// Enable parallel compression})],}};module.exports = merge(baseConfig, prodConfig);
Copy the code
webpack.dll.conf.js
const path = require('path');
const webpack = require('webpack');
const TerserPlugin = require('terser-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
// Multiple entries can be set up to package multiple JS and JSON
entry: {
react: ['react'.'react-dom'].vue: ['vue'.'vue-router'],},output: {
filename: '[name][chunkhash].dll.js'.path: path.join(__dirname, '.. /dll'),
library: '[name]',},plugins: [
new CleanWebpackPlugin(),
new TerserPlugin({
extractComments: false.// License.text is not generated
parallel: true.// Enable parallel compression
}),
new webpack.DllPlugin({
name: '[name]'.// Note that the name must be the same as library, otherwise it will cause subsequent access failures
path: path.join(__dirname, '.. /dll/[name].json'),})]};Copy the code
conclusion
This article is my webpack training as a beginner, if you are also a novice, I hope this article will help you.
Refer to the article
- Webpack4 Multi-page, multi-environment configuration