01-performance項(xiàng)目
vue-cli 搭建項(xiàng)目
- 查看 vue-cli 版本:
vue -V
報(bào)錯(cuò)或者說(shuō)不存在 vue 命令:安裝 vue-cli:
npm install -g @vue/cli
- 創(chuàng)建項(xiàng)目:
vue create 01-performance
Vue CLI v5.0.8
? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, Router, Vuex, CSS Pre-processors, Linter
? Choose a version of Vue.js that you want to start the project with 3.x
? Use history mode for router? (Requires proper server setup for index fallback in production) Yes
? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): Sass/SCSS (with dart-
? Pick a linter / formatter config: Standard
? Pick additional lint features: Lint on save
? Where do you prefer placing config for Babel, ESLint, etc.? In dedicated config files
? Save this as a preset for future projects? No
? Pick the package manager to use when installing dependencies: NPM
- 運(yùn)行項(xiàng)目:
cd 01-performance
烂翰,npm run serve
安裝 axios
npm i --save axios
報(bào)錯(cuò):npm ERR! code ERESOLVE npm ERR! ERESOLVE could not resolve
原因:npm 不同版本庫(kù)之間命令不兼容
解決:npm i --save axios --legacy-peer-deps
數(shù)據(jù)懶加載(DataLazy.vue)
該功能一共被分為三個(gè)階段:
不獲取數(shù)據(jù)
用戶將要看到(使用 IntersectionObserver玉掸,或 useIntersectionObserver 進(jìn)行判斷)
獲取數(shù)據(jù)并渲染(在視圖元素可見時(shí),再獲取數(shù)據(jù))
IntersectionObserver
作用:監(jiān)聽某個(gè)視窗是否被用戶看見
// IntersectionObserver為 JS 的原生api璧榄,可直接使用
const box3Target = ref(null)
onMounted(() => {
const intersectionObserver = new IntersectionObserver((entries) => {
if (entries[0].intersectionRatio <= 0) {
return console.log('當(dāng)前試圖不可見')
}
console.log('當(dāng)前視圖可見')
// TODO 獲取數(shù)據(jù)
})
// box3Target.value:被監(jiān)聽的元素對(duì)象
intersectionObserver.observe(box3Target.value)
})
useIntersectionObserver
vue 的工具庫(kù) vueuse
提供的一個(gè)基于 IntersectionObserver 的封裝方法业筏,需安裝npm i --save @vueuse/core
報(bào)錯(cuò):npm ERR! code ERESOLVE npm ERR! ERESOLVE could not resolve
原因:npm 不同版本庫(kù)之間命令不兼容
解決:npm i --save @vueuse/core --legacy-peer-deps
import { useIntersectionObserver } from '@vueuse/core'
const box3Target = ref(null)
onMounted(() => {
const { stop } = useIntersectionObserver(
box3Target,
([{ isIntersecting }]) => {
if (isIntersecting) {
console.log('當(dāng)前視圖可見')
// TODO 獲取數(shù)據(jù)
// 觸發(fā) stop黔攒,監(jiān)聽停止
stop()
} else {
console.log('當(dāng)前試圖不可見')
}
}
)
})
圖片懶加載(ImgLazy.vue)
使用 <b>自定義指令</b> 實(shí)現(xiàn)圖片懶加載
通過(guò) vue3 的 app.directive
完成 <b>自定義指令</b>
步驟:
構(gòu)建自定義指令
利用 IntersectionObserver旨巷,或 useIntersectionObserver 完成監(jiān)聽
// 01-performance\src\directive\index.js
import { useIntersectionObserver } from '@vueuse/core'
const imgLazy = {
// mounted: 在綁定元素的父組件及他自己的所有子節(jié)點(diǎn)都掛載完成后調(diào)用
// el: 調(diào)用該指令的元素
mounted(el) {
// 圖片懶加載:一開始不加載,等到將要看到時(shí)再加載
// 1. 緩存當(dāng)前的圖片路徑
const catchSrc = el.src
console.log(catchSrc)
// 2. 把 img.src 變?yōu)檎嘉粓D
el.src = 'https://res.lgdsunday.club/img-load.png'
// 3. 使用 useIntersectionObserver 監(jiān)聽 el 將要被看到
const { stop } = useIntersectionObserver(el, ([{ isIntersecting }]) => {
if (isIntersecting) {
// 4. 渲染圖片
el.src = catchSrc
// 5. 停止監(jiān)聽
stop()
}
})
}
}
export default {
// app.use 的方式使用
install: (app) => {
app.directive('imglazy', imgLazy)
}
}
// 01-performance\src\main.js
import directive from './directive'
app.use(directive)
<!-- 01-performance\src\views\ImgLazy.vue -->
<!-- v-imglazy: 自定義指令imglazy -->
<img :src="item.path" alt="" class="item-img" v-imglazy />
解決打包體積過(guò)大
例子:安裝并使用了 xlsx 和 echarts 后尿赚,打包結(jié)果如下:
warning
asset size limit: The following asset(s) exceed the recommended size limit (244 KiB).
This can impact web performance.
Assets:
js/chunk-vendors.bd8f41b3.js (1.55 MiB)
warning
entrypoint size limit: The following entrypoint(s) combined asset size exceeds the recommended limit (244 ct web performance.
Entrypoints:
app (1.56 MiB)
js/chunk-vendors.bd8f41b3.js
js/app.f9f8599c.js
File Size Gzipped
dist\js\chunk-vendors.bd8f41b3.js 1591.84 KiB 522.06 KiB
dist\js\67.24f04139.js 37.50 KiB 14.77 KiB
dist\js\app.f9f8599c.js 5.74 KiB 2.61 KiB
dist\js\546.4ca973ee.js 2.26 KiB 0.86 KiB
dist\js\816.5c4d75f2.js 1.02 KiB 0.59 KiB
dist\css\546.2e47b4de.css 0.76 KiB 0.30 KiB
dist\css\816.5617b692.css 0.75 KiB 0.32 KiB
步驟:
- 分析包體積過(guò)大的主要原因
1.1 命令 vue-cli-service build --report
散庶,打包的同時(shí)生成 dist\report.html 以幫助分析包內(nèi)容
// 01-performance\package.json
{
"scripts": {
"report": "vue-cli-service build --report"
}
}
1.2 查看 dist\report.html 可看到最大的占比為 echarts 和 xslx蕉堰,即包體積過(guò)大的主要原因
- 使用 webpack5 的
externals
配置選項(xiàng),排除體積過(guò)大的包
// 01-performance\vue.config.js
// @vue/cli-service 集成了webpack的配置
const { defineConfig } = require('@vue/cli-service')
let externals = {}
// 排除打包悲龟,只需要在 build 排除
const isProd = process.env.NODE_ENV === 'production'
if (isProd) {
externals = {
xlsx: 'xlsx',
echarts: 'echarts'
}
}
module.exports = defineConfig({
transpileDependencies: true,
// 調(diào)整webpack配置
// 對(duì)象:會(huì)被 webpack-merge 合并入最終的 webpack 配置
configureWebpack: {
externals: externals
},
})
重新打包后的結(jié)果如下:
WARNING Compiled with 1 warning 14:22:38
[eslint]
D:\Study\前端\05-性能優(yōu)化\01-performance\src\views\DataLazy.vue
44:3 warning Unexpected console statement no-console
51:3 warning Unexpected console statement no-console
59:3 warning Unexpected console statement no-console
79:9 warning Unexpected console statement no-console
85:9 warning Unexpected console statement no-console
D:\Study\前端\05-性能優(yōu)化\01-performance\src\views\HomeView.vue
14:3 warning Unexpected console statement no-console
15:3 warning Unexpected console statement no-console
D:\Study\前端\05-性能優(yōu)化\01-performance\src\views\ImgLazy.vue
7:3 warning Unexpected console statement no-console
? 8 problems (0 errors, 8 warnings)
You may use special comments to disable some warnings.
Use // eslint-disable-next-line to ignore the next line.
Use /* eslint-disable */ to ignore all warnings in a file.
File Size Gzipped
dist\js\chunk-vendors.8c4522c4.js 146.95 KiB 51.96 KiB
dist\js\67.e0736f3f.js 37.71 KiB 14.86 KiB
dist\js\app.8c52ff36.js 5.74 KiB 2.61 KiB
dist\js\546.4ca973ee.js 2.26 KiB 0.86 KiB
dist\js\816.5c4d75f2.js 1.02 KiB 0.59 KiB
dist\css\546.2e47b4de.css 0.76 KiB 0.30 KiB
dist\css\816.5617b692.css 0.75 KiB 0.32 KiB
- 運(yùn)行此時(shí)的打包文件屋讶,會(huì)得到錯(cuò)誤:
Uncaught ReferenceError: XLSX is not defined
可以利用第三方
anywhere
運(yùn)行打包之后的項(xiàng)目
- 安裝:
npm i -g anywhere
- 在 dist 目錄下,執(zhí)行終端命令:
anywhere
- 會(huì)自動(dòng)啟動(dòng)服務(wù)
- 使用 CDN 引入被 webpack 排除的包须教,利用 vue-cli 默認(rèn)配置的
HtmlWebpackPlugin
攜帶屬性的特性皿渗,添加 CDN
// 01-performance\vue.config.js
const { defineConfig } = require('@vue/cli-service')
let cdnJS = []
// 排除打包,只需要在 build 排除
const isProd = process.env.NODE_ENV === 'production'
if (isProd) {
cdnJS = [
'https://unpkg.com/echarts@5.5.1/dist/echarts.js',
'https://unpkg.com/xlsx@0.18.5/dist/xlsx.full.min.js'
]
}
module.exports = defineConfig({
transpileDependencies: true,
// 允許對(duì)內(nèi)部的 webpack 配置進(jìn)行更細(xì)粒度的修改
chainWebpack(config) {
// 修改插件選項(xiàng)
// config.plugin('html'):獲取到HtmlWebpackPlugin
// tap():修改參數(shù)
config.plugin('html').tap((args) => {
// 攜帶指定的屬性到 HtmlWebpackPlugin
args[0].cdnJS = cdnJS
return args
})
}
})
<!-- 01-performance\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" />
<!-- 請(qǐng)求不添加請(qǐng)求來(lái)源轻腺,解決403錯(cuò)誤 -->
<meta name="referrer" content="no-referrer" />
<title>
<!-- 從 htmlWebpackPlugin 配置項(xiàng)中獲取 title 屬性 --> <%=
htmlWebpackPlugin.options.title %>
</title>
<style>
* {
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<div id="app"></div>
<!-- 從 htmlWebpackPlugin 配置項(xiàng)中獲取 cdnJS 屬性 -->
<% for(var js of htmlWebpackPlugin.options.cdnJS){ %>
<script src="<%=js%>"></script>
<% } %>
</body>
</html>
其它優(yōu)化
externals + CDN 只能減小打包的體積乐疆,加快訪問(wèn)速度
其它的優(yōu)化如:
gzip 壓縮
http 緩存
service worker
gzip 壓縮
通過(guò) LZ77 算法與 Huffman 編碼來(lái)壓縮文件,<b>重復(fù)度越高</b> 的文件可壓縮的空間越大约计,對(duì)JS诀拭、CSS迁筛、HTML等文本資源均有效
當(dāng) Nginx 返回 js 文件的時(shí)候煤蚌,會(huì)判斷是否開啟 gzip,然后壓縮后再返回給瀏覽器
該方法需要 Nginx 配置開啟 Gzip 壓縮细卧,單純前端通過(guò) webpack 插件開啟 Gzip 壓縮是不能達(dá)到優(yōu)化效果的
http 緩存
網(wǎng)頁(yè) 304 狀態(tài)碼:所請(qǐng)求的資源<b>未修改</b>尉桩。服務(wù)器返回此狀態(tài)碼時(shí),<b>不會(huì)</b>返回任何資源贪庙≈├纾客戶端通常會(huì)緩存訪問(wèn)過(guò)的資源,通過(guò)提供一個(gè)頭信息指出客戶端希望只返回在指定日期之前修改的資源
大多數(shù)情況下止邮,304 一般在服務(wù)框架中進(jìn)行了處理这橙,前端一般不需要過(guò)于關(guān)注
service worker
是一個(gè) JS api:https://developer.mozilla.org/zh-CN/docs/Web/API/Service_Worker_API
旨在創(chuàng)建有效的離線體驗(yàn),它會(huì)攔截網(wǎng)絡(luò)請(qǐng)求并根據(jù)網(wǎng)絡(luò)是否可用來(lái)采取適當(dāng)?shù)膭?dòng)作导披、更新來(lái)自服務(wù)器的資源
還提供入口以推送通知和訪問(wèn)后臺(tái)同步 API