0%

webpack-note

1 .Webpack是什么?

Webpack是一种前端构建工具,一个静态模块的打包器(module bundler)。在Webpack看来,前端的所有资源文件(js/json/css/less/…)都会作为模块处理。它将根据模块的依赖关系进行静态分析,打包生成对应资源文件(bundle)

webpack

2.Webpack五个核心概念

2.1Entry

入口(Entry)指示Webpack以哪个文件为入口起点开始打包,分析构建内部以来图

2.2Output

输出(Outout)指示Webpack打包后的资源bundles输出到哪里去,以及如何命名。

2.3Loader

Loader让Webpack能够去处理那些非javaScript文件(Webpack自身只能理解JavaScript)

2.4Plugins

插件(Plugins)可以用于执行范围更广的任务,插件的范围包括,从打包优化和压缩,一直到重新定义环境中的变量等。

2.5Mode

模式(Mode)指示Webpack使用相应模式的配置

选项 描述 特点
development 会将process.env.NODE_ENV的值设为development。启用NameChunksPlugin和NamedModulesPlugin 能让代码本地调试运行环境
pproduction 会将process.env.NODE_ENV的值设为production,启用FlagDependencyUsagePluin,FlagIncludedChunksPlugin,ModuleConcatenationPlugin,NoEmitOnErrorsPlugin,OccurrenceOrderPlugin,SideEffectsFlagPlugin和UglifyJsPlugin。 能让代码优化上线运行环境

tip:webpack最新版本是与webpack-dev-server是版本不兼容的建议使用时,选择

1
2
3
>"webpack": "^4.41.6",
>"webpack-cli": "^3.3.11",
>"webpack-dev-server": "^3.10.3"

2.6webpack.config.js(开发环境):

1
2
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
/*
webpack.config.js webpack的配置文件
作用 : 指示webpack去干哪些活(当你运行webpack指令时,会加载里面的配置)
所有构建工具都是基于node.js平台运行的~模块化默认采用commonjs。

loader:1.下载 2.使用(配置loader)
plugins: 1.下载 2.引入 3.使用
*/
// resolve用来拼接绝对路径的方法
const {resolve} = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

// 设置nodejs环境变量
process.env.NODE_ENV = 'development';
module.exports = {
// webpack配置
// 入口
entry: './src/index.js',
// 输出路径
output: {
// 输出文件名
filename: 'built.js',
// 输出路径
// __dirname nodejs的变量,代表当前文件的目录绝对路径
path: resolve(__dirname, 'build')
},
module: {
rules: [
// 详细loader配置,每一条rules为一个对象
// 不同资源文件必须配置不容的rules
{
// 正则表达式用于匹配哪些文件
test: /\.css$/,
// 通过test匹配获取到指定文件后通过use指定使用loader进行处理
use: [
// use数组中的loader执行顺序:从左到右,从下到上,依次执行
// 创建一个style标签,将js中的样式资源插入到标签内最后添加到页面中生效
'style-loader',
// 将css文件以字符串的形式变成commonjs模块加载到js中,里面内容是样式字符串
'css-loader'
]
},
{
test: /\.(css|less)$/,
use: [
MiniCssExtractPlugin.loader, //替换style-loader达到适配不同的浏览器
// 'style-loader',
'css-loader',
/*
css兼容性处理:postcss --> postcss-loader postcss-preset-env

帮postcss找到package.json中browserslist里面的配置,通过配置加载指定的css兼容性样式

"browserslist": {
// 开发环境 --> 设置node环境变量:process.env.NODE_ENV = development
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
],
// 生产环境:默认是看生产环境
"production": [
">0.2%",
"not dead",
"not op_mini all"
]
}
*/
// 使用loader的默认配置
// 'postcss-loader',
// 修改loader的配置
{ // 型版本的postcss-loader的使用方式有所改变
/ 将options配置单独抽离成一个postcss.config.js文件单独配置
loader: 'postcss-loader',

}
'less-loader'
]
},
{
// 排除css/js/html资源
exclude: /\.(css|less|js|html)$/,
loader: 'file-loader',
options: {
name:'[hash:10].[ext]'
}
},
// 问题:默认处理不了html中的img标签的图片
{ // 处理图片资源
// 使用一个loader
// 下载url-loader file-loader
test: /\.(png|jpg|gif)$/,
loader: 'url-loader',
options: {
// 当发现图片大小小于8kb,就会被base64处理
// 优点:减少请求数量(减轻服务器压力)
// 缺点:图片体积会变大(文件请求速度更慢)
limit: 8 * 1024,
// 问题:因为url-loader默认使用es6模块化解析,而html-loader引入图片是 common.js
// 解析:时会出现问题:[Object Module]
// 解决: 关闭url-loader的es6模块解析,使用common.js解析
esModule: false,
// 给图片重命名
// [hash:10]取图片的hash前10位
// [ext]去文件原来的扩展名
name: '[hash:10].[ext]'
}
},
{
test: /\.html$/,
// 处理html 中img标签图片(负责引入img,从而能够被url-loader进行处理)
loader: 'html-loader'
},
{
// 排除css/js/html资源
exclude: /\.(css|less|js|html)$/,
loader: 'file-loader',
options: {
name:'[hash:10].[ext]'
}
}

]
},
// plugins 的配置
plugins: [
// 每一个plugin为一个函数对象
// plugins配置
// html-webpack-plugin
// 功能:默认会创建一个空的HTML,自动引入打包输出的所有资源(js/css)
// 需求:需要有结构的HTMl文件
new HtmlWebpackPlugin({
// 复制./src/index.html创建一个HTML./src/index.html文件,并自动引入打包输出的所有资源(js/css)
template: './src/index.html'
}),
new MiniCssExtractPlugin({ //将css单独抽离成一个文件
filename: 'css/built.css'
})
],
// 模式
mode: 'development', //开发模式
// mode:'production'
};

