background
I believe that many children in the interview will often be asked “have you manually configured webpack”, “webpack basic configuration” and other questions. This article takes you through common webPack basics (this article is based on the React stack).
I. Dependency package installation
1. Dependency packages of WebPack
- webpack
Webpack Core package This article relies on version 4.x
- webpack-cli
Webpack command line tool that relies on the WebPack core package
- webpack-dev-server
Development environment code live reloading vs. Hot Module replacement
- webpack-merge
The development and production environments incorporate the WebPack base configuration
npm install webpack webpack-cli webpack-dev-server webpack-merge -D
Copy the code
2. Babel dependency packages
- @babel/core
The JS code is analyzed into AST, which is convenient for each plug-in to analyze the syntax for corresponding processing
- @babel/preset-env
You can use the latest JS syntax without having to manage syntactic conversions or browser polyfills required by the target environment
- @babel/preset-react
React support, such as JSX syntax
- @babel/plugin-proposal-class-properties
- core-js
Supports new ES6 + features, such as Promise, Set, and Iterator
- babel-loader
Parsing js
npm install @babel/core @babel/preset-env @babel/preset-react @babel/plugin-proposal-class-properties core-js@3 babel-loader -D
Copy the code
Starting with Babel V7, all stage presets written for features of the standard proposal stage have been deprecated, and are officially removed @babel/preset-stage-x
3. Dependency packages related to style processing (here take less as an example)
- autoprefixer
Add prefixes to CSS properties for different browsers
- css-loader
- postcss
- postcss-loader
CSS parses into an AST that JS can manipulate, and calls plug-ins to process the AST to get the result
- less
- less-loader
npm install autoprefixer css-loader postcss postcss-loader less less-loader -D
Copy the code
- This can be done by replacing autoprefixer with CSSNext.
- The CSSNext plug-in allows developers to use new features that may be added to future versions of CSS in their current projects.
- Cssnext is responsible for translating these new features into syntax that can be used in current browsers. From an implementation perspective, CSSNext is a collection of PostCSS plug-ins related to future versions of CSS. For example, cssNext already includes the use of Autoprefixer, so using CSSNext eliminates the need for Autoprefixer.
4. File (including picture, video, audio and font files) processing related dependency packages
- file-loader
- url-loader
npm install file-loader url-loader -D
Copy the code
- File-loader returns the URL of the image
- Url-loader can process images based on the limit attribute. When the size of an image is smaller than limit (byte), the image is transferred to Base64. When the size is larger than limit, the image is processed by file-loader.
5. Common plugins dependencies (important)
- clean-webpack-plugin
Clearing the package file
- copy-webpack-plugin
Copy some static resources to a specific folder
- html-webpack-plugin
Create an HTML file and automatically insert the webpack static file into it
- mini-css-extract-plugin
Extract the CSS into a separate file
- optimize-css-assets-webpack-plugin
Compress CSS
- terser-webpack-plugin
Compression js
npm install clean-webpack-plugin copy-webpack-plugin html-webpack-plugin mini-css-extract-plugin optimize-css-assets-webpack-plugin terser-webpack-plugin -D
Copy the code
- The HTML-webpack-plugin can be configured multiple times and is common in multi-entry packaging
- The extract-text-webpack-plugin is used to replace the extract-text-webpack-plugin, which has advantages over the extract-text-webpack-plugin. (1) asynchronous loading (2) no repeated compilation (performance) (3) Simpler configuration (4) CSS specific development
- Terser-webpack-plugin is used to replace uglifyjs-webpack-plugin because UglifyJS does not support ES6 syntax
Webpack configuration
0. Front path configuration file
Add the config.js configuration file
const path = require('path');
const resolve = (dir) => path.resolve(__dirname, dir);
const config = {
// The path specified by publicPath is prefixed to all urls, such as link tags, script tags, and img tags in HTML files
pubicPath: '/'.
template: resolve('.. /public/index.html'),
entry: resolve('.. /src/index.js'),
// Package file location
path: resolve('.. /dist'),
};
module.exports = config;
Copy the code
1. Basic configuration
Add the basic webpack.config.js configuration file as follows:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const config = require('.. /config');
const webpackConfig = {
devtool: false, // This option controls whether and how it is generatedsource map
resolve: {
alias: {
demo: path.join(__dirname, '.. /src/components'),
},
// Try to resolve file suffixes in order. If there are multiple files with the same name but different suffixes, WebPack will resolve files with the suffixes listed at the top of the array and skip the rest.
extensions: [The '*'.'.js'.'.jsx'.'.less'.'.css'].
},
// Entry configuration
entry: {
bundle: config.entry,
vendor: ['react'.'react-dom'.'react-router-dom'].
},
// Output configuration
output: {
filename: '[name]-[hash:8].js'.
// chunkFilename: '[name]-[chunkhash:8].js'.
path: config.path,
},
module: {
// Parser configuration
rules: [
{
test: /\.(js|jsx)$/,
use: {
loader: 'babel-loader'.
options: {
presets: [
[
'@babel/preset-env'.
{
targets: {
// Preset -env is not required if the version is larger than the relevant browser version
edge: '17'.
firefox: '60'.
chrome: '67'.
safari: '11.1'.
},
corejs: '3', // Declare the corejs version, which provides support for new es6+ syntax and features
// Import methods according to the ES6+ syntax used in the code logic, not all
useBuiltIns: 'usage'// useBuiltIns specifies whether to enable automatic support for polyfill, which automatically adds the poly-fill required for each file.
},
].
'@babel/preset-react'.
].
plugins: ['@babel/proposal-class-properties'], // Resolve Supportfor the experimental syntax 'classProperties' isn't currently enabled
},
},
exclude: /node_modules/,
},
{
test: /\.(css|less)$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
// Enable hot updates only in development mode
hmr: process.env.NODE_ENV === 'development',
// If module hot update does not work, reload all styles
reloadAll: true,
},
},
'css-loader',
{
loader: 'postcss-loader',
options: {
postcssOptions: {
ident: 'postcss', // specify which add-ons are used for postCSS
plugins: [
// The plugin here is only for PostCSS
require('autoprefixer')(), // to introduce the prefixed plug-in, the second empty parenthesis is to execute the plug-in
].
},
},
},
'less-loader',
].
},
{
test: /\.(png|jpe? g|gif|svg)(\? . *)? $/,
use: [
{
loader: 'url-loader',
options: {
Limit: 100, // If the value does not exceed 100 bytes, it is converted to Base64 bits
name: 'assets/img/[name].[ext]', // Image output path
},
},
].
},
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\? . *)? $/,
use: [
{
loader: 'url-loader',
options: {
limit: 10000,
name: 'assets/blob/[name].[ext]', // Audio/video output path
},
},
].
},
{
test: /\.(woff2? |eot|ttf|otf)(\? . *)? $/,
use: [
{
loader: 'url-loader',
options: {
limit: 10000,
name: 'assets/font/[name].[ext]', // font output path
},
},
].
},
].
},
// Plug-in configuration
plugins: [
new HtmlWebpackPlugin({
template: config.template,
Inject: true, // The inject option has four values: true,body(script tag at the bottom of body),head,false(do not insert JS file)
filename: 'index.html',
minify: {
HTML / / compression
RemoveComments: true, // removeComments
CollapseWhitespace: true, // Remove whitespace
},
}),
new MiniCssExtractPlugin({
filename: process.env.NODE_ENV === 'development'? 'assets/style.css':'assets/style.[hash:8].css', // configure the style file output path
}),
].
};
module.exports = webpackConfig;
Copy the code
- Plug-ins included with @babel/preset-env will support all the latest JS features (ES2015,ES2016, etc., excluding the stage stage) and turn them into ES5 code without any configuration. For example, if the code uses new Optional Chaining or Nullish coalescing Operator that is still in the stage, configure @babel/ PRESET -env, The conversion throws an error and requires an additional plug-in.
- After babel7.4, @babel/polyfill is officially not recommended, and core-js@3 is used instead
- When configuring filename, the MiniCssExtractPlugin differentiates the name of the style file between the development environment and the production environment. The reason is that in the development environment, if the name of the style file is not fixed, the style cannot be updated automatically
- Import img from ‘./image.png’. Import CSS styles, for example, backgorund: URL (‘./image.png’).
2. Add the dev environment configuration file based on the basic configuration
const webpack = require('webpack');
const merge = require('webpack-merge');
// const CopyWebpackPlugin = require('copy-webpack-plugin');
const baseConfig = require('./webpack.config');
const config = require('.. /config');
const devConfig = merge(baseConfig, {
mode: 'development'.
devtool: 'inline-source-map'.
devServer: {
hot: true, // hotOnly after modificationcommandAfter +s, the page is not refreshed, but needs to be refreshed manually
inline: true.
disableHostCheck: true.
contentBase: config.path,
compress: true.
host: 'localhost'.
port: 8080,
overlay: true.
publicPath: config.pubicPath,
proxy: {
'/api': {
target: 'http://xxx.meituan.com'.
changeOrigin: true.
},
},
},
output: {
publicPath: '/'.
},
plugins: [
new webpack.HotModuleReplacementPlugin()
// new CopyWebpackPlugin([
/ / {
// from: path.resolve(__dirname, '.. /static'),
// to: config.staticSubDirectory,
// ignore: ['*'].
// },
// ]),
].
});
module.exports = devConfig;
Copy the code
- After hotOnly is modified, the page is not refreshed after command+s is executed. You need to manually refresh the page
- When mode is development, NamedModulesPlugin, NamedChunksPlugin, and DefinePlugin configurations can be omitted
- In the development environment, you can always use webpack-dev-server for hot updates. As you can see from the above configuration, hot updates are already in effect, but each change reloads the entire page instead of local updates. The solution is to add the following code at the entrance:
It is very important
) :
if (module.hot) {
Module.hot.accept (App, () => {//App represents the DOM that needs hot updates
render(App);
});
}
Copy the code
The 5.x version of Wepback has been released, but I tried the hot update of 5.x version and it didn't work, so I haven't found a solution yet
3. Add the PROD environment configuration file based on the basic configuration
const merge = require('webpack-merge');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const TerserWebpackPlugin = require('terser-webpack-plugin');
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
// const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const baseConfig = require('./webpack.config');
const config = require('.. /config');
module.exports = merge(baseConfig, {
mode: 'production'.
output: {
publicPath: config.pubicPath,
},
plugins: [
new CleanWebpackPlugin(),
// New BundleAnalyzerPlugin(), // after the package is finished, a service is started to view the size of the package and the package contents in the browser
].
optimization: {
minimizer: [
/ / js compressed
new TerserWebpackPlugin({
parallel: true.
exclude: /\/node_modules/,
extractComments: false// If this option istrueAn xxx.js.license. TXT file is generated to store comments in a specific format
terserOptions: {
warnings: false.
compress: {
unused: true.
drop_debugger: true// Delete the debugger
drop_console: true// Delete console
},
},
}),
/ / CSS compression
new OptimizeCssAssetsPlugin({
cssProcessorOptions: { safe: true, discardComments: { removeAll: true}},
}),
].
},
});
Copy the code
- Mode of production can be omitted when NoEmitOnErrorsPlugin, DefinePlugin, TerserPlugin, ModuleConcatenationPlugin configuration
Start the command
"scripts": {
"start": "NODE_ENV=development webpack-dev-server --inline --config webpack.dev.js".
"build": "NODE_ENV=production webpack --config webpack.prod.js".
}
Copy the code
You may refer to detailed code https://github.com/XUGAOBO/webpack-demo