在前端开发中,我一直很注重性能优化,这篇文章就给大家分享一下我的优化思路与方案。
当使用浏览器打开一个URL时,浏览器会先查看当前URL是否有缓存,没有缓存则进行DNS域名解析,将域名解析为IP地址,建立TCP链接,会经历三次握手,向服务器发送HTTP请求,服务器返回HTML文档;
浏览器开始渲染页面,首先解析HTML文档生成DOM树,然后下载CSS文件,解析CSS文件生成CSSOM树,DOM树和CSSOM树相结合生成渲染树。
根据渲染树里面元素的大小和位置,进行网页布局;布局完成后,再遍历render渲染树,根据渲染树里面的颜色、尺寸等显示属性,进行绘制,最终将网页显示在屏幕上。
访问URL会经历很复杂的一个过程,所以我从下面几个部分提高前端性能。
优化流程
移除多余文件
移除不用插件
按需引入插件
小图片转base64格式
使用SVG图标
当前项目技术栈:Vue + Element
分析项目文件大小
在项目优化之前我都会对前端项目进行分析,利用webpack包分析器,分析文件大小
安装插件
npm install webpack-bundle-analyzer -D
在vue.config.js里面配置
// vue.config.js
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
module.exports = {
chainWebpack: config => {
// 结果输出分析
config.plugin('webpack-bundle-analyzer')
.use(
new BundleAnalyzerPlugin({
analyzerMode: 'server', // 'server' | 'static' | 'disabled',
analyzerHost: '127.0.0.1',
analyzerPort: 8889
})
)
}
}
运行项目,自动打开分析页面
npm run serve
利用插件分析无用文件
安装插件
npm i useless-files-webpack-plugin -D
在vue.config.js里面配置
const UselessFile = require('useless-files-webpack-plugin')
module.exports = {
chainWebpack: config => {
// 结果输出分析
config.plugin('useless-files-webpack-plugin')
.use(
new UselessFile({
root: './src', // 项目目录
out: './fileList.json', // 输出文件列表
clean: false,// 删除文件,
// exclude: path // 排除文件列表, 格式为文件路径数组
})
)
}
}
运行项目,自动生成无用文件列表
npm run serve
当运行项目时会自动生成fileList.json文件,里面显示着没有用到的文件,理论上是都可以删除的,但是建议根据实际情况进行删除,尽量不要删除以后可能会用到的文件。
Echarts 按需引入
安装Echarts
npm install echarts --save
如果只有首页用到了Echarts,建议直接在文件夹内引入,若很多页面都用到Echarts可在main.js里全局引入
// 引入基本模板
import * as echarts from 'echarts/lib/echarts'
// 引入柱状图组件
import 'echarts/lib/chart/bar'
// 引入提示框和title组件,图例
import 'echarts/lib/component/tooltip'
import 'echarts/lib/component/title'
import 'echarts/lib/component/legend'
import 'echarts/lib/component/grid'
Element 按需引入
安装插件
// 安装插件
npm install element-ui --save
// 安装 babel-plugin-component
npm install babel-plugin-component -D
引入
import { Button, Row } from 'element-ui';
Vue.use(Button);
因为按照官方配置 .babelrc会报错Cannot find module 'babel-preset-es2015' ,所以跳过该配置,进行下面配置
安装插件
npm install babel-preset-es2015 -D
配置babel.config.js
module.exports = {
'presets': [
'@vue/cli-plugin-babel/preset'
],
'plugins': [
[
'component',
{
'libraryName': 'element-ui',
'styleLibraryName': 'theme-chalk'
}
]
]
}
按需引入全局尺寸配置
Vue.prototype.$ELEMENT = { size: 'small' }
使用SVG
安装插件
npm install svg-sprite-loader -D
在vue.config.js里面配置
const path = require('path')
function resolve(dir) {
return path.join(__dirname, dir)
}
module.exports = {
chainWebpack: config => {
// set svg-sprite-loader
config.module
.rule('svg')
.exclude.add(resolve('src/assets/icons'))
.end()
config.module
.rule('icons')
.test(/\.svg$/)
.include.add(resolve('src/assets/icons'))
.end()
.use('svg-sprite-loader')
.loader('svg-sprite-loader')
.options({
symbolId: 'icon-[name]'
})
.end()
}
}
然后在src/assets目录下创建icon文件夹,内部有svg文件夹,用于存放svg文件,还有index.js文件。
// index.js 文件
import Vue from 'vue'
import SvgIcon from '@/components/SvgIcon'// svg component
// register globally
Vue.component('svg-icon', SvgIcon)
const req = require.context('./svg', false, /\.svg$/)
const requireAll = requireContext => requireContext.keys().map(requireContext)
requireAll(req)
然后在components 中新建组件 SvgIcon.vue
<template>
<div v-if="isExternal" :style="styleExternalIcon" class="svg-external-icon svg-icon" v-on="$listeners" />
<svg v-else :class="svgClass" aria-hidden="true" v-on="$listeners">
<use :href="iconName" />
</svg>
</template>
<script>
// doc: https://panjiachen.github.io/vue-element-admin-site/feature/component/svg-icon.html#usage
import { isExternal } from '@/utils/validate'
export default {
name: 'SvgIcon',
props: {
iconClass: {
type: String,
required: true
},
className: {
type: String,
default: ''
}
},
computed: {
isExternal() {
return isExternal(this.iconClass)
},
iconName() {
return `#icon-${this.iconClass}`
},
svgClass() {
if (this.className) {
return 'svg-icon ' + this.className
} else {
return 'svg-icon'
}
},
styleExternalIcon() {
return {
mask: `url(${this.iconClass}) no-repeat 50% 50%`,
'-webkit-mask': `url(${this.iconClass}) no-repeat 50% 50%`
}
}
}
}
</script>
<style scoped>
.svg-icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
.svg-external-icon {
background-color: currentColor;
mask-size: cover!important;
display: inline-block;
}
</style>
内部引入的isExternal函数
export function isExternal(path) {
return /^(https?:|mailto:|tel:)/.test(path)
}
最后在main.js文件中引入icon
// main.js
import './assets/icons' // icon
在vue文件里使用即可
<svg-icon icon-class="email" />
小图片转base64格式
安装插件
cnpm install url-loader file-loader -D
vue.config.js配置
configureWebpack: {
// limit 单位为B 1000 = 1k
chainWebpack(config) {
config.module
.rule('images')
.use('url-loader')
.loader('url-loader')
.tap(options => Object.assign(options, { limit: 200000,esModule: false}))
}
}