postcss.config.js

1
2
3
4
5
6
module.exports={
plugins:[
// postcss插件
require('postcss-preset-env')()
]
}

2.7webpack.config.js(生产环境):

1
2
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
const {resolve} = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');

// 定义环境变量:决定使用 browserslist 的哪个模式配置 默认:production
process.env.NODE_ENV = 'production';
// 复用loader

module.exports = {
entry: './src/index.js',
output: {
filename: 'built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
//处理less与css
{
test: /\.(less|css)$/,
use: [
// 抽取css文件
MiniCssExtractPlugin.loader,
'css-loader',
{ // css兼容处理
loader: 'postcss-loader',
}
'less-loader'
]
},
/**
* 正常情况下,一个文件只能被一个loader处理
* 当一个文件被多个loader处理,那么一定要指定loader的执行先后顺序
* 先执行eslint 在执行babel
*/
{ //js语法检查
// 需要在package.json配置eslintConfig --->airbnb
test: /\.js$/,
exclude: /node_modules/,
enforce: 'pre', //优先执行
loader: 'eslint-loader'
options: {
fix: true //自动修复语法不规范
}
},
{ //js兼容性处理
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: { //具体规则
presets: [ //预设置
[
'@babel/preset-env' //基础语法兼容
{//按需全兼容
useBuiltIns: true,
corejs: {version: 3},
targets: { //指定兼容最低版本
chrome: '60',
fix: '50'
}
}
]
]
}
},
{ //处理图片 默认使用es模块化处理
test: /\.(png|jpg|gif)$/,
loader: 'url-loader',
options: {
limit: 8 * 1024,
name: '[hash:10].[ext]',
outputPath: 'images',
esModule: false //关闭es模块化
}
},
{//处理html中的图片 使用的是commonjs模块化处理
test: /.html$/,
loader: 'html-loader',
},
{ //将一些其他文件统一打包到指定目录
exclude: /\.(html|css|less|jpg|png|gif|js)$/,
loader: 'file-loader',
options: {
output:'media'
}
}

]
},
plugins: [
new HtmlWebpackPlugin(
{
template: './src/index.html',
// 压缩html代码
minify: {
// 移除空格
collapseWhitespace: true,
// 移除注释
removeComments: true

}
}
),
// 抽取css
new MiniCssExtractPlugin(
{filename: 'styles/index.css'}
),
// 压缩css
new OptimizeCssAssetsWebpackPlugin()

],
// 生产环境下,自动压缩js代码
mode: 'production'
};

package.json:

