一、降低打包体积方案
1. 图片压缩
png图片,有透明度的转webp,没有透明度的转jpg,用python+Image库可以实现
2. 视频压缩
下载一个ffmpeg,对于超过10MB的视频进行压缩
ffmpeg -i input.mp4 -vcodec libx264 -crf 23 -preset fast -acodec aac -b:a 128k -movflags +faststart output.mp4
3. 字体文件压缩
使用woff2格式的字体文件,比ttf和woff格式的要小
4. 组件库按需引入
例如ant-design和swiper这种库,不在main.ts中引入,而是在用到的组件中进行import { Button } from 'ant-design-vue' 这种引入。
5. gzip打包
用.gz格式取代.js格式,可压缩近一半的大小,需要在nginx上配置。
二、提高评分
1. 引入字体文件的时候,加上font-display:swap
html
@font-face {
font-family: 'alibabapuhuiti';
src: url('@/assets/fonts/AlibabaPuHuiTi-3-85-Bold.woff2') format('woff2');
font-weight: 600 700;
font-display: swap;
}
2. 百度api引入,改成异步加载的语法,而不是在index.html添加script脚本
javascript
const LoadBaiduMapScript = () => {
const BMap_URL = "https://api.map.baidu.com/api?v=3.0&ak=xxxxxx";
return new Promise((resolve, reject) => {
// 如果已加载直接返回
if (typeof window.BMap !== "undefined") {
console.log("百度地图已经加载过了");
resolve(window.BMap);
return;
}
// 百度地图异步加载回调处理
window.onBMapCallback = () => {
console.log("百度地图脚本初始化成功...");
resolve(window.BMap);
};
// 插入script脚本
const scriptNode = document.createElement("script");
scriptNode.setAttribute("type", "text/javascript");
scriptNode.setAttribute("src", BMap_URL);
scriptNode.onerror = () => {
console.error("百度地图脚本加载失败");
reject(new Error("百度地图脚本加载失败"));
};
document.body.appendChild(scriptNode);
});
};
3.vite.config.ts配置,添加预加载和包分割
javascript
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import path from "path"; // 导入 path 模块
import viteCompression from "vite-plugin-compression";
export default defineConfig({
plugins: [
vue(),
{
name: "optimize-lcp",
transformIndexHtml: {
order: "post",
handler(html) {
// 为 CSS 文件添加 preload 和非阻塞加载
return html.replace(
/<link\s+rel="stylesheet"\s+crossorigin\s+href="([^"]+\.css)"\s*\/?>/g,
(_match, href) => {
return `<link rel="preload" href="${href}" as="style" onload="this.onload=null;this.rel='stylesheet'" crossorigin>
<noscript><link rel="stylesheet" crossorigin href="${href}"></noscript>`;
}
);
},
},
},
viteCompression({
verbose: true, // 控制台输出压缩结果
disable: false, // 是否禁用
threshold: 10240, // 大于 10KB 的文件才压缩
algorithm: "gzip", // 压缩算法,也可用 'brotliCompress'
ext: ".gz", // 生成的压缩包后缀
deleteOriginFile: false, // 压缩后是否删除原文件(慎用!)
}),
],
server: {
port: 5200,
},
resolve: {
alias: {
"@": path.resolve(__dirname, "src"),
},
},
build: {
// CSS 代码分割优化
cssCodeSplit: true,
rollupOptions: {
output: {
// 手动分离 CSS chunk
manualChunks(id) {
// 将第三方库的 CSS 单独打包
if (id.includes("node_modules")) {
if (id.includes("ant-design-vue") || id.includes("swiper")) {
return "vendor-styles";
}
}
},
},
},
},
});
4.nginx配置缓存
给字体文件、视频文件等不太会变的内容添加长时间缓存,修改nginx.conf文件
javascript
http {
#...默认的内容
server {
listen 80;
server_name localhost;
# 开启 gzip_static和gzip
gzip_static on;
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json;
location / {
root html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
add_header Cache-Control "no-cache, no-store, must-revalidate" always;
}
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2?|ttf|eot)$ {
add_header Cache-Control "public, max-age=31536000, immutable" always;
}
location @router {
rewrite ^.*$ /index.html last;
}
}
}
5. 动态引入组件
(1) 充分利用vue3中的动态导入机制,在route.ts中使用component: import(...)
{
path: "/",
name: "Home",
component: () => import("../views/home/index.vue"),
}
(2) 使用defineAsyncComponent代替import
html
<script setup lang="ts">
import { ref, onMounted, onUnmounted, defineAsyncComponent } from 'vue'
const Navbar = defineAsyncComponent(() => import('./navigation/Navbar.vue'));
const Footer = defineAsyncComponent(() => import('./Footer.vue'));
const ScrollToTop = defineAsyncComponent(() => import('./ScrollToTop.vue'));
const isMobile = ref(false)
</script>
<template>
<div>
<Navbar />
<main class="main-content">
<router-view />
</main>
<Footer />
<ScrollToTop />
</div>
</template>
<style scoped>
</style>
三、代码规范
1. head标签中添加meta属性,对提高SEO评分有好处
html
<meta name="description" content="" />
<meta name="keywords" content="" />
2. video添加poster属性,设置占位图片,更规范不过文件更多,所以只给首屏视频加上了。
3. 所有img元素添加alt属性
四、未生效方案
1. vendor-styles-xxx文件优化
(1) swiper css优化,即使用细分的 import 'swiper/css/*'; 代替全部引入的 import 'swiper/swiper-bundle.css',对评分和时间都没区别
(2) ant-design-vue components优化,即在vite.config.ts里面引入 AntDesignVueResolver 额外组件库,然后取消css的引入,变成 import 'ant-design-vue/es/drawer/style' 这样的手动引入,实际上没用
(3) vendor-styles-xxx是我命名的外部库的名称,通过浏览器开发者工具的覆盖范围查看这个文件中多余的部分,有很多其实是必要的冗余,针对不同条件的样式,根本没办法再优化,但是Lighthouse会一直提到这个文件
五、总结
通过以上操作,将Lighthouse性能评分从37分提到了74分,将dist大小从234MB减少到了120MB