At this point the Webpack version is V4.42.0.
introduce
Gitee has been uploaded to demo during learning, click the jump address
Why use
Front-end web features are rich, especially with the popularity of SPA technology, packaging: JavaScript has increased in complexity and requires a lot of dependency packages
Conversion compilation: Sass, LESS, ES6/ES7, etc
Optimization: When pages are complex, performance can be a problem, and WebPack can be optimized as well
The principle of
The installation
NPM install -g webpackCopy the code
// Initialize NPM initCopy the code
// install webpack NPM install --save-dev webpack webpack-dev-server webpack-cliCopy the code
use
Single file entry
// create webpack.base.js in the root directory
const path = require('path');
module.exports = {
entry: './src/index.js'.output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',}};Copy the code
// Package the NPM run buildCopy the code
Multifile entry
const path = require('path');
module.exports = {
entry: {
entry: './src/index.js'.second: './src/second.js',},output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js'.publicPath: 'static',},// chunkFilename: '',
};
Copy the code
Dist /entry.js dist/second.jsCopy the code
Configuration items
mode
Tell Webpack to use the built-in optimizations for the corresponding pattern.
Production: Pay attention to module size (default) and compress scripts
Development: debugging, hot update
Webpack generates a process.env.node_env variable based on mode, which is a global variable defined in webpack.definedPlugin and allows different code to be executed depending on the environment, for example:
if (process.env.NODE_ENV==='development') {
// Development environment execution
} else {
// Production environment execution
}
Copy the code
In the production environment,uglify will automatically delete unreachable code when packaging the code, that is to say, the final code compressed in the production environment is:
// Production environment executionCopy the code
Hot update HMR
In a development environment, we need to debug the code quickly, so we need the local server to access static files packed with Webpack
Advantages:
- Preserve application state that is lost when the page is fully reloaded
- Only update changes to save time
- Adjusting styles is faster, almost as fast as changing styles in the browser debugger
After listening, hot updates do not generate the actual package file, just live in memory, no disk IO, and faster
Webpack-dev-server is an official tool provided by Webpack. When mode is in development, you can enable hot update and preview the modified code in real time.
First we have webpack-dev-server installed, next we need to configure scripts in package.json,
scripts: {
dev: 'webpack-dev-server --mode development --config webpack.base.js',}Copy the code
// webpack.base.js
const path = require('path');
const distSrc = path.resolve(__dirname, '.. /dist');
module.exports = {
entry: {
entry: path.resolve(__dirname, '.. /src/index.js'),
second: path.resolve(__dirname, '.. /src/second.js'),},output: {
path: distSrc,
filename: '[name].js',},devServer: {
contentBase: distSrc,
port: '9091'.// Local access port number
compress: true.// Whether to enable compression
hot: true.// Enable hot update}};Copy the code
devServer
Common parameters:
host - default:'localhost'
Hot – Starts hot updates
HotOnly – Hot updates are enabled only for modules that contain HMR
How does HMR work?
In the application,
In the editor,
In a module, if the HMR interface is implemented in the module and updates are received to the HMR, the update replaces the old one. However, not all modules require an HMR interface, and when a module does not implement an HMR interface, its updates bubble, meaning that a simple handler can update the entire module tree.
In such modules, a single module updates and the entire dependency block is reloaded.
In the HMR Runtime
loader
Loader is used to convert source code. You can convert different languages to JavaScript. You can preprocess imports or preprocess files while loading modules. Loader can convert inline images to data urls and even import CSS files directly from JavaScript,
Loader parameters:
Test: the extension of the matching processing file
Use: Loader name, the name of the module to be used
Include /exclude: Adds mandatory files or excludes unnecessary files
Query: Provides additional setup options for loaders.
css-loader
: The css-loader
interprets @import
and url()
like import/require()
and will resolve them.
The main purpose is to handle dependencies in CSS, such as @import and URL () declarations that refer to external files
style-loader
: Inject CSS into the DOM.
The result of csS-loader parsing is converted into JS code, and the runtime inserts style tags dynamically to make the CSS code work.
Url-loader /file-loader: used to process JPG, PNG, and GIF files
Sass-loader node-sass parses SCSS files
module: {
rules: [{test: /\.(css|less)$/.use: [{loader: 'style-loader'
},
{
loader: 'css-loader'.options: {
importLoaders: 1,}}, {loader: 'postcss-loader'.options: {
ident: 'postcss'.plugins: (loader) = > [
require('postcss-import') ({root: loader.resourcePath }),
require('postcss-cssnext') (the),require('autoprefixer') (the),require('cssnano')(),],},}, {loader: 'less-loader'.options: {
importLoaders: 1,},},],}, {test: /\.(png|jpg|gif)/.use: {
loader: 'url-loader'.options: {
limit: 1024.fallback: {
loader: 'file-loader'.options: {
name: 'img/[name].[hash:8].[ext]',},},},},},},Copy the code
or
rules: [
{ test: ' '.use: ' '}].Copy the code
babel
The current version of the browser does not support es6/ ES7 syntax, you need to switch to ES5 syntax.
After packing:
NPM install -d babel-loader @babel/ core-babel /preset-env NPM install -d babel-loader @babel/ core-babel /preset-envCopy the code
Babel-polyfill is introduced and needs to be used in production environments
npm intall --save babel-polyfill
Copy the code
Not the introduction of Babel – polyfill
After the introduction of
Entry.js is obviously a lot bigger because babel-Polyfill pollutes the global environment by adding promises as global variables. The plugin-transform-Runtime is required
Advantages:
Does not pollute the global variable multiple use will only be packaged once dependency unified introduction on demand, no repeated introduction, no redundant introductionCopy the code
{
test: /\.js$/.use: {
loader: 'babel-loader'.options: {
presets: ['@babel/preset-env'].plugins: ['@babel/plugin-transform-runtime'],}}},Copy the code
// error
Uncaught TypeError: Cannot assign to read only property 'exports' of object '#<Object>'
Copy the code
When you use @babel/ plugin-transform-Runtime in a commonJS file, Babel assumes that the file is an ES6 file and imports the plugin using import. This led to the error of mixing import and module.exports. The solution is to configure unambiguous Settings in babel.config.js so that Babel, like WebPack, strictly differentiates commonJS files from ES6 files.
{
test: /\.js$/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
plugins: ['@babel/plugin-transform-runtime'].sourceType: 'unambiguous',}}},Copy the code
plugin
In the webpack build process, plugin users handle more other build tasks, loader is used to convert languages, better compatibility.
Block, compress, optimize
Since webPack was upgraded to 4, it boasts zero configuration. The code will automatically split, compress, and optimize, and Webpack will automatically Scope and tree-shaking you as well.
When multiple bundles share the same dependencies, these dependencies need to be extracted into the shared bundle to avoid repeated packaging. CommonsChunkPlugin in webpack4.0 were removed, replaced by optimization. The splitChunks and optimization. The runtimeChunk
Built-in code separation strategy:
Whether the new chunk is shared or from the node_modules module
Whether the new chunk size is greater than 30KB before compression
The number of concurrent requests for loading chunk on demand is less than or equal to 5
The number of concurrent requests during initial page loading is less than or equal to 3
Chunk analysis plug-in
npm install --save-dev webpack-bundle-analyzer
Copy the code
// vue.config.js or webpack.base.js
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
plugins: [
new BundleAnalyzerPlugin({
analyzerMode: 'server'.// analyzerHost: '127.0.0.1',
analyzerPort: 7777.reportFilename: 'index.html'.defaultSizes: 'parsed'.openAnalyzer: true.generateStatsFile: false.statsFilename: 'stats.json'.statsOptions: null.logLevel: 'info',})],Copy the code
// package.json
scripts: {
"analyze": "NODE_ENV=production npm_config_report=true npm run build"
},
Copy the code
DefinePlugin
Allows you to create a global variable that can be used at compile time.
The separation of CSS
mini-css-extract-plugin
npm install --save-dev mini-css-extract-plugin
Copy the code
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
output: {
filename: '[name].js'.// fix img path in HTML
publicPath: 'http://localhost:9091',},plugins: [
new MiniCssExtractPlugin({
filename: 'css/[name].js'.chunkFilename: '[id].css',})],module: {
rules: [{test: /\.(css|less)$/.use: [
MiniCssExtractPlugin.loader,
css-loader,
less-loader,
],
}
],
}
Copy the code
Images introduced in HTML:
Images introduced in CSS:
Automatically adds CSS property prefixes
Prefixes the CSS with autoprefixer. Previously, when writing to csS-Loader, you added the PostCSS-Loader for CSS, which includes the autoprefixer plug-in
rules: [
{
test: /\.(css|less)$/.use: [
MiniCssExtractPlugin.loader,
'css-loader'.'post-loader',]}],Copy the code
// Add the file postcss.config.js to the root directory
module.exports = {
plugins: {
autoprefixer: {},}};Copy the code
// Add the file.browserslistrc to the root directory (recommended)
> 1%
last 2 versions
not ie <= 8
// Add it to package.json (not recommended)
"browserslist": [
"last 1 version"."1%" >."IE 10"
]
Copy the code
Ignore module packaging
IgnorePlugin: Ignores specific modules so that WebPack does not pack them.
module.exports = {
// ...
plugins: [
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/)
]
}
Copy the code
The IgnorePlugin configuration takes two parameters. The first is a regular expression that matches the path of the incoming module, and the second is the name of the directory in which the module resides.
Ignore the package module configuration in vue-CLI:
module.exports = {
chainWebpack: (config) = > {
config.externals({
'element-ui': 'ElEMENT'.'moment': 'moment',})}};Copy the code
These ignored unpackaged files can be imported as script.
<script src="< % = BASE_URL % > [email protected]"></script>
<script src="< % = BASE_URL % > [email protected]"></script>
Copy the code
Split code file
In order to reduce the size of packaged code and use caching to speed up static resource access, it is necessary to separate different and non-affecting code blocks. Plugin says that mini-CSS-extract-plugin can be used to separate CSS files. In addition, It is recommended that publicly used third-party class libraries be explicitly configured as public parts. Because in the actual development of third-party libraries, there is little change, which can avoid cache invalidation due to frequent changes in the public chunk.
Hash: All files with the same hash value will be regenerated regardless of whether the file is modified
Chunkhash: resolves dependent files according to different entry files, constructs corresponding chunks, generates corresponding hash, and does not need to rebuild without changing the code.
Contenthash: Since CSS and JS use the same chunkhash, CSS will be regenerated when only JS is changed. So CSS uses contenthash
module.exports = {
entry: {
vendor: ["react"."lodash"."angular". ] .// Specify a third-party library for public use
},
optimization: {
splitChunks: {
cacheGroups: {
vendor: {
chunks: "initial".test: "vendor".name: "vendor".// Use the vendor entry as the public part
enforce: true,},},},},/ /... Other configuration
}
/ / or
module.exports = {
optimization: {
splitChunks: {
cacheGroups: {
vendor: {
test: /react|angluar|lodash/.// Use test directly to do path matching
chunks: "initial".name: "vendor".enforce: true,},},},},}/ / or
module.exports = {
optimization: {
splitChunks: {
cacheGroups: {
vendor: {
chunks: "initial".test: path.resolve(__dirname, "node_modules") // paths in node_modules are public parts
name: "vendor".// Use the vendor entry as the public part
enforce: true,},},},},}...Copy the code
Vue – in cli vue. Config. Js
module.exports = {
chainWebpack: (config) = > {
config.optimization.splitChunks(Object.assign({}, splitOptions, {
name: false.cacheGroups: {
default: false.vendors: {
name: 'chunk-vendors'.test: /[\\/]node_modules|plat-utils[\\/]/.minChunks: 2.priority: 11.chunks: 'all'.reuseExistingChunk: true,},betterScroll: {
test: /[\\/]node_modules[\\/]better-scroll[\\/]/.name: 'better-scroll'.priority: 12.chunks: 'all'.reuseExistingChunk: true.enforce: true,},vueRouter: {
test: /[\\/]node_modules[\\/]vue-router[\\/]/.name: 'vue-router'.enforce: true.priority: 12.chunks: 'all'.reuseExistingChunk: true,},vueLazyload: {
test: /[\\/]node_modules[\\/]vue-lazyload[\\/]/.name: 'vueLazyload'.enforce: true.priority: 12.chunks: 'all'.reuseExistingChunk: true,}}})); }};Copy the code
resolve.alias
module.exports = {
resolve: {
alias: {
utils: path.resolve(__dirname, 'src/utils'),}}};Copy the code
References:
// The original reference
import cookie from './utils/cookie';
/ / alias
import cookit form 'utils/cookie';
Copy the code
Vue – in cli vue. Config. Js
module.exports = {
configureWebpack: {
resolve: {
alias: {
'utils': path.resolve('utils'), // Configure the alias}},},chainWebpack: (config) = > {
config.resolve.alias.set('utils', path.resolve(__dirname, 'src/components')); }};Copy the code
Reference:
Webpackage 4.0 from Scratch
Webpack3.X: The Path to God (24 episodes)
Webpack Chinese Document
Webpack official website
The notes are recorded before, and I am reviewing them recently. By the way, I will send them below. Welcome to correct them if there is any wrong understanding.
Optimization problem
To be updated