1
2
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
{
"name": "webpackprj",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Liyi",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.12.10",
"@babel/polyfill": "^7.12.1",
"@babel/preset-env": "^7.12.10",
"@webpack-cli/serve": "^1.1.0",
"babel-loader": "^8.2.2",
"core-js": "^3.8.1",
"css-loader": "^5.0.1",
"eslint": "^7.15.0",
"eslint-config-airbnb-base": "^14.2.1",
"eslint-loader": "^4.0.2",
"eslint-plugin-import": "^2.22.1",
"file-loader": "^6.2.0",
"html-loader": "^1.3.2",
"html-webpack-plugin": "^3.2.0",
"less": "^3.12.2",
"less-loader": "^7.1.0",
"mini-css-extract-plugin": "^1.3.2",
"optimize-css-assets-webpack-plugin": "^5.0.4",
"postcss-loader": "^4.1.0",
"postcss-preset-env": "^6.7.0",
"style-loader": "^2.0.0",
"stylus-loader": "^4.3.1",
"url-loader": "^4.1.1",
"webpack": "^4.41.6",
"webpack-cli": "^3.3.11",
"webpack-dev-server": "^3.10.3"
},
"browserslist": {
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
],
"production": [
">0.2%",
"not dead",
"not op_mini all"
]
},
"eslintConfig": {
"extends": "airbnb-base"
}
}

3.webpack性能优化(HMR功能)

  • 开发环境性能优化
  • 生产环境性能优化
    开发环境性能优化
    1.优化webpack的打包构建速度
    2.优化代码调试功能
生产环境性能优化

1.优化打包构建速度
2.优化代码运行的性能

webpack.config.js:

1
2
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148

const {resolve} = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');

// 定义环境变量:决定使用 browserslist 的哪个模式配置 默认:production
process.env.NODE_ENV = 'production';
// 复用loader

module.exports = {

entry: ['./src/index.js','./src/index.html'], //将html添加到入口中便于开启html的HMR功能
output: {
publicPath: './',
filename: 'built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
//处理less与css
{
test: /\.(less|css)$/,
use: [
// 抽取css文件
MiniCssExtractPlugin.loader,
'css-loader',
{ // css兼容处理
loader: 'postcss-loader',
},
'less-loader'
]
},
/**
* 正常情况下,一个文件只能被一个loader处理
* 当一个文件被多个loader处理,那么一定要指定loader的执行先后顺序
* 先执行eslint 在执行babel
*/
// { //js语法检查
// // 需要在package.json配置eslintConfig --->airbnb
// test: /\.js$/,
// exclude: /node_modules/,
// enforce: 'pre', //优先执行
// loader: 'eslint-loader',
// options: {
// fix: true //自动修复语法不规范
// }
// },
{ //js兼容性处理
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: { //具体规则
presets: [ //预设置
[
'@babel/preset-env', //基础语法兼容
{//按需全兼容
useBuiltIns: 'usage',
corejs: {version: 3},
targets: { //指定兼容最低版本
firefox: '60',
ie: '9',
safari: '10',
edge: '17'
}
}
]
]
}
},
{ //处理图片 默认使用es模块化处理
test: /\.(png|jpg|gif)$/,
loader: 'url-loader',
options: {
limit: 8 * 1024,
name: '[hash:10].[ext]',
outputPath: 'images',
esModule: false ,//关闭es模块化,
// 解决打包后样式资源中图片引用路径错误
publicPath:'../images',
}
},
{//处理html中的图片 使用的是commonjs模块化处理
test: /.html$/,
loader: 'html-loader',
},
{ //将一些其他文件统一打包到指定目录
exclude: /\.(html|css|less|jpg|png|gif|js)$/,
loader: 'file-loader',
options: {
output:'media'
}
}

]
},
plugins: [
new HtmlWebpackPlugin(
{
template: './src/index.html',
// 压缩html代码
minify: {
// 移除空格
collapseWhitespace: true,
// 移除注释
removeComments: true

}
}
),
// 抽取css
new MiniCssExtractPlugin(
{filename: 'styles/index.css'}
),
// 压缩css
// new OptimizeCssAssetsWebpackPlugin()

],
// 生产环境下,自动压缩js代码
mode: 'production',
devServer: {
contentBase:resolve(__dirname,'build'),
compress:true,
port:3000,
open:true,
// 开启HMR功能
// 当修改webpack配置必须重启webpack服务
hot:true
},
devtool: 'source-map'
/**
* source-map: 一种 提供源代码到构建后代码映射 技术(如果构建后代码出错了,通过映射关系追踪到源代码错误)
* [inline-|hidden-|eval-|][nosources-][cheap-[module]]source-map
* source-map 外联
* 提供错误代码准确信息和源代码的错误位置
* inline-source-map 内联
* 只生成一个内联source-map
* 提供错误代码准确信息和源代码的错误位置
* hidden-source-map 外部
* 提供错误原因,但是没有错误位置,不能追踪源码错误位置,只能提示到构建后代码的位置
* eval-source-map 内联
* 每一个文件都对生成一个内联source-map,都在eval
* nosources 外部
* cheap 外部
*
* 内联 和 外部的区别:1.外部生产了文件,内联没有 2.内联构建速度更快
*/
};

