webpack常用配置
 一、安装与运行
| 1
 | npm i webpack webpack-cli -D
 | 
配置文件:webpack.config.js
运行命令:配置**package.json**文件
| 12
 3
 4
 5
 
 | {"scripts": {
 "build": "webpack --config webpack.config.js"
 }
 }
 
 | 
 二、基础配置
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 
 | const {resolve} = require("path")
 module.exports = {
 mode: 'development',
 entry: resolve(__dirname, 'src/index.js'),
 output: {
 path: resolve(__dirname, 'dist'),
 filename: 'js/bundle.js',
 },
 module: { rules: [] },
 plugins: []
 }
 
 | 
 三、开发配置
 1. 处理CSS/Less/Sass
| 12
 3
 4
 5
 
 | npm i style-loader css-loader -D 
 npm i style-loader css-loader less less-loader -D
 
 npm i style-loader css-loader sass-loader sass node-sass -D
 
 | 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 
 | module.exports = {module: {
 rules: [
 {
 test: /\.css$/,
 use: [
 'style-loader',
 'css-loader'
 ]
 },
 {
 test: /\.less$/,
 use: [
 'style-loader',
 'css-loader',
 'less-loader'
 ]
 },
 {
 test: /\.scss$/,
 use: [
 'style-loader',
 'css-loader',
 'sass-loader'
 ]
 },
 ]
 }
 }
 
 | 
 2. 处理HTML
html-webpack-plugin:指定默认处理的html文件,自动引入打包后的CSS,JS,同时可以压缩打包后的html
| 1
 | npm i html-webpack-plugin -D
 | 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 
 | const HtmlWebpackPlugin = require("html-webpack-plugin")
 module.exports = {
 plugins: [
 new HtmlWebpackPlugin({
 
 template: resolve(__dirname,"public/index.html"),
 })
 ]
 }
 
 | 
 3. 图片/字体处理
| 1
 | npm i file-loader url-loader html-loader -D
 | 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 
 | module.exports = {module: {
 rules: [
 {
 test: /\.(png|svg|jpe?g|gif)$/i,
 loader: 'url-loader',
 options: {
 limit: 4096,
 name: 'img/[name].[hash:8].[ext]'
 }
 },
 {
 test: /\.html$/,
 loader: 'html-loader'
 },
 {
 test: /\.(eot|ttf|woff2?)$/,
 loader: 'file-loader',
 options: {
 name: 'fonts/[name].[hash:8].[ext]'
 }
 }
 ]
 }
 }
 
 | 
 4. 自动编译构建
 4.1 watch
自动监听并构建,需要手动刷新浏览器。
原理:轮询判断文件的最后编辑时间是否发生变化,某个文件发生变化,先缓存起来,等aggregateTimeout之后再构建。
| 12
 3
 4
 5
 6
 7
 8
 
 | module.exports = {watch: true,
 watchOptions: {
 poll: 1000,
 aggregateTimeout: 500,
 ignored: /node_modules/
 }
 }
 
 | 
 4.2 devServer
开发服务器。自动编译(只在内存中编译打包,不会有任何文件输出)、自动打开浏览器、自动刷新浏览器等功能。
| 1
 | npm i webpack-dev-server -D 
 | 
| 12
 3
 4
 5
 
 | {"script": {
 "dev": "webpack-dev-server --config webpack.config.js"
 }
 }
 
 | 
| 12
 3
 4
 5
 6
 7
 8
 9
 
 | module.exports = {devServer: {
 contentBase: resolve(__dirname, 'dist'),
 host: 'localhost',
 port: 3000,
 open: true,
 compress: true,
 }
 }
 
 | 
 四、生产配置
 1. CSS
 1.1 提取CSS到单独文件中
| 1
 | npm i mini-css-extract-plugin -D
 | 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 
 | module.exports = {module: {
 rules: [
 {
 test: /\.css$/,
 use: [
 {
 loader: MiniCssExtractPlugin.loader,
 options: {
 publicPath: '../'
 }
 },
 'css-loader'
 ]
 }
 ]
 },
 plugins: [
 new MiniCssExtractPlugin({
 filename: 'css/[name].[contenthash:8].css',
 chunkFilename: 'css/[name].[contenthash:8].css',
 }),
 ]
 }
 
 | 
 1.2 CSS兼容性处理
