# webpack4(三) webpack实战配置
# library的打包
我们如果想要打包生成一个库文件,那么还需要再进行一些配置。
在webpack.config.js中
module.exports = {
//...
mode: 'production',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'library.js',
externals: 'lodash',// 在打包时不引入库文件,在业务代码使用的时候再在业务代码里引入
library: 'library', // 将library库挂载在library上,使用全局变量library就可以拿到库内容,这样在使用<script></script>标签时就可以通过全局变量library拿到库
libraryTarget: 'umd', // umd 支持各种引入模式 import require
}
//...
}
2
3
4
5
6
7
8
9
10
11
12
13
# PWA的打包
Progressive Web Application
在生产环境下运行时,如果服务器挂掉,那么页面就访问不到了,PWA目的在于当第一次浏览页面后,在本地有缓存,当服务器挂掉后,依旧可以使用本地缓存看到页面。
npm install workbox-webpack-plugin --save-dev
在生产环境下才需要PWA,修改webpack.prod.js
const WorkboxWebpackPlugin = require('workbox-webpack-plugin');
const prodConfig = {
//....
plugins: [
new WorkboxWebpackPlugin.GenerateSW({
clientsClaim: true,
skipWaiting: true
})
],
//...
}
2
3
4
5
6
7
8
9
10
11
12
然后在我们的业务代码里添加一些东西,这样就可以使用PWA了。只是简单的使用,还有很多东西,需要再做了解。
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/service-worker.js').then(registration => {
console.log('service-worker registed');
}).catch(error => {
console.log('service-worker register error');
})
})
}
2
3
4
5
6
7
8
9
# typescript的打包配置
首先安装 typescript 和 ts-loader
npm install typescript ts-loader --save-dev
在webpack.config.js中进行配置. 入口文件为 index.tsx 对tsx文件进行loader处理
module.exports = {
// ...
entry: './src/index.tsx',
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/
}
]
},
// ....
}
2
3
4
5
6
7
8
9
10
11
12
13
14
光配置loader还不能使用,接下来还需要在根目录创建一个 tsconfig.json
{
"compilerOptions": {
"outDir": "./dist", // 打包到dist文件夹下
"module": "es6", // 允许使用es6的引入 import
"target": "es5", // 打包成es5代码
"allowJs": true // 允许引入js文件
}
}
2
3
4
5
6
7
8
在引入其他第三方库时,如lodash等,ts无法继续为我们对其进行代码检测,这时我们需要对其进行配置,来使用ts对其进行检测
npm install @types/lodash --save-dev
这样在使用lodash库时如果没有按规则使用的话,ts会提示报错。
# 使用webpackDevServer实现请求转发
在开发环境下使用 webpackDevServer 进行代理转发 配置proxy
module.exports = {
//...
devServer:{
//...
proxy: {
// 将/react/api下的接口进行代理
'/react/api': {
target: 'http://www.dell-lee.com', // 代理到这个地址上
pathRewrite: {
'header.json': 'demo.json' // 可以不用改变业务代码,直接代理到demo.js上
},
headers: {
host: 'www.dell-lee.com' // 可以在请求头上添加一些东西
}
}
}
},
//...
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# EsLint 在webpack中的配置
npm install eslint eslint-loader --save-dev
npm install babel-eslint --save-dev
生成eslint配置文件
npx eslint --init
然后在webpack中配置一下,添加eslint-loader
module.exports = {
entry: {
"main": './src/index.js'
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: ["babel-loader", "eslint-loader"]
},
]
},
}
2
3
4
5
6
7
8
9
10
11
12
13
14
# webpack 性能提升————提升打包速度
- 跟上技术的迭代(node, npm , yarm)
- 在尽可能少的模块上的应用loader
- plugin尽可能精简并确保可靠
- resolve参数合理配置
- 使用DllPlugin提高打包速度
创建webpack.dll.js,通过命令在dll文件夹下将用到的库文件单独打包出来,并使用library将打包的vendors挂在全局。 也可以分开打成多个包挂在全局
webpack.dll.js
const path = require('path');
const webpack = require('webpack');
module.exports = {
mode: 'production',
entry: {
vendors: ['react', 'react-dom', 'lodash'] // 也可以打成多个包
},
output: {
filename: '[name].dll.js',
path: path.resolve(__dirname, '../dll'),
library: '[name]'// 挂在全局
},
plugins: [
new webpack.DllPlugin({
name: '[name]',
path: path.resolve(__dirname, '../dll/[name].manifest.json'),
})
]
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
在package.json中添加生成dll文件热键命令
{
//...
"scripts": {
//...
"build:dll": "webpack --config ./scripts/webpack.dll.js"
}
//...
}
2
3
4
5
6
7
8
9
安装add-asset-html-webpack-plugin插件
npm install add-asset-html-webpack-plugin --save-dev
在webpack.common.js中添加两个插件
module.exports = {
//...
plugins: [
//...
new AddAssetHtmlWebpackPlugin({
filepath: path.resolve(__dirname, '../dll/vendors.dll.js')// 将打包的静态资源挂在html上
}),
new webpack.DllReferencePlugin({
manifest: path.resolve(__dirname, '../dll/vendors.manifest.json')// 将打包成的全局变量跟文件内引用的第三方库形成映射
})
],
//...
}
2
3
4
5
6
7
8
9
10
11
12
13
此时,先运行 npm run build:dev 生成所有dll文件 然后再运行启动服务或者打包,降低了多次查找打包第三方库的时间
但是如果我们要拆分多个库,那岂不是要每加一个库我们都要在webpack.common.js中手动添加一个plugin? 所有我们使用node进行一个自动添加的工作。
在webpack.common.js中
var webpack = require('webpack');
var AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin');
var fs = require('fs');
// 定义一个plugins数组,先将之前用的插件添加进去
var plugins = [
new HtmlWebpackPlugin({
template: 'src/index.html'
}), // 打包后在html中自动插入js
new CleanWebpackPlugin(),// 每次打包之前清除文件
new webpack.ProvidePlugin({
_: 'lodash'// 垫片,在遇到"_"时,就会自动加载lodash库
})
];
// 用node获取所有dll生成的第三方库
const files = fs.readdirSync(path.resolve(__dirname, '../dll'));
// 循环判断file的后缀,根据.dll.js 和 .manifest.json 将所有dll库分别动态加载到plugins中
files.forEach(file => {
// 找到所有 .dll.js 结尾文件添加,使用插件挂载在html上
if (/.*\.dll.js/.test(file)) {
plugins.push(new AddAssetHtmlWebpackPlugin({
filepath: path.resolve(__dirname, '../dll', file)
}))
}
// 找到所有 .manifest.json 结尾文件添加,使用插件将其映射与全局挂载的变量对应
if (/.*\.manifest.json/.test(file)) {
plugins.push(new webpack.DllReferencePlugin({
manifest: path.resolve(__dirname, '../dll', file)
}))
}
})
// 再将plugins数组传给plugins
module.exports = {
//...
plugins,
//.....
}
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
这样,我们只需要在 webpack.dll.js 中添加想要加入到dll中的库,分别进行打包,在文件中引用时就会先到dll中进行查找,如果dll中已经打包过此第三方库,那么再打包的时候就不会再去对其进行打包。
webpack.dll.js
const path = require('path');
const webpack = require('webpack');
module.exports = {
mode: 'production',
entry: {
vendors: ['lodash'],// 将不同的第三方库分开来打包
react: ['react', 'react-dom'], // 将不同的第三方库分开来打包
redux: ['redux'], // 将不同的第三方库分开来打包
},
output: {
filename: '[name].dll.js',
path: path.resolve(__dirname, '../dll'),
library: '[name]',
},
plugins: [
new webpack.DllPlugin({
name: '[name]',
path: path.resolve(__dirname, '../dll/[name].manifest.json'),
})
]
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
控制包文件大小
thread-loader, parallel-webpack, happypack 多进程打包
合理使用sourceMap
结合stats分析打包结果
开发环境内存编译
开发环境无用插件剔除
# 多页面打包配置
本质上其实是在entry中添加多个入口文件,再在plugins插件中多添加几个 HtmlWebpackPlugin 插件
module.exports = {
entry: {
"index" : {
}
},
//...
plugins: [
new HtmlWebpackPlugin({
template: 'src/index.html', // html模板位置
filename: 'index.html', // 生成的html文件
chunks: ['runtime', 'vendors', 'main'] // 需要挂在html上的js文件
}),
new HtmlWebpackPlugin({
template: 'src/index.html', // html模板位置
filename: 'list.html', // 生成的html文件
chunks: ['runtime', 'vendors', 'list'] // 需要挂在html上的js文件
}),
new HtmlWebpackPlugin({
template: 'src/index.html', // html模板位置
filename: 'test.html', // 生成的html文件
chunks: ['runtime', 'vendors', 'test'] // 需要挂在html上的js文件
}),
//....
]
}
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
最后我们再对这段配置进行做自动化设计
webpack.common.js
const path = require('path');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var { CleanWebpackPlugin } = require('clean-webpack-plugin');
var webpack = require('webpack');
var AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin');
var fs = require('fs');
//创建一个函数来动态创建加载插件
const makePugins = configs => {
let plugins = [
new CleanWebpackPlugin(),// 每次打包之前清除文件
new webpack.ProvidePlugin({
_: 'lodash'// 垫片,在遇到"_"时,就会自动加载lodash库
})
];
// 通过判断入口文件的个数名称,来动态添加 HtmlWebpackPlugin 插件
Object.keys(configs.entry).forEach(item => {
plugins.push(new HtmlWebpackPlugin({
template: 'src/index.html', // html模板位置
filename: `${item}.html`, // 生成的html文件
chunks: ['runtime', 'vendors', item] // 需要挂在html上的js文件
}))
})
// 获取所有dll生成的第三方库
const files = fs.readdirSync(path.resolve(__dirname, '../dll'));
// 循环将所有dll库动态加载到plugins中
files.forEach(file => {
if (/.*\.dll.js/.test(file)) {
plugins.push(new AddAssetHtmlWebpackPlugin({
filepath: path.resolve(__dirname, '../dll', file)
}))
}
if (/.*\.manifest.json/.test(file)) {
plugins.push(new webpack.DllReferencePlugin({
manifest: path.resolve(__dirname, '../dll', file)
}))
}
})
return plugins;
}
// 将配置项放在对象中保存
const config = {
entry: {
"main": './src/index.js',
"list": './src/list.js'
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader",
},
{
test: /\.(jpg|png|gif)$/,
use: {
loader: 'url-loader',
options: {
name: '[name].[ext]',
outputPath:'images/',
limit: 1024// 图片大小小于限制的时候直接打包到js里,大于的话生成到images/下
// 其他用法和file-loader基本一样
}
},
}
]
},
performance: false,
optimization: {
splitChunks: {
chunks: 'async',
minSize: 30000,
maxSize: 0,
minChunks: 1,
maxAsyncRequests: 5,
maxInitialRequests: 3,
automaticNameDelimiter: '~',
automaticNameMaxLength: 30,
name: true,
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true
}
}
}
},
output: {
path: path.resolve(__dirname, '../dist')
},
}
// 调用函数生成plugins
config.plugins = makePugins(config);
// 导出
module.exports = config;
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