index.js:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 引入font
import '../assets/font/font-icon.css';
import '../assets/styles/index.less';
import { print } from './print';

function add(x, y) {
return x + y;
}

print();
console.log(add(1, 2));

if (module.hot) {
// 一旦module中存在hot属性,说明开启HMR功能。---->HMR功能生效
module.hot.accept('print.js', () => {
// 方法会监听 print.js文件变化,一旦发生变化,其他默模块认不会重新打包构建。
// 会执行后面的回调函数
});
}

source-map

一种 提供源代码到构建后代码映射 技术(如果构建后代码出错了,通过映射关系追踪到源代码错误)

[inline-|hidden-|eval-|][nosources-][cheap-[module]]source-map

  • source-map 外联

    提供错误代码准确信息和源代码的错误位置

  • inline-source-map 内联

    只生成一个内联source-map

    提供错误代码准确信息和源代码的错误位置

  • hidden-source-map 外部

    提供错误原因,但是没有错误位置,不能追踪源码错误位置,只能提示到构建后代码的位置

  • eval-source-map 内联

    每一个文件都对生成一个内联source-map,都在eval

    提供错误代码准确信息和源代码的错误位置

  • nosources-source-map 外部

    提供 代码准确信息,但是没有任何源码信息

  • cheap-source-map 外部

    提供错误代码准确信和源码的错误位置只能精确的行

  • cheap-module-source-map 外部

    提供错误代码准确信息和源代码的错误位置

    module会将loader的sourcemap加入

内联 和 外部的区别:1.外部生产了文件,内联没有 2.内联构建速度更快

开发环境:

速度快,调试更加友好

  • 速度快(eval->inline>cheap>….)
  • eval-cheap-source-map
  • eval-source-map
  • 调试更加友好
  • source-map
  • cheap-module-source-map
  • cheap-source-map

tip:vue.js React.js 都是默认使用cheap-source-map

生产环境:

源代码是否需要隐藏,调试是否更加友好

  • 源代码是否需要隐藏,调试是否更加友好
  • 内联会让代码体积变大,所以一般在生产环境下不使用
  • nosources-source-map 全部隐藏
  • hidden-source-map 只隐藏源代码
  • —-> source-map/cheap-module-source-map

4.oneOf

文件处理时loader只会匹配一个,解决了之前每个文件都会去一一匹配一次loader

tip:不能有两个配置文件处理同一个文件,解决方法就是将两个配置中的其中一个抽离到oneOf数组外部

1
2
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
module: {
rules: [
{
// 一下loader只会匹配一个,解决了之前每个文件都会去一一匹配一次loader
// 不能有两个配置文件处理同一个文件
oneOf: [
//处理less与css
{
test: /\.(less|css)$/,
use: [
// 抽取css文件
MiniCssExtractPlugin.loader,
'css-loader',
{ // css兼容处理
loader: 'postcss-loader',
}
'less-loader'
]
},
/**
* 正常情况下,一个文件只能被一个loader处理
* 当一个文件被多个loader处理,那么一定要指定loader的执行先后顺序
* 先执行eslint 在执行babel
*/
{ //js语法检查
// 需要在package.json配置eslintConfig --->airbnb
test: /\.js$/,
exclude: /node_modules/,
enforce: 'pre', //优先执行
loader: 'eslint-loader'
options: {
fix: true //自动修复语法不规范
}
},
{ //js兼容性处理
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: { //具体规则
presets: [ //预设置
[
'@babel/preset-env' //基础语法兼容
{//按需全兼容
useBuiltIns: 'usage',
corejs: {version: 3},
targets: { //指定兼容最低版本
chrome: '60',
fix: '50'
}
}
]
]
}
},
{ //处理图片 默认使用es模块化处理
test: /\.(png|jpg|gif)$/,
loader: 'url-loader',
options: {
limit: 8 * 1024,
name: '[hash:10].[ext]',
outputPath: 'images',
esModule: false //关闭es模块化
}
},
{//处理html中的图片 使用的是commonjs模块化处理
test: /.html$/,
loader: 'html-loader',
},
{ //将一些其他文件统一打包到指定目录
exclude: /\.(html|css|less|jpg|png|gif|js)$/,
loader: 'file-loader',
options: {
output:'media'
}
}
]
}

]
},

