您现在的位置是:首页 >技术教程 >vue中vue.config.js配置优化首屏加载速度,以及打包分析网站首页技术教程
vue中vue.config.js配置优化首屏加载速度,以及打包分析
简介vue中vue.config.js配置优化首屏加载速度,以及打包分析
1. 优化 CDN 引入
vue.config.js:
// import { swiper, swiperSlide } from 'vue-awesome-swiper'
// import 'swiper/swiper-bundle.css'
const IS_PROD = ['production', 'prod'].includes(process.env.NODE_ENV)
const externals = {
'vue-awesome-swiper': 'VueAwesomeSwiper',
Swiper: 'Swiper',
}
const cdn = {
// 开发环境
dev: {
css: [],
js: [],
},
// 生产环境
build: {
css: ['https://cdn.jsdelivr.net/npm/swiper@6.1.1/swiper-bundle.css'],
js: [
'https://cdn.jsdelivr.net/npm/swiper@6.1.1/swiper-bundle.js',
'https://cdn.jsdelivr.net/npm/vue-awesome-swiper@3.1.3/dist/vue-awesome-swiper.js',
],
},
}
module.exports = {
configureWebpack: (config) => {
config.name = name
if (IS_PROD) {
Object.assign(config, {
name: name,
externals: externals,
})
}
},
chainWebpack: (config) => {
/**
* 添加CDN参数到htmlWebpackPlugin配置中
*/
config.plugin('html').tap((args) => {
if (IS_PROD) {
args[0].cdn = cdn.build
} else {
args[0].cdn = cdn.dev
}
return args
})
},
}
index.html:
<head>
<!-- 动态css-->
<% 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" />
<% } %>
<!-- 动态js-->
<% for (var i in
htmlWebpackPlugin.options.cdn&&htmlWebpackPlugin.options.cdn.js) { %>
<script src="<%= htmlWebpackPlugin.options.cdn.js[i] %>"></script>
<% } %>
</head>
2.压缩和 Gzip
npm install --save-dev compression-webpack-plugin
vue.config.js:
const CompressionWebpackPlugin = require('compression-webpack-plugin')
const productionGzipExtensions = /.(js|css|json|txt|html|ico|svg)(?.*)?$/i
const IS_PROD = ['production', 'prod'].includes(process.env.NODE_ENV)
module.exports = {
// 其他配置...
configureWebpack: (config) => {
config.name = name
const plugins = []
if (IS_PROD) {
// gzip
plugins.push(
new CompressionWebpackPlugin({
filename: '[path].gz[query]',
algorithm: 'gzip',
test: productionGzipExtensions,
threshold: 10240,
minRatio: 0.8,
})
)
}
config.plugins = [...config.plugins, ...plugins]
},
// 其他配置...
}
3. 代码分割
vue.config.js:
const IS_PROD = ['production', 'prod'].includes(process.env.NODE_ENV)
module.exports = {
// 其他配置...
chainWebpack: (config) => {
// 其他配置...
// 判断是否是生产环境
config.when(IS_PROD, (config) => {
config.optimization.splitChunks({
chunks: 'all',
cacheGroups: {
// cacheGroups 下可以可以配置多个组,每个组根据test设置条件,符合test条件的模块
commons: {
name: 'chunk-commons',
test: resolve('src/components'),
minChunks: 3, // 被至少用三次以上打包分离
priority: 5, // 优先级
reuseExistingChunk: true, // 表示是否使用已有的 chunk,如果为 true 则表示如果当前的 chunk 包含的模块已经被抽取出去了,那么将不会重新生成新的。
},
node_vendors: {
name: 'chunk-libs',
chunks: 'initial', // 只打包初始时依赖的第三方
test: /[\/]node_modules[\/]/,
priority: 10,
},
vueawesomeswiper: {
name: 'chunk-vueawesomeswiper', // 单独将 vueawesomeswiper 拆包
test: /[\/]node_modules[\/]vue-awesome-swiper[\/]/,
priority: 20, // 数字大权重到,满足多个 cacheGroups 的条件时候分到权重高的
},
},
})
config.optimization.runtimeChunk('single')
})
},
}
4.使用 Service Worker
npm install workbox-webpack-plugin --save-dev
vue.config.js:
const WorkboxPlugin = require('workbox-webpack-plugin')
const IS_PROD = ['production', 'prod'].includes(process.env.NODE_ENV)
module.exports = {
// 其他配置...
configureWebpack: (config) => {
config.name = name
if (IS_PROD) {
config.plugins.push(
new WorkboxPlugin.GenerateSW({
clientsClaim: true,
skipWaiting: true,
})
)
}
},
// 其他配置...
}
5. 使用预渲染
npm install prerender-spa-plugin --save-dev
vue.config.js:
const PrerenderSPAPlugin = require('prerender-spa-plugin')
const Renderer = PrerenderSPAPlugin.PuppeteerRenderer
const IS_PROD = ['production', 'prod'].includes(process.env.NODE_ENV)
module.exports = {
// 其他配置...
configureWebpack: (config) => {
config.name = name
if (IS_PROD) {
config.plugins.push(
new PrerenderSPAPlugin({
staticDir: path.join(__dirname, 'dist'),
routes: [
'/',
'/#/custom', // hash路由时
],
renderer: new Renderer({
renderAfterTime: 5000, // 等待时间(确保页面加载完成)
headless: true,
injectProperty: '__PRERENDER_INJECTED',
waitForElement: '#app', // 等待特定元素出现
}),
})
)
}
},
// 其他配置...
}
6. 其他东西 webpack-report,打包分析
npm install --save-dev webpack-bundle-analyzer
vue.config.js:
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')
const IS_PROD = ['production', 'prod'].includes(process.env.NODE_ENV)
module.exports = {
// 配置1
chainWebpack: (config) => {
/**
* 打包分析
*/
if (IS_PROD) {
config.plugin('webpack-report').use(BundleAnalyzerPlugin, [
{
analyzerMode: 'static',
},
])
}
},
//配置2
configureWebpack: (config) => {
config.name = name
const plugins = []
if (IS_PROD) {
plugins.push(
new BundleAnalyzerPlugin({
analyzerMode: 'static', // 生成静态 HTML 报告
generateStatsFile: true, // 生成 stats 文件
statsFilename: 'stats.json', // stats 文件的名称
reportFilename: 'report.html', // 报告文件的名称
openAnalyzer: false, // 不自动打开报告
})
)
}
config.plugins = [...config.plugins, ...plugins]
},
}
7.整体结果
vue.config.js:
'use strict'
const path = require('path')
// 压缩和 Gzip
const CompressionWebpackPlugin = require('compression-webpack-plugin')
const productionGzipExtensions = /.(js|css|json|txt|html|ico|svg)(?.*)?$/i
// 预渲染
const PrerenderSPAPlugin = require('prerender-spa-plugin').PrerenderSPAPlugin
const Renderer = PrerenderSPAPlugin.PuppeteerRenderer
// 打包分析
const BundleAnalyzerPlugin =
require('webpack-bundle-analyzer').BundleAnalyzerPlugin
const resolve = (dir) => path.join(__dirname, dir)
const name = 'vue mobile template'
const IS_PROD = ['production', 'prod'].includes(process.env.NODE_ENV)
const externals = {
'vue-awesome-swiper': 'VueAwesomeSwiper',
Swiper: 'Swiper',
}
const cdn = {
dev: {
css: [],
js: [],
},
build: {
css: [
'https://image-v2.youpaizhaohuo.cn/insideH5/node_modules/swiper-bundle-6.1.1.css',
],
js: [
'https://image-v2.youpaizhaohuo.cn/insideH5/node_modules/swiper-bundle-6.1.1.js',
'https://image-v2.youpaizhaohuo.cn/insideH5/node_modules/vue-awesome-swiper-3.1.3.js',
],
},
}
module.exports = {
publicPath: './',
outputDir: 'dist',
assetsDir: 'static',
lintOnSave: !IS_PROD,
productionSourceMap: false,
devServer: {
//port: 8000, // 端口
open: false,
overlay: {
warnings: false,
errors: true,
},
//代理
proxy: {
'/api': {
target: ''//代理的域名,
changeOrigin: true,
pathRewrite: {
'^/api': '/',
},
},
},
},
css: {
extract: IS_PROD, // 是否将组件中的 CSS 提取至一个独立的 CSS 文件中 (而不是动态注入到 JavaScript 中的 inline 代码)。
sourceMap: false,
loaderOptions: {
// 向全局sass样式传入共享的全局变量, $src可以配置图片cdn前缀
// 详情: https://cli.vuejs.org/guide/css.html#passing-options-to-pre-processor-loaders
scss: {
prependData: `
@import "assets/css/mixin.scss";
@import "assets/css/variables.scss";
$cdn: "";
`,
},
},
},
configureWebpack: (config) => {
config.name = name
const plugins = []
if (IS_PROD) {
Object.assign(config, {
name: name,
externals: externals,
})
// prerender-spa-plugin
plugins.push(
new PrerenderSPAPlugin({
staticDir: path.join(__dirname, 'dist'),
routes: ['/', '/#/customBack/commonIndex'],
renderer: new Renderer({
renderAfterTime: 5000,
headless: true,
injectProperty: '__PRERENDER_INJECTED',
waitForElement: '#app',
}),
})
)
// gzip
plugins.push(
new CompressionWebpackPlugin({
filename: '[path].gz[query]',
algorithm: 'gzip',
test: productionGzipExtensions,
threshold: 10240,
minRatio: 0.8,
})
)
// Service Worker
plugins.push(
new WorkboxPlugin.GenerateSW({
clientsClaim: true,
skipWaiting: true,
})
)
}
config.plugins = [...config.plugins, ...plugins]
},
chainWebpack: (config) => {
config.plugins.delete('preload')
config.plugins.delete('prefetch')
// 别名 alias
config.resolve.alias
.set('@', resolve('src'))
.set('assets', resolve('src/assets'))
.set('api', resolve('src/api'))
.set('views', resolve('src/views'))
.set('components', resolve('src/components'))
/**
* 添加CDN参数到htmlWebpackPlugin配置中
*/
config.plugin('html').tap((args) => {
if (IS_PROD) {
args[0].cdn = cdn.build
} else {
args[0].cdn = cdn.dev
}
return args
})
/**
* 设置保留空格
*/
config.module
.rule('vue')
.use('vue-loader')
.loader('vue-loader')
.tap((options) => {
options.compilerOptions.preserveWhitespace = true
return options
})
.end()
/**
* 打包分析
*/
if (IS_PROD) {
config.plugin('webpack-report').use(BundleAnalyzerPlugin, [
{
analyzerMode: 'static',
},
])
}
config.when(!IS_PROD, (config) => config.devtool('cheap-source-map'))
config.when(IS_PROD, (config) => {
config
.plugin('ScriptExtHtmlWebpackPlugin')
.after('html')
.use('script-ext-html-webpack-plugin', [
{
inline: /runtime..*.js$/,
},
])
.end()
config.optimization.splitChunks({
chunks: 'all',
cacheGroups: {
// cacheGroups 下可以可以配置多个组,每个组根据test设置条件,符合test条件的模块
commons: {
name: 'chunk-commons',
test: resolve('src/components'),
minChunks: 3, // 被至少用三次以上打包分离
priority: 5, // 优先级
reuseExistingChunk: true, // 表示是否使用已有的 chunk,如果为 true 则表示如果当前的 chunk 包含的模块已经被抽取出去了,那么将不会重新生成新的。
},
node_vendors: {
name: 'chunk-libs',
chunks: 'initial', // 只打包初始时依赖的第三方
test: /[\/]node_modules[\/]/,
priority: 10,
},
vueawesomeswiper: {
name: 'chunk-vueawesomeswiper', // 单独将 vueawesomeswiper 拆包
test: /[\/]node_modules[\/]vue-awesome-swiper[\/]/,
priority: 20, // 数字大权重到,满足多个 cacheGroups 的条件时候分到权重高的
},
},
})
config.optimization.runtimeChunk('single')
})
},
}
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。





QT多线程的5种用法,通过使用线程解决UI主界面的耗时操作代码,防止界面卡死。...
U8W/U8W-Mini使用与常见问题解决
stm32使用HAL库配置串口中断收发数据(保姆级教程)
分享几个国内免费的ChatGPT镜像网址(亲测有效)
Allegro16.6差分等长设置及走线总结