| 1
 | npm i postcss-loader postcss-preset-env -D
 | 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 
 | 
 
 
 module.exports = {
 module: {
 rules: [
 {
 test: /\.css$/,
 use: [
 {
 loader: MiniCssExtractPlugin.loader,
 options: {
 publicPath: '../'
 }
 },
 'css-loader',
 {
 loader: 'postcss-loader',
 options: {
 postcssOptions: {
 plugins: [ "postcss-preset-env" ]
 }
 }
 }
 ]
 }
 ]
 }
 }
 
 | 
修改package.json
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 
 | {"browserslist": {
 "development": [
 "last 1 chrome version",
 "last 1 firefox version",
 "last 1 safari version"
 ],
 "production": [
 ">0.2%",
 "not dead",
 "not op_mini all"
 ]
 }
 }
 
 | 
 1.3 CSS压缩
| 1
 | npm i optimize-css-assets-webpack-plugin -D
 | 
| 12
 3
 4
 5
 6
 7
 
 | const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')
 module.exports = {
 plugins: [
 new OptimizeCssAssetsWebpackPlugin()
 ]
 }
 
 | 
 2. JS兼容性处理
| 1
 | npm i babel-loader @babel/core @babel/preset-env -D
 | 
 2.1 兼容基础语法
两种配置方式写法相同。
 (1) 配置到babel.config.js单独文件
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 
 | 
 
 
 module.exports = {
 presets: [
 "@babel/preset-env",
 ]
 }
 
 
 
 
 
 module.exports = {
 module: {
 rules: [
 {
 test: /\.js$/,
 exclude: /node_modules/,
 loader: 'babel-loader',
 }
 ]
 }
 }
 
 | 
 (2) 配置到webpack.config.js中
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 
 | module.exports = {module: {
 rules: [
 {
 test: /\.js$/,
 exclude: /node_modules/,
 loader: 'babel-loader',
 options: {
 presets: [
 '@babel/preset-env',
 ]
 }
 }
 ]
 }
 }
 
 | 
 2.2 兼容ES6,ES7等
 (1) 全局兼容处理(polyfill)
| 1
 | npm i @babel/polyfill -D
 | 
相当于把所有不兼容的JS方法等都重新定义(打包后,体积大)。
| 12
 3
 4
 5
 
 | 
 
 
 import "@babel/polyfill"
 
 | 
 (2) 按需加载(core-js)
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 
 | 
 
 
 module.exports = {
 presets: [
 [
 "@babel/preset-env",
 {
 useBuiltIns: 'usage',
 corejs: { version: 3 },
 targets: {
 chrome: '60',
 firefox: '60',
 ie: '9',
 safari: '10',
 edge: '17'
 }
 }
 ]
 ]
 }
 
 | 
 3. JS压缩
production模式下,自动压缩
 4. HTML压缩
使用html-webpack-plugin提供的压缩功能
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 
 | module.exports = {plugins: [
 new HtmlWebpackPlugin({
 template: resolve(__dirname, 'public/index.html'),
 minify: {
 removeComments: true,
 collapseWhitespace: true,
 minifyCSS: true,
 minifyJS: true
 }
 })
 ]
 }
 
 | 
 5. 辅助插件清空构建目录
| 1
 | npm i clean-webpack-plugin -D
 | 
| 12
 3
 4
 5
 6
 7
 
 | const { CleanWebpackPlugin } = require("clean-webpack-plugin")
 module.exports = {
 plugins: [
 new CleanWebpackPlugin()
 ]
 }
 
 | 
 五、性能优化
 1. 开发优化
 1.1 HMR
HMR:一个模块发生了变化,只会重新构建这个模块,而不是所有模块,提高构建速度。
| 12
 3
 4
 5
 6
 7
 8
 
 | module.exports = {devServer: {
 hot: true
 },
 plugins: [
 new HotModuleReplacementPlugin()
 ]
 }
 
 | 
- 
样式文件:可以通过 style-loader 使用HMR 
- 
js文件:默认不能使用HMR, 可以通过module.hot 监听JS文件HMR | 12
 3
 4
 5
 6
 7
 8
 9
 
 | 
 
 
 if (module.hot) {
 module.hot.accept('./js/common.js', function () {
 test()
 })
 }
 
 |  
 
- 
html文件:默认不能使用HMR,html文件只有一个,所以不需要使用HMR 
 1.2 source-map