5.缓存

babel缓存

cacheDirectory: true

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
module.exports = {
...
module: {
rules: [
...
//js兼容性处理
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets: [
...
],
//开启babelh缓存,第二次构建时,会读取之前的缓存
cacheDirectory: true
}
}
]
}
}

文件资源缓存

  • hash:每次webpack打包都会生成一个唯一的hash值

    缺点:因为js和css同时使用一个hash值

    如果重新打包,会导致所有缓存失效。(可能我只改动了一个文件)

    1
    2
    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 = {
    ...
    output: {
    filename: 'built[hash:8].js', //js文件的命名
    path: path.resolve(__dirname, 'bulid'),
    },
    module: {
    rules: [
    ...
    //处理css中的图片文件
    {
    test: /\.(png|gif|jpe?g)$/,
    loader: "url-loader",
    options: {
    limit: 8 * 1024,
    outputPath: 'imgs/',
    name: '[name][hash:8].[ext]',//图片文件的命名
    }
    },
    ...
    ]
    },
    plugins: [
    ...
    new MiniCssExtractPlugin({
    filename: 'css/built[hash:8].css', //css文件的命名
    }),
    ...
    ]
    }
  • chunkhash:根据chunk生产hash值,如果打包来源同一个chunk,那么hash值一样

    缺点:js和css还是同一个hash值,因为css与js是在同一个入口引进,所以同属于一个chunk

    1
    2
    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 = {
    ...
    output: {
    filename: 'built[chunkhash:8].js',//js文件的命名
    path: path.resolve(__dirname, 'bulid'),
    },
    module: {
    rules: [
    ...
    //处理css中的图片文件
    {
    test: /\.(png|gif|jpe?g)$/,
    loader: "url-loader",
    options: {
    limit: 8 * 1024,
    outputPath: 'imgs/',
    name: '[name][hash].[ext]',//图片文件的命名,图片无法用chunkhash
    }
    },
    ...
    ]
    },
    plugins: [
    ...
    new MiniCssExtractPlugin({
    filename: 'css/built[chunkhash:8].css', //css文件的命名
    }),
    ...
    ]
    }
  • contenthash:根据文件内容生成hash值,不同的文件hash值一定不一样

    1
    2
    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 = {
    ...
    output: {
    filename: 'built[contenthash:8].js', //js文件的命名
    path: path.resolve(__dirname, 'bulid'),
    },
    module: {
    rules: [
    ...
    //处理css中的图片文件
    {
    test: /\.(png|gif|jpe?g)$/,
    loader: "url-loader",
    options: {
    limit: 8 * 1024,
    outputPath: 'imgs/',
    name: '[name][contenthash:8].[ext]',//图片文件的命名
    }
    },
    ...
    ]
    },
    plugins: [
    ...
    new MiniCssExtractPlugin({
    filename: 'css/built[contenthash:8].css', //css文件的命名
    }),
    ...
    ]
    }

6.tree shaking(树摇)

tree shaking主要作用是打包项目时会将不用到的代码不打包入项目中,这样得以优化项目体积。

tip:tree shaking在版本上存在一些差异,可能会导致把引入的css文件干掉

“sideEffects”: “false” 所有代码都是没有副作用(都可以进行ree shaking)

问题:可能会把css/@babel/polyfill(副作用)文件干掉

“sideEffects”:[“*.css”] 不对css进行tree shaking

前提条件:

1.必须使用ES6模块化 2.开启production模式

主要原理:

利用ES6模块的特点:

只能作为模块顶层的语句出现

import 的模块名只能是字符串常量

import binding 是 immutable的

代码擦除:uglify阶段删除无用代码

使用方法很简单,webpack配置中的wbpack.prod.js中只需要设置

1
mode: 'production',

就可以了,该模式下tree shaking是默认开启

