优化思路
/**
* webpack的作用是用来对项目进行打包操作。如果要对webpack打包进行优化的话那么需要从两方面进行考虑:
* 1、优化项目的体积
* 1)、可以通过配置externals将第三方的包不打到项目中
* 2)、可以通过动态链接库的方式将第三方的包不打到项目中
* 3)、可以将大的包放在CDN上通过引入的方式,减少项目的体积
* 4)、【自带优化】tree-sharking,实现将不用的不打包到项目中。注意需要在mode="production"才生效
* 5)、【自带优化】scope-hoising,作用域提升,将一些变量直接按值的方式计算,不把定义的变量打包到项目中
* 2、优化项目的打包速度
* 1)、通过happypack,进行多线程的打包。注意需要项目比较大的情况,如果是小项目反而会慢
*/
初始化测试项目
|-- node_modules
|-- package-lock.json
|-- package.json
|-- src
| |-- index.html
| `-- main.js
`-- webpack.config.js
在操作过程之中还需要用到的依赖要下载:
npm i @babel/core @babel/preset-env babel-loader jquery --save-dev
externals配置
通过externals配置,把jquery第三方包不打包进入项目,通过CDN的方式引用jQuery。
package.json文件:
{
"name": "src",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "webpack --mode development",
"build": "webpack --mode production",
"dll": "webpack --mode development --config webpack_dll.config.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.11.6",
"@babel/preset-env": "^7.11.5",
"babel-loader": "^8.1.0",
"css-loader": "^4.2.1",
"file-loader": "^6.0.0",
"html-webpack-plugin": "^4.3.0",
"html-webpack-plugins": "^3.0.0",
"style-loader": "^1.2.1",
"url-loader": "^4.1.0",
"webpack": "^4.44.1",
"webpack-cli": "^3.3.12"
},
"dependencies": {
"jquery": "^3.5.1",
}
}
webpack.config.js文件:
const path = require('path');
module.exports = {
entry: ['./src/main.js'],
output: {
// 1.指定输出的文件的名称为 bundle.js ( 默认为main.js )
filename: 'bundle.js',
// 2. 指定输出文件存放的目录(默认是dist目录)
path: path.resolve(__dirname, './dist'), // 借助node的path模块来拼接一个绝对路径
},
module: {
rules: [
{
test: /\.js$/, // 匹配 .css 结尾的文件,注意test的值不是一个字符串,而是一个正则
exclude: /(node_modules|bower_components)/,
use: [
{
loader: 'babel-loader',
options: {
// 2.使用bable,新语法转成es5语法
presets: [
'@babel/preset-env'
]
}
}
],
}
]
},
// externals:{
// // 把导入语句里的 jQuery 替换成运行环境里的全局变量 jQuery
// jquery: "jQuery",
// }
};
main.js文件:
import $ from 'jquery'
(function(){
$('body').css({
background: 'blue'
})
})()
index.html文件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app"></div>
<!-- <script src="https://code.jquery.com/jquery-3.1.0.js"></script> -->
<script src="../dist/bundle.js"></script>
</body>
</html>
还没有使用externals配置的情况下,会把jQuery包也打包进项目的结果:
打包结果:
打包用时:1963ms
项目体积:323KiB (jQuery依赖也被打包到bundle.js中)
随后进行externals配置,分别开启 webpack.config.js和 index.html 中的注释:
externals:{
// 把导入语句里的 jQuery 替换成运行环境里的全局变量 jQuery
jquery: "jQuery",
}
<script src="https://code.jquery.com/jquery-3.1.0.js"></script>
有进行externals配置jQuery之后打包项目的结果:
打包结果:
打包用时:1546ms
项目体积:4.84KiB (jQuery依赖没有打包到bundle.js中)
很明显使用externals配置,优化webpack项目的打包体积还是非常有效果,但是也发现了一个不足之处那就是需要去用CDN。换做其他没有CDN的第三方包就不行了。
动态链接库
Webpack 已经内置了对动态链接库的支持,需要通过2个内置的插件接入,它们分别是:
- DllPlugin 插件:用于打包出一个个单独的动态链接库文件。
- DllReferencePlugin 插件:用于在主要配置文件中去引入 DllPlugin 插件打包好的动态链接库文件。
也就说直接使用不需要通过npm i 下载了!接下来在修改上面初始化的项目,将其改为动态链接库的方式。为了看到效果同样也演示有使用动态链接库和没使用动态链接库的效果,这次主要是针对 vuex 依赖。
npm i vuex // 先安装下vuex依赖
修改main.js文件:
import vuex from 'vuex'
一句话就足够了,在mode环境为development时是会能将所有有用到或者没用到的文件全部打包,所有这里即便没有使用也能被打包进去。除非设置mode为production模式,这就是上面思路中提到的 【自带优化】tree-sharking,其他文件都不变直接进行打包。
打包结果:
打包用时:4969ms
项目体积:43.8KiB (vuex依赖也被打包到bundle.js中)
开始使用动态链接库打包,在webpack.config.js同级目录下创建webpack._dll.config.js文件进行如下配置:
const path = require('path');
const DllPlugin = require('webpack/lib/DllPlugin');
module.exports = {
// JS 执行入口文件
entry: {
// 把项目需要所有的 vuex 相关的放到一个单独的动态链接库
vuex: ['vuex'], // 例如:vue: ['vue', 'vuex', 'vue-router']
},
output: {
// 输出的动态链接库的文件名称,[name] 代表当前动态链接库的名称,也就是 entry 中配置的 vuex
filename: '[name].dll.js',
// 输出的文件都放到 dist 目录下
path: path.resolve(__dirname, 'dist'),
// 存放动态链接库的全局变量名称,例如对应 vuex 来说就是 _dll_vuex
// 之所以在前面加上 _dll_ 是为了防止全局变量冲突
library: '_dll_[name]',
},
plugins: [
// 接入 DllPlugin
new DllPlugin({
// 动态链接库的全局变量名称,需要和 output.library 中保持一致
// 该字段的值也就是输出的 manifest.json 文件 中 name 字段的值
// 例如 vuex.manifest.json 中就有 "name": "_dll_vuex"
name: '_dll_[name]',
// 描述动态链接库的 manifest.json 文件输出时的文件名称
path: path.join(__dirname, 'dist', '[name].manifest.json'),
}),
],
};
由于之前在package.json中已经配置过dll命令了,所以执行对以下命令即可打包:
npm run dll
打包结果:
打包用时:335ms
项目体积:43.1KiB (vuex依赖被打包到vuex.dll.js中)
对vuex进行打包成动态链接库,将会生成vuex.dll.js和vuex.manifest.json文件。随后再webpack.config.js主文件中引入vuex.manifest.json:
const path = require('path');
// 1.导入webpack内置的DllReferencePlugin插件
const DllReferencePlugin = require('webpack/lib/DllReferencePlugin');
module.exports = {
entry: ['./src/main.js'],
output: {
// 1.指定输出的文件的名称为 bundle.js ( 默认为main.js )
filename: 'bundle.js',
// 2. 指定输出文件存放的目录(默认是dist目录)
path: path.resolve(__dirname, './dist'), // 借助node的path模块来拼接一个绝对路径
},
module: {
rules: [
{
test: /\.js$/, // 匹配 .css 结尾的文件,注意test的值不是一个字符串,而是一个正则
exclude: /(node_modules|bower_components)/,
use: [
{
loader: 'babel-loader',
options: {
// 2.使用bable,新语法转成es5语法
presets: [
'@babel/preset-env'
]
}
}
],
}
]
},
externals:{
// 把导入语句里的 jQuery 替换成运行环境里的全局变量 jQuery
jquery: "jQuery",
},
plugins: [
// 2.告诉 Webpack 使用了哪些动态链接库
new DllReferencePlugin({
// 3.描述 jquery 动态链接库的文件内容
manifest: require('./dist/vuex.manifest.json'),
}),
],
};
执行命令进行打包:
npm run dev
打包结果:
打包用时:1599ms
项目体积:5.68KiB (vuex依赖没有打包到bundle.js中,引用动态链接库的vuex)
很明显使用动态链接库效果也是很好,优化webpack项目的打包体积还是非常有效果。就是需要先打包生成动态链接库,随后在配置主项目打包配置引入动态链接库。