一个信息文件,存储着位置信息,可以定位到源代码,用于代码调试。
[inline- | hidden- | eval-][nosources-][cheap- [module-]]source-map
- inline:内联,保存在打包后的js文件中,只生成一个最终的source-map信息,构建速度快。能定位到源代码的行列。
- hidden:外部map文件。不能定位到源代码。
- eval:内联,保存在打包后的js文件中,每个模块对应一个eval包裹的source-map信息。能定位到源代码的行列。
- nosources:外部map文件。不能定位到源代码。
- cheap:外部map文件。只能定位到源代码的行。
- module:外部map文件,包含loader。只能定位到源代码的行。
- source-map:外部map文件。能定位到源代码的行列。
开发环境:eval-source-map(速度快,调试友好)
生产环境:source-map / nosources-source-map(全部隐藏) / hidden-source-map(只隐藏源代码)
 2. 生产优化
 2.1 oneOf
只会匹配一个
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 
 | module.exports = {module: {
 rules: [
 { test: /\.js$/ },
 {
 oneOf: [
 { test: /\.js$/ },
 { test: /\.css$/ },
 ]
 }
 ]
 }
 }
 
 | 
 2.2 缓存
 (1) babel-loader缓存
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 
 | module.exports = {module: {
 rules: [
 {
 test: /\.js$/,
 exclude: /node_modules/,
 loader: 'babel-loader',
 options: {
 
 cacheDirectory: true
 }
 }
 ]
 }
 }
 
 | 
 (2) 文件资源缓存(文件指纹)
- hash:和整个项目的构建有关,只要项目文件有改动,整个项目构建的hash就会变
- chunkhash:和webpack打包的chunk有关,不同的entry会生成不同的chunkhash
- contenthash:根据文件内容定义hash,内容不变,则ContentHash不变
JS设置文件指纹:[name].[chunkhash:8].js
CSS设置文件指纹:[name].[contenthash:8].css
图片/字体设置文件指纹:[name]. [hash:8].[ext]
 2.3 tree shaking
去除无用代码。
开启条件:
- 使用ES6模块化
- mode: production
在package.json中添加sideEffects: false,表示所有代码都是没有副作用的(即都可以tree shaking),此时import css文件可能会导致tree shaking。
可以指定哪些文件有副作用,如sideEffects: ['*.css']
 2.4 多进程打包
多进程打包:进程启动大概消耗600ms,进程通信也有开销,只有工作时间较长,才需要。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 
 | module.exports = {module: {
 rules: [
 {
 test: /\.js$/,
 use: [
 'thread-loader',
 'babel-loader'
 ]
 }
 ]
 }
 }
 
 | 
 2.5 code split
代码分割。
 (1) 多入口文件分割
打包后自动分割,一个entry对应一个代码文件。
| 12
 3
 4
 5
 6
 
 | module.exports = {entry: {
 index: 'src/index.js',
 test: 'src/test.js'
 }
 }
 
 | 
 (2) 分割node_modules中公共依赖
| 12
 3
 4
 5
 6
 7
 
 | module.exports = {optimization: {
 splitChunks: {
 chunks: 'all'
 }
 }
 }
 
 | 
 (3) 分割指定文件
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 
 | 
 
 
 import(
 
 'x.js'
 ).then()
 
 
 
 
 
 module.exports = {
 optimization: {
 splitChunks: {
 chunks: 'all',
 },
 runtimeChunk: {
 
 name: entrypoint => `runtime~${entrypoint.name}`
 }
 }
 }
 
 | 
 2.6 JS懒加载和预加载
正常加载:并行加载
懒加载:使用时才加载
预加载:等其他资源加载完,浏览器利用空闲时间加载资源
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 
 | 
 
 
 div.onclick = function(){
 import(
 
 'x.js'
 ).then()
 }
 
 div.onclick = function(){
 import(
 
 
 'x.js'
 ).then()
 }
 
 | 
 2.7 PWA
PWA:渐进式网络应用程序,即离线可访问。主要技术是service worker + cache。
service worker 必须运行在服务器上。
| 1
 | npm i workbox-webpack-plugin -D
 | 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | module.exports = {plugins: [
 
 
 
 new WorkboxWebpackPlugin.GenerateSW({
 skipWaiting: true,
 clientsClaim: true
 })
 ]
 }
 
 | 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 
 | 
 
 
 if ('serviceWorker' in navigator) {
 window.addEventListener('load', () => {
 navigator.serviceWorker
 .register('service-worker.js')
 .then(() => {
 console.log('sw注册成功')
 })
 .catch(() => {
 console.log('sw注册失败')
 })
 })
 }
 
 | 
 2.8 externals
