前端静态网站Lighthouse评分优化,vue3项目

一、降低打包体积方案

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

相关推荐
浩星3 小时前
css实现类似element官网的磨砂屏幕效果
前端·javascript·css
一只小风华~3 小时前
Vue.js 核心知识点全面解析
前端·javascript·vue.js
2022.11.7始学前端3 小时前
n8n第七节 只提醒重要的待办
前端·javascript·ui·n8n
SakuraOnTheWay3 小时前
React Grab实践 | 记一次与Cursor的有趣对话
前端·cursor
阿星AI工作室3 小时前
gemini3手势互动圣诞树保姆级教程来了!附提示词
前端·人工智能
徐小夕3 小时前
知识库创业复盘:从闭源到开源,这3个教训价值百万
前端·javascript·github
xhxxx3 小时前
函数执行完就销毁?那闭包里的变量凭什么活下来!—— 深入 JS 内存模型
前端·javascript·ecmascript 6
StarkCoder3 小时前
求求你试试 DiffableDataSource!别再手算 indexPath 了(否则迟早崩)
前端
fxshy3 小时前
Cursor 前端Global Cursor Rules
前端·cursor
红彤彤3 小时前
前端接入sse(EventSource)(@fortaine/fetch-event-source)
前端