需求:项目过大可以使用打包优化,减少项目体积,加速页面加载,增强用户体验,跟着步骤来即可实现,主要是vue2的打包优化,不是vue3,文章可能有点长,但是很实用哈哈,耐心看完~
1.打包前体积
运行如下命令开始打包,注意!!!打包之前必须保证项目有node_modules依赖包,不然提示命令无效,npm run build后默认的环境为production
npm run build
优化前打包体积 2.14M
2.下载打包体积可视化工具
npm i webpack-bundle-analyzer
再vue.config.js文件中配置,如果没有这个文件,自己在主目录新建个就行,配置如下:
// 导入包分析器插件
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const ENV = process.env.NODE_ENV
module.exports = {
configureWebpack: config => {
// 如果是在线上环境
if (ENV === 'production') {
config.plugins.push(
// 解决端口被占用的问题
new BundleAnalyzerPlugin({
analyzerMode: 'server',
analyzerHost: '127.0.0.1',//ip地址
analyzerPort: 8880,//设置个未使用的端口就行,默认端口为8888
reportFilename: 'report.html',
defaultSizes: 'parsed',
openAnalyzer: true,
generateStatsFile: false,
statsFilename: 'stats.json',
statsOptions: null,
logLevel: 'info'
}),
)
}
}
}
配置完成后删除dist文件再重新打包,会自动弹出网页,这里我们可以看到打包后的体积为2.43MB
3.使用Gzip压缩js和css
安装插件,注意!!!一定不要安装最新版,直接安装6.1.1的版本就行
npm i compression-webpack-plugin@6.1.1
安装最新版会报如下错误
再vue.config.js中添加
// 导入包分析器插件
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
// 导入gzip
const CompressionWebpackPlugin = require('compression-webpack-plugin')
const ENV = process.env.NODE_ENV
module.exports = {
configureWebpack: config => {
// 如果是在线上环境
if (ENV === 'production') {
config.plugins.push(
// 解决端口被占用的问题
new BundleAnalyzerPlugin({
analyzerMode: 'server',
analyzerHost: '127.0.0.1',//ip地址
analyzerPort: 8880,//设置个未使用的端口就行,默认端口为8888
reportFilename: 'report.html',
defaultSizes: 'parsed',
openAnalyzer: true,
generateStatsFile: false,
statsFilename: 'stats.json',
statsOptions: null,
logLevel: 'info'
}),
// gzip,压缩js
new CompressionWebpackPlugin({
filename: '[path].gz[query]',//压缩文件的输入路径和名称
algorithm: "gzip",//表示使用gzip算法进行压缩
test: new RegExp('\\.(' + ['js', 'css'].join('|') + ')$'),//正则匹配文件名
threshold: 10240,//文件大小阀值,大于或者等于10240字节(10kb)
minRatio: 0.8,//最小压缩比例,只有压缩后大小与原始大小的比例大于等于该值时,才会保留压缩后的文件。这里设置为 0.8,表示压缩后的文件大小至少为原始文件大小的 80%。
deleteOriginalAssets: false,//保留原始文件
})
)
}
}
}
4.添加基础配置和删除需要预先加载和预先获取的资源
主要代码:
chainWebpack: (config) => {
// 删除需要预先加载(当前页面)的资源,当需要这些资源的时候,页面会自动加载
config.plugins.delete('preload')
// 删除需要预先获取(将来的页面)的资源
config.plugins.delete('prefetch')
}
// 导入包分析器插件
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
// 导入gzip
const CompressionWebpackPlugin = require('compression-webpack-plugin')
const ENV = process.env.NODE_ENV
module.exports = {
outputDir: 'dist',
// 放置生成的静态资源 (js、css、img、fonts) 的 (相对于 outputDir 的) 目录
assetsDir: 'static',
// lintOnSave: process.env.NODE_ENV === 'development',
lintOnSave: false,//关闭eslint检查
// 不输出 map 文件,false将提高构建速度
productionSourceMap: false,
configureWebpack: config => {
// 如果是在线上环境
if (ENV === 'production') {
config.plugins.push(
// 解决端口被占用的问题
new BundleAnalyzerPlugin({
analyzerMode: 'server',
analyzerHost: '127.0.0.1',//ip地址
analyzerPort: 8880,//设置个未使用的端口就行,默认端口为8888
reportFilename: 'report.html',
defaultSizes: 'parsed',
openAnalyzer: true,//浏览器自动打开
generateStatsFile: false,
statsFilename: 'stats.json',
statsOptions: null,
logLevel: 'info'
}),
// gzip,压缩js
new CompressionWebpackPlugin({
filename: '[path].gz[query]',//压缩文件的输入路径和名称
algorithm: "gzip",//表示使用gzip算法进行压缩
test: new RegExp('\\.(' + ['js', 'css'].join('|') + ')$'),//正则匹配文件名
threshold: 10240,//文件大小阀值,大于或者等于10240字节(10kb)
minRatio: 0.8,//最小压缩比例,只有压缩后大小与原始大小的比例大于等于该值时,才会保留压缩后的文件。这里设置为 0.8,表示压缩后的文件大小至少为原始文件大小的 80%。
deleteOriginalAssets: false,//保留原始文件
})
)
}
},
chainWebpack: (config) => {
// 删除需要预先加载(当前页面)的资源,当需要这些资源的时候,页面会自动加载
config.plugins.delete('preload')
// 删除需要预先获取(将来的页面)的资源
config.plugins.delete('prefetch')
}
}
原先文件目录结构==============修改基础配置后的打包文件结构
5.使用webpack合并js,并且可以对代码进行优化压缩
主要代码
`vue.config.js: `
const webpack = require('webpack')
const ENV = process.env.NODE_ENV
module.exports = {
chainWebpack: (config) => {
config.when(ENV === 'production', config => {
config.plugin('webpackOptimize')
.use(
webpack.optimize.LimitChunkCountPlugin,
// 限制生成的代码块(chunks)的数量
[{ maxChunks: 10 }]
)
.use(
webpack.optimize.MinChunkSizePlugin,
// 指定代码块的最小字节数
[{ minChunkSize: 50000 }]
)
})
}
}
完整代码
const webpack = require('webpack')
// 导入包分析器插件
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
// 导入gzip
const CompressionWebpackPlugin = require('compression-webpack-plugin')
const ENV = process.env.NODE_ENV
module.exports = {
outputDir: 'dist',
// 放置生成的静态资源 (js、css、img、fonts) 的 (相对于 outputDir 的) 目录
assetsDir: 'static',
// lintOnSave: process.env.NODE_ENV === 'development',
lintOnSave: false,//关闭eslint检查
// 不输出 map 文件,false将提高构建速度
productionSourceMap: false,
configureWebpack: config => {
// 如果是在线上环境
if (ENV === 'production') {
config.plugins.push(
// 解决端口被占用的问题
new BundleAnalyzerPlugin({
analyzerMode: 'server',
analyzerHost: '127.0.0.1',//ip地址
analyzerPort: 8880,//设置个未使用的端口就行,默认端口为8888
reportFilename: 'report.html',
defaultSizes: 'parsed',
openAnalyzer: true,//浏览器自动打开
generateStatsFile: false,
statsFilename: 'stats.json',
statsOptions: null,
logLevel: 'info'
}),
// gzip,压缩js
new CompressionWebpackPlugin({
filename: '[path].gz[query]',//压缩文件的输入路径和名称
algorithm: "gzip",//表示使用gzip算法进行压缩
test: new RegExp('\\.(' + ['js', 'css'].join('|') + ')$'),//正则匹配文件名
threshold: 10240,//文件大小阀值,大于或者等于10240字节(10kb)
minRatio: 0.8,//最小压缩比例,只有压缩后大小与原始大小的比例大于等于该值时,才会保留压缩后的文件。这里设置为 0.8,表示压缩后的文件大小至少为原始文件大小的 80%。
deleteOriginalAssets: false,//保留原始文件
})
)
}
},
chainWebpack: (config) => {
// 删除需要预先加载(当前页面)的资源,当需要这些资源的时候,页面会自动加载
config.plugins.delete('preload')
// 删除需要预先获取(将来的页面)的资源
config.plugins.delete('prefetch')
config.when(ENV === 'production', config => {
config.plugin('webpackOptimize')
.use(
webpack.optimize.LimitChunkCountPlugin,
// 限制生成的代码块(chunks)的数量
[{ maxChunks: 10 }]
)
.use(
webpack.optimize.MinChunkSizePlugin,
// 指定代码块的最小字节数
[{ minChunkSize: 50000 }]
)
})
}
}
大小查看,减小了一点点哈哈
6.使用cdn加速,可以把一些大包在线上使用cdn加速的方式实现
6.1在主目录建立dependencies-cdn.js
6.2添加需要cdn的加速插件
在这里我用的是BootCDN - Bootstrap 中文网开源项目免费 CDN 加速服务有需要的直接去里面搜之后把你自己下载好的插件版本对应上就行,比如我在项目的vuex:3.6.2,那么我去里面找对应版本之后把min.js文件复制进去就行,css是这个插件需要俩个一起导入才行,比如element有一个样式和一个功能。
// cnd加速
module.exports = [
{ name: 'vue', library: 'Vue', js: 'https://cdn.bootcdn.net/ajax/libs/vue/2.6.14/vue.min.js', css: '' },
{ name: 'vue-router', library: 'VueRouter', js: 'https://cdn.bootcdn.net/ajax/libs/vue-router/3.5.1/vue-router.min.js', css: '' },
{ name: 'vuex', library: 'Vuex', js: 'https://cdn.bootcdn.net/ajax/libs/vuex/3.6.2/vuex.min.js', css: '' },
{ name: 'axios', library: 'axios', js: 'https://cdn.bootcdn.net/ajax/libs/axios/1.1.3/axios.min.js', css: '' },
{ name: 'element-ui', library: 'ELEMENT', js: 'https://unpkg.com/element-ui/lib/index.js', css: 'https://unpkg.com/element-ui/lib/theme-chalk/index.css' },
]
6.3在vue.config.js中导入
主要代码:
const cdnDependencies = require('./dependencies-cdn')
// 设置不参与构建的库
let externals = {}
cdnDependencies.forEach(package => { externals[package.name] = package.library })
// 引入文件的 cdn 链接
const cdn = {
css: cdnDependencies.map(e => e.css).filter(e => e),
js: cdnDependencies.map(e => e.js).filter(e => e)
}
module.exports = {
configureWebpack: config => {
// 如果是在线上环境
if (ENV === 'production') {
config.externals = externals}},
chainWebpack: (config) => {
/**
* 添加 CDN 参数到 htmlWebpackPlugin 配置中
*/
config.plugin('html').tap(args => {
if (process.env.NODE_ENV === 'production') {
args[0].cdn = cdn
} else {
args[0].cdn = []
}
return args
})
}
}
}
完整代码
const webpack = require('webpack')
// 导入包分析器插件
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
// 导入gzip
const CompressionWebpackPlugin = require('compression-webpack-plugin');
// 导入cdn
const cdnDependencies = require('./dependencies-cdn')
// 设置不参与构建的库
let externals = {}
cdnDependencies.forEach(package => { externals[package.name] = package.library })
// 引入文件的 cdn 链接
const cdn = {
css: cdnDependencies.map(e => e.css).filter(e => e),
js: cdnDependencies.map(e => e.js).filter(e => e)
}
const ENV = process.env.NODE_ENV
module.exports = {
// 例如 https://www.ciqin.vip/。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 https://www.ciqin.vip/admin/,则设置 baseUrl 为 /admin/。
publicPath: process.env.NODE_ENV === "production" ? "/" : "/",
outputDir: 'dist',
// 放置生成的静态资源 (js、css、img、fonts) 的 (相对于 outputDir 的) 目录
assetsDir: 'static',
// lintOnSave: process.env.NODE_ENV === 'development',
lintOnSave: false,//关闭eslint检查
// 不输出 map 文件,false将提高构建速度
productionSourceMap: false,
configureWebpack: config => {
// 如果是在线上环境
if (ENV === 'production') {
config.externals = externals
config.plugins.push(
// 解决端口被占用的问题
new BundleAnalyzerPlugin({
analyzerMode: 'server',
analyzerHost: '127.0.0.1',//ip地址
analyzerPort: 8880,//设置个未使用的端口就行,默认端口为8888
reportFilename: 'report.html',
defaultSizes: 'parsed',
openAnalyzer: true,//浏览器自动打开
generateStatsFile: false,
statsFilename: 'stats.json',
statsOptions: null,
logLevel: 'info'
}),
// gzip,压缩js
new CompressionWebpackPlugin({
filename: '[path].gz[query]',//压缩文件的输入路径和名称
algorithm: "gzip",//表示使用gzip算法进行压缩
test: /\.(js|css|html)?$/i,//正则匹配文件名
threshold: 10240,//文件大小阀值,大于或者等于10240字节(10kb)
minRatio: 0.8,//最小压缩比例,只有压缩后大小与原始大小的比例大于等于该值时,才会保留压缩后的文件。这里设置为 0.8,表示压缩后的文件大小至少为原始文件大小的 80%。
deleteOriginalAssets: false,//保留原始文件
cache: false// 不启用文件缓存
})
)
}
},
chainWebpack: (config) => {
// 删除需要预先加载(当前页面)的资源,当需要这些资源的时候,页面会自动加载
config.plugins.delete('preload')
// 删除需要预先获取(将来的页面)的资源
config.plugins.delete('prefetch')
config.when(ENV === 'production', config => {
config.plugin('webpackOptimize')
.use(
webpack.optimize.LimitChunkCountPlugin,
// 限制生成的代码块(chunks)的数量
[{ maxChunks: 10 }]
)
.use(
webpack.optimize.MinChunkSizePlugin,
// 指定代码块的最小字节数
[{ minChunkSize: 50000 }]
)
})
/**
* 添加 CDN 参数到 htmlWebpackPlugin 配置中
*/
config.plugin('html').tap(args => {
if (process.env.NODE_ENV === 'production') {
args[0].cdn = cdn
} else {
args[0].cdn = []
}
return args
})
}
}
6.4在public下的index.html中设置
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
<link rel="icon" href="<%= BASE_URL %>favicon.ico" />
<!-- 使用 CDN 加速的 CSS 文件,配置在 vue.config.js 下 -->
<% for (var i in
htmlWebpackPlugin.options.cdn&&htmlWebpackPlugin.options.cdn.css) { %>
<link
href="<%= htmlWebpackPlugin.options.cdn.css[i] %>"
rel="preload"
as="style"
/>
<link href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" rel="stylesheet" />
<% } %>
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<noscript>
<strong
>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work
properly without JavaScript enabled. Please enable it to
continue.</strong
>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
<!-- 使用 CDN 加速的 JS 文件,配置在 vue.config.js 下 -->
<% for (var i in htmlWebpackPlugin.options.cdn &&
htmlWebpackPlugin.options.cdn.js) { %>
<script src="<%= htmlWebpackPlugin.options.cdn.js[i] %>"></script>
<% } %>
</body>
</html>
6.4打包后体积1.51MB,减小了快一半了,当然你写的cdn越多减的体积也越多
7.使用happypack提高打包速度
7.1下载happypack
npm install happypack -D
7.2再vue.config.js中导入
主要代码
// 导入多线程
const HappyPack = require('happypack');
const os = require('os');
// 开辟一个线程池,拿到系统CPU的核数,happypack 将编译工作利用所有线程
const happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length });
new HappyPack({
id: 'happybabel',
loaders: ['babel-loader'],
threadPool: happyThreadPool
})
)
完整代码
const webpack = require('webpack')
// 导入包分析器插件
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
// 导入gzip
const CompressionWebpackPlugin = require('compression-webpack-plugin');
// 导入cdn
const cdnDependencies = require('./dependencies-cdn')
// 导入多线程
const HappyPack = require('happypack');
const os = require('os');
// 开辟一个线程池,拿到系统CPU的核数,happypack 将编译工作利用所有线程
const happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length });
// 设置不参与构建的库
let externals = {}
cdnDependencies.forEach(package => { externals[package.name] = package.library })
// 引入文件的 cdn 链接
const cdn = {
css: cdnDependencies.map(e => e.css).filter(e => e),
js: cdnDependencies.map(e => e.js).filter(e => e)
}
const ENV = process.env.NODE_ENV
module.exports = {
// 例如 https://www.ciqin.vip/。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 https://www.ciqin.vip/admin/,则设置 baseUrl 为 /admin/。
publicPath: process.env.NODE_ENV === "production" ? "/" : "/",
outputDir: 'dist',
// 放置生成的静态资源 (js、css、img、fonts) 的 (相对于 outputDir 的) 目录
assetsDir: 'static',
// lintOnSave: process.env.NODE_ENV === 'development',
lintOnSave: false,//关闭eslint检查
// 不输出 map 文件,false将提高构建速度
productionSourceMap: false,
configureWebpack: config => {
// 如果是在线上环境
if (ENV === 'production') {
config.externals = externals
config.plugins.push(
// 解决端口被占用的问题
new BundleAnalyzerPlugin({
analyzerMode: 'server',
analyzerHost: '127.0.0.1',//ip地址
analyzerPort: 8880,//设置个未使用的端口就行,默认端口为8888
reportFilename: 'report.html',
defaultSizes: 'parsed',
openAnalyzer: true,//浏览器自动打开
generateStatsFile: false,
statsFilename: 'stats.json',
statsOptions: null,
logLevel: 'info'
}),
// gzip,压缩js
new CompressionWebpackPlugin({
filename: '[path].gz[query]',//压缩文件的输入路径和名称
algorithm: "gzip",//表示使用gzip算法进行压缩
test: /\.(js|css|html)?$/i,//正则匹配文件名
threshold: 10240,//文件大小阀值,大于或者等于10240字节(10kb)
minRatio: 0.8,//最小压缩比例,只有压缩后大小与原始大小的比例大于等于该值时,才会保留压缩后的文件。这里设置为 0.8,表示压缩后的文件大小至少为原始文件大小的 80%。
deleteOriginalAssets: false,//保留原始文件
cache: false// 不启用文件缓存
}),
new HappyPack({
id: 'happybabel',
loaders: ['babel-loader'],
threadPool: happyThreadPool
})
)
}
},
chainWebpack: (config) => {
// 删除需要预先加载(当前页面)的资源,当需要这些资源的时候,页面会自动加载
config.plugins.delete('preload')
// 删除需要预先获取(将来的页面)的资源
config.plugins.delete('prefetch')
config.when(ENV === 'production', config => {
config.plugin('webpackOptimize')
.use(
webpack.optimize.LimitChunkCountPlugin,
// 限制生成的代码块(chunks)的数量
[{ maxChunks: 10 }]
)
.use(
webpack.optimize.MinChunkSizePlugin,
// 指定代码块的最小字节数
[{ minChunkSize: 50000 }]
)
})
/**
* 添加 CDN 参数到 htmlWebpackPlugin 配置中
*/
config.plugin('html').tap(args => {
if (process.env.NODE_ENV === 'production') {
args[0].cdn = cdn
} else {
args[0].cdn = []
}
return args
})
}
}
未完待续。。。