7.code split(代码分割)

把代码分离到不同的 bundle 中,然后可以按需加载或并行加载这些文件。代码分离可以用于获取更小的 bundle,以及控制资源加载优先级,如果使用合理,会极大影响加载时间。

8.LazyLoding&Pre-loading(懒加载与/预加载)

1
2
3
4
5
6
7
8
9
10
11
console.log("index.js文件被加载了");
document.getElementById('btn').onclick = function () {
// 懒加载~
// 预加载:webpackPrefetch:true 会在我们使用之前,提前加入js文件(慎用)
// 正常加载可以认为是并行加载(同一时间加载多个任务)
// 预加载等其他资源加载完毕,浏览器空闲再偷偷加载之后会用到的资源
// 缺点:只在pc端的一些高版本浏览器支持,移动端浏览器不支持
import(/*webpackChunkName:'test',webpackPrefetch:true*/'./test').then(({mul, count}) => {
console.log(mul(2, 5));
})
};

9.PWA(渐进式网页应用)

使用多种技术来增强web app的功能,可以让网站的体验变得更好,能够模拟一些原生功能,比如通知推送。在移动端利用标准化框架,让网页应用呈现和原生应用相似的体验,离线也能访问应用

webpack中使用workbox-webpack-plugin实现

webpack.config.js:

1
2
3
4
5
6
7
8
9
new WorkBoxWebpackPlugin.GenerateSW({
/**
* 1.帮助serviceworker快速启动
* 2.去除旧的serviceworker
* 生产一个serviceworker配置文件
*/
clientsClaim: true,
skipWaiting: true
})

index.js:

1
2
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
import '../assets/styles/index.css';
/**
* 1.eslint 不认识window、navigator全局变量
* 解决:需要修改package.json中eslintConfig配置 加入
* "env": {
"browser": true
}
2.serviceworker代码必须运行在服务器上
-->node.js
-->
npm i serve -g
serve -s build 启动一个服务器,将build目录下的资源作为静态资源暴露出去
*/
// 注册serviceworker
// 处理兼容性问题
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/service-worker.js')
.then(() => {
// eslint-disable-next-line
console.log('serviceworker注册成功');
})
.catch(() => {
// eslint-disable-next-line
console.log('serviceworker注册失败');
});
});
}

10.多进程打包

将threed-loaer放在某一个loader后,启动多进程运作,一般在loader任务量特别大时使用

1
npm i thread-loader -D
1
2
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
33
34
{ //js兼容性处理
test: /\.js$/,
exclude: /node_modules/,
use: [{
/**
* 开启多进程打包
* 进程开启是需要时间的 600ms,进程通讯也需要花时间
* 只有工作消耗时间比较长,才需要多进程打包
*/
loader: 'thread-loader',
options: {
workers:2 //进程2个
}

}],
loader: 'babel-loader',
options: { //具体规则
presets: [ //预设置
[
'@babel/preset-env', //基础语法兼容
{//按需全兼容
useBuiltIns: 'usage',
corejs: {version: 3},
targets: { //指定兼容最低版本
firefox: '60',
ie: '9',
safari: '10',
edge: '17'
}
}
]
]
}
},

11.externals

当我们使用cdn引入一些第三库时,不需要将库打包时,便可以使用externals

webpack.config.js

1
2
3
4
externals: {
// 拒绝jQuery被打包
jquery:'jQuery'
}

12.DLL(动态链接库)

将多个库单独打包成一个chunk

使用场景:

我们可以将公司开发过程中经常会用到的一些第三库整理起来,

在每次开发之前生产一个dll,这样就省去了二次重复打包第三方库的时间

1.编写一个dll配置文件

1
2
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
/**
* 使用dll技术对某些库(第三方库:jquery、react、vue...)进行单独打包
* 当你运行webpack时,默认查找webpack.config.js
* 需求: 需要运行webpack.dll.js 文件
* --->webpack --config webpack.dll.js
* @type {{}}
*/
const {resolve} = require('path');
const webpack = require('webpack');
module.exports = {
entry: {
// 最终打包的生成的[name]--->jquery
//['jQuery']--->要打包的库时jQuery
jquery: ['jQuery']
},
output: {
filename: '[name].js',
path: resolve(__dirname, 'dll'),
library: '[name]_[hash]', //打包的库里面向外面暴露出去的内容叫什么名字
},
plugins: [
// 帮我们生产一个manifest.json--->提供jquery映射
new webpack.DllPlugin({
name: '[name]_[hash]', // 映射库的暴露的内容名称
path: resolve(__dirname, 'dll/manifest.json') //输出w文件路径
})
],
mode: 'production'
};