当某些资源不要打包并且需要通过CDN引入时,可通过externals排除某些包
| 12
 3
 4
 5
 
 | module.exports = {externals: {
 jquery: 'jQuery'
 }
 }
 
 | 
 2.9 DLL(动态链接库)
单独打包库文件
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 
 | 
 
 
 const { resolve } = require('path')
 const webpack = require('webpack')
 
 module.exports = {
 mode: 'production',
 entry: {
 jquery: ['jquery']
 },
 output: {
 path: resolve(__dirname, 'dll'),
 filename: '[name].js',
 library: '[name]_[hash]'
 },
 plugins: [
 new webpack.DllPlugin({
 name: '[name]_[hash]',
 path: resolve(__dirname, 'dll/manifest.json')
 })
 ]
 }
 
 | 
| 12
 3
 4
 5
 
 | {"script": {
 "dll": "webpack --config webpack.dll.js"
 }
 }
 
 | 
| 1
 | npm i add-asset-html-webpack-plugin -D
 | 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 
 | 
 
 
 const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin')
 
 module.exports = {
 plugins: [
 new webpack.DllReferencePlugin({
 manifest: resolve(__dirname, 'dll/manifest.json')
 }),
 new AddAssetHtmlWebpackPlugin({
 filepath: resolve(__dirname, 'dll/jquery.js'),
 outputPath: 'libs',
 publicPath: './libs'
 })
 ]
 }
 
 | 
 六、其他配置
 1. entry
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 
 | 
 
 
 module.exports = {
 entry: 'index.js'
 }
 
 
 
 
 
 module.exports = {
 
 entry: ['index.js', 'index2.js']
 }
 
 
 
 
 
 module.exports = {
 entry: {
 index: 'index.js',
 index2: ['index2.js', 'index3.js']
 }
 }
 
 | 
 2. output
- publicPath:所有资源引入的公共路径前缀
- chunkFilename:非入口chunk的名称(code split 分割出来的文件命名)
- library:整个文件向外暴露的变量名
- libraryTarget:变量名添加到那个对象上,‘window’ | ‘global’ | ‘commonjs’…
 3. module
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 
 | module.exports = {module: {
 rules: [
 {
 test: /\./,
 use: [],
 loader: '',
 options: {},
 exclude: /node_modules/,
 include: 'src',
 enforce: 'pre' | 'post',
 oneOf: []
 }
 ]
 }
 }
 
 | 
 4. resolve
| 12
 3
 4
 5
 6
 7
 8
 9
 
 | module.exports = {resolve: {
 alias: {
 @: 'src'
 },
 extensions: ['.js'],
 modules: ['node_modules']
 }
 }
 
 | 
 5. resolveLoader
| 12
 3
 4
 5
 
 | module.exports = {resolveLoader: {
 modules: ['node_modules']
 }
 }
 
 | 
 6. devServer
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 
 | module.exports = {devServer: {
 proxy: {
 before(app) {
 app.get("/user", (req, res) => {})
 },
 "/admin": "http://localhost:3000",
 "/api": {
 target: "http://localhost:3000",
 pathRewrite: {
 "^/api": ""
 }
 }
 },
 watchContentBase: true,
 watchOptions: {
 ignored: /node_modules/
 },
 clientLogLevel: 'none',
 quiet: true,
 overlay: false,
 }
 }
 
 | 
 7. optimization
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 
 | module.exports = {optimization: {
 splitChunks: {
 chunks: 'all',
 minSize: 30 * 1024,
 maxSize: 0,
 minChunks: 1,
 cacheGroups: {
 vendors: {
 name: 'chunk-vendors',
 test: /[\\/]node_modules[\\/]/,
 priority: -10,
 chunks: 'initial'
 },
 common: {
 name: 'chunk-common',
 minChunks: 2,
 priority: -20,
 chunks: 'initial',
 reuseExistingChunk: true
 }
 }
 },
 minimizer: [
 new TerserWebpackPlugin({
 cache: true,
 paraller: true,
 sourceMa: true
 })
 ]
 }
 }
 
 |