1. 跟上技术的迭代(node,npm,yarn)
在项目中尽可能 使用新的webpack、node等.新版本内可能做了一些性能上的优化,更好用一些 。
2. 在尽可能少的 模块上使用loader。
如合理的使用include和exclude
...
module.exports = {
...
module: {
rules: [{
test: /\.js$/,
exclude: /node_modules/, //一定要加,不然会降低打包速度
use: ['babel-loader','eslint-loader']
}]
},
}
3. plugin尽可能精简并确保可靠。开发环境无用插件剔除
开发模式下未使用css压缩的插件,生产模式下未使用热更新的插件,为的就是减少插件 的使用,提升性能。
//webpack.prod.js
plugins: [new MiniCssExtractPlugin({
filename: '[name].css'
})]
//webpack.dev.js
plugins: [
new webpack.HotModuleReplacementPlugin()
]
插件尽可能使用官方推荐过的,性能比较好的或社区 验证过的插件 。
4. import时后缀名是否要加?extensions和mainFiles
const commonConfig = {
...
resolve:{
extensions:['.js','.jsx'] ,//如果import时没有指定文件后缀 ,就先找.js文件
mainFiles:['index','main'] //如果导入时不加文件名和后缀,指定先去找名为index文件,没有的话再去找名为main的文件。
}
}
import Home from './home'; //js、jsx文件可以不加
import './style.css'; //css文件加上后缀名
import Child from './child/'; //配置了mainFiles,引入时不加文件名,不可取
js、ts、jsx等逻辑代码可以不加后缀,.jpg、.svg、.css等建议导入时加上 文件后缀,因为类型多了,一个类型一个类型查找就费时间了。mainFiles能不配就不配,影响打包性能。
5. 控制webpack打包生成的文件大小
tree shaking
splitchunks
6. thread-loader,parallel-webpack,happypack多进程打包。默认是单进程,同事利用多个 cpu。
7. 合理使用sourcemap,sourcemap越详细打包越慢
8. 结合stats分析打包结果
9. 开发环境内存编辑。不会生成dist目录,放在内存里边,内存比硬盘读取快的多
10.DllPlugin
也可以参考臂展某个老师的视频,很清晰:https://www.bilibili.com/video/BV1eC4y147RX/?spm_id_from=333.337.search-card.all.click&vd_source=8d08ffbe793f2ec363ae13e64d626a61
第三方模块的代码并不会变,但是每次打包都会去分析一次再融合成一个文件打包出来的,默认配置如此。
如果单独把这些第三方包打包成一个文件,只分析一次 ,之后再次打包不再去分析,直接用上次分析好的结果,达到第三方包只打包一次,这是个很好的思路。
optimization: {
splitChunks: {
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10,
},
}
}
},
准备工作:创建一个新项目mytest-dll,生产和开发分开配置,入口文件用到了react、react-dom和lodash等第三方包
5.1. 生成单独三方包文件 ,配置DllPlugin生成映射文件
单独写个三方包配置文件webpack.dll.js,生成一个js文件,暴露到全局,再用插件生成一个对应的包映射文件。 npm run build:dll
//webpack.dll.js
const path = require('path')
const webpack = require('webpack')
module.exports = {
mode:'production',
entry:{
vendors:['react-dom','react','lodash'], //用到的第三方包,生成 一个js文件
},
output:{
filename:'[name].dll.js', //包名将是vendors.dll.js
path:path.resolve(__dirname,'../dll'), //输出到dll目录
library:'[name]',//entry叫什么名,暴露的全局对象就叫什么名
},
plugins:[
new webpack.DllPlugin({ //生成import三方包请求 到module id的映射文件
name:'[name]', //entry名
path:path.resolve(__dirname,'../dll/[name].manifest.json') //映射文件的生成路径
})
]
}
//package.json
"scripts": {
"dev-build": "webpack --config ./build/webpack.common.js",
"build": "webpack --env.production --config ./build/webpack.common.js",
"build:dll": "webpack --config ./build/webpack.dill.js",
"start": "webpack-dev-server --config ./build/webpack.common.js"
},
5.2. add-asset-html-webpack-plugin嵌入dll.js文件到html中
把这个vendors.dill.js通过script标签插入到HtmlWebpackPlugin生成的index.html中,安装基于HtmlWebpackPlugin的一个插件 npm i add-asset-html-webpack-plugin@3.1.2 -D
...
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin');
const commonConfig = {
...
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname,'../src/index.html')
}),
new AddAssetHtmlWebpackPlugin({ //把生成的vendors.dll.js通过script标签嵌入html中
filepath: path.resolve(__dirname,'../dll/vendors.dll.js')
})
]
}
...
5.3. 配置DllReferencePlugin
用插件在包导入的时候,先去映射文件里查找是否有该包,有就使用dll导出的包,没有再去已分析出的包中找。 npm run build
...
const path = require('path')
const webpack = require('webpack')
const commonConfig = {
...
plugins: [
new webpack.DllReferencePlugin({ //import包时,先去manifest.json中看有没有这个包,有就用全局变量的,没有再去node_modules里找
manifest:path.resolve(__dirname,'../dll/vendors.manifest.json')
})
]
}
...
5.4 项目比较复杂,三方包生成多个文件
//webpack.dll.js
module.exports = {
entry:{
vendors:['react-dom','react'],
lodash:['lodash'],
}
}
//webpack.common.js
const path = require('path')
const fs = require('fs')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const CleanWebpackPlugin = require('clean-webpack-plugin')
const webpack = require('webpack')
const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin');
function getPlugins() {
var plugins = [
new CleanWebpackPlugin(['dist'], {
root: path.resolve(__dirname, '../'), //指定项目根目录,默认清空下会认为当前文件所在的目录为根目录。
}),
new HtmlWebpackPlugin({
template: path.resolve(__dirname, '../src/index.html')
})
]
const files = fs.readdirSync(path.resolve(__dirname, '../dll')) //读取文件夹内的文件名
console.log(files)
files.forEach((filename) => {
if (/.\.dll\.js$/.test(filename)) {
plugins.push(
new AddAssetHtmlWebpackPlugin({ //把生成的vendors.dll.js通过script标签嵌入html中
filepath: path.resolve(__dirname, '../dll', filename)
})
)
} else if (/.\.manifest\.json$/.test(filename)) {
plugins.push(
new webpack.DllReferencePlugin({
manifest: path.resolve(__dirname, '../dll',filename)
})
)
}
})
return plugins
}
const commonConfig = {
...
plugins: getPlugins()
// plugins: [
// new CleanWebpackPlugin(['dist'], {
// root: path.resolve(__dirname, '../'), //指定项目根目录,默认清空下会认为当前文件所在的目录为根目录。
// }),
// new HtmlWebpackPlugin({
// template: path.resolve(__dirname,'../src/index.html')
// }),
// new AddAssetHtmlWebpackPlugin({ //把生成的vendors.dll.js通过script标签嵌入html中
// filepath: path.resolve(__dirname,'../dll/vendors.dll.js')
// }),
// new webpack.DllReferencePlugin({
// manifest:path.resolve(__dirname,'../dll/vendors.manifest.json')
// }),
// new AddAssetHtmlWebpackPlugin({ //把生成的lodash.dll.js通过script标签嵌入html中
// filepath: path.resolve(__dirname,'../dll/lodash.dll.js')
// }),
// new webpack.DllReferencePlugin({
// manifest:path.resolve(__dirname,'../dll/lodash.manifest.json')
// })
// ]
}
5.5 也可以把打好的库放到cdn上