2.在webpack.config.js中使用

1
2
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
const {resolve} = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');
const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
filename: 'built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
// loader配置
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
}),
// 告诉webpack哪些库不参与打包,同时使用时的名称也得改变
new webpack.DllReferencePlugin({
manifest: resolve(__dirname, 'dll/manifest.json')
}),
// 将某个文件打包输出出去,并在html中自动引入
new AddAssetHtmlWebpackPlugin({
filepath:resolve(__dirname,'dll/jquery.js')
})
],
mode: 'production'
};

13.Webpack5

此版本重点关注以下内容

  • 通过持久缓存提高构建性能
  • 使用更好的算法和默认值类改善长期缓存
  • 通过更好的树摇和代码生产来改善捆绑包大小
  • 清除处于怪异状态的内部结构,同时在v4中实现功能而不引入任何重大更改
  • 通过引入重大更改来为将来的功能做准备,以使我们能够长期的使用v5

下载

  • npm i webpack@next webpack-cli -D

自动删除 Node.js Polyfills

早期,webpack 的目标是允许在浏览器中运行大多数 node.js 模块,但是模块格局发生了变化,许多模块用途现在主要是为前端目的而编写的。webpack <= 4 附带了许多 node.js 核心模块的 polyfill,一旦模块使用任何核心模块(即 crypto 模块),这些模块就会自动应用。

尽管这使使用为 node.js 编写的模块变得容易,但它会将这些巨大的 polyfill 添加到包中。在许多情况下,这些 polyfill 是不必要的。

webpack 5 会自动停止填充这些核心模块,并专注于与前端兼容的模块。

迁移:

  • 尽可能尝试使用与前端兼容的模块。
  • 可以为 node.js 核心模块手动添加一个 polyfill。错误消息将提示如何实现该目标。

Chunk 和模块 ID

添加了用于长期缓存的新算法。在生产模式下默认情况下启用这些功能。

chunkIds: "deterministic", moduleIds: "deterministic"

Chunk ID

你可以不用使用 import(/* webpackChunkName: "name" */ "module") 在开发环境来为 chunk 命名,生产环境还是有必要的

webpack 内部有 chunk 命名规则,不再是以 id(0, 1, 2)命名了

Tree Shaking

  1. webpack 现在能够处理对嵌套模块的 tree shaking
1
2
3
4
5
6
7
8
9
10
11
// inner.js
export const a = 1;
export const b = 2;

// module.js
import * as inner from './inner';
export { inner };

// user.js
import * as module from './module';
console.log(module.inner.a);

在生产环境中, inner 模块暴露的 b 会被删除

  1. webpack 现在能够多个模块之前的关系
1
2
3
4
5
6
7
8
9
import { something } from './something';

function usingSomething() {
return something;
}

export function test() {
return usingSomething();
}

当设置了"sideEffects": false时,一旦发现test方法没有使用,不但删除test,还会删除"./something"

  1. webpack 现在能处理对 Commonjs 的 tree shaking

Output

webpack 4 默认只能输出 ES5 代码

webpack 5 开始新增一个属性 output.ecmaVersion, 可以生成 ES5 和 ES6 / ES2015 代码.

如:output.ecmaVersion: 2015

SplitChunk

1
2
// webpack4
minSize: 30000;
1
2
3
4
5
// webpack5
minSize: {
javascript: 30000,
style: 50000,
}

Caching

1
2
3
4
5
6
7
8
9
// 配置缓存
cache: {
// 磁盘存储
type: "filesystem",
buildDependencies: {
// 当配置修改时,缓存失效
config: [__filename]
}
}

缓存将存储到 node_modules/.cache/webpack

监视输出文件

之前 webpack 总是在第一次构建时输出全部文件,但是监视重新构建时会只更新修改的文件。

此次更新在第一次构建时会找到输出文件看是否有变化,从而决定要不要输出全部文件。

默认值

  • entry: "./src/index.js
  • output.path: path.resolve(__dirname, "dist")
  • output.filename: "[name].js"

更多内容

https://github.com/webpack/changelog-v5

谢谢老板