1.技术选型
- vue3 :^3.4.21
- vite :^5.2.0
-
puppeteer :^24.15.0
-
vite-plugin-seo-prerender :^1.0.0
-
@vueuse/head :^2.0.0
2.现代 SSR 方案已高度框架化,应该优先选择生态成熟的方案(Next.js/Nuxt.js)。于 Vue3 项目,Nuxt.js 提供了开箱即用的 SSR+SEO 解决方案,兼顾开发效率与性能,尤其适合内容型博客的场景。若需极致轻量化,这里采用 vite-plugin-seo-prerender 与 Puppeteer 原生实现 因为实在是不想去大改现有逻辑。所以选择了这两个插件 下面会一步步教你如果优化并列出踩到的坑 你们好直接避免。话不多说直接开始吧。
3. 首先下载插件
- pnpm i puppeteer
- pnpm i vite-plugin-seo-prerender
- 这个时候会遇到下载失败问题
- 不用去百度 不用去问DeepSeek,他们提供的方法都没用
- 解决方案:切换npm镜像到cnpm 这样安装时会自动下载Chromium,命令如下
-
// 第一步 npm install -g cnpm // 第二步 cnpm install puppeteer // 第三步 cnpm install vite-plugin-seo-prerender
- pnpm i @vueuse/head
- 这时候插件就全部下载完成了
4. @vueuse/head SEO 实现 Meta 设置
- main.ts文件导入
-
// main.ts 导入 import { createApp } from "vue"; import App from "./App.vue"; import { createHead } from '@vueuse/head'; const app = createApp(App); const head = createHead() app.use(head); app.mount("#app");
- App.vue设置(我是设置在App.vue里面)
-
<script setup lang="ts"> const route = useRoute(); import {useHead} from "@vueuse/head"; // 默认设置一次 useHead({ meta: [ { name: "keywords", content: "关键词1,关键词2,关键词3", }, { name: "description", content: `科技有限公司致力于工业软件国产化的创新研发和推广应用,通过自主研发和技术引进及消化,推出了全系列国产化工业软件,应用范围覆盖数字化工程、数字化交付和数字化工厂`, }, ], }); watch( () => route.path, (_newVal, _oldVal) => { let title: any = route.meta.title; if (route.path === "/cloudHome/cloudApplication") { useHead({ title: "网站title", script: [ { type: "application/ld+json", innerHTML: JSON.stringify({ "@context": "https://schema.org", // ✔️ 固定值(不可改) "@type": "Organization", // 你的企业类型 name: "网站title", url: "https://console.com.cn/", // ✔️ 你的网站 logo: "https://console.com.cn/vite.svg", description: "领先的工程设计软件云端解决方案", contactPoint: { "@type": "ContactPoint", telephone: "001-***", contactType: "客户服务", }, }), }, ], }); } else { useHead({ title: "网站title-" + 路由名称, }); } }, {deep: true} ); </script> <template> <loading-provider> <router-view/> </loading-provider> </template>
5. 使用vite-plugin-seo-prerender 进行预渲染
- 1.找到vite.config.ts文件
-
import { defineConfig } from "vite"; import vue from "@vitejs/plugin-vue"; import path from "path"; // 注意这里的ts校验过不去 不知道为什么 有大佬知道可以探讨一下 // 我新建了一个type.d.ts 并且设置了vite-plugin-seo-prerender 还是爆红 找不到模块 // @ts-ignore import seoPrerender from "vite-plugin-seo-prerender"; // https://vitejs.dev/config/ export default defineConfig({ resolve: { extensions: [".vue", ".ts"], alias: { "@": path.resolve(__dirname, "src"), }, }, plugins: [ vue(), // 预渲染页面路由 seoPrerender({ hashHistory: false, routes: [ "/", "/cloudHome/cloudApplication", "/cloudHome/supportAndService", "/cloudHome/projectCase", "/cloudHome/productIntroduction", "/cloudHome/understandHly", "/cloudHome/businessPartner", "/cloudHome/wingTool", "/cloudHome/digitalDeliveryAlliance", ], rendererOptions: { renderAfterDocumentEvent: "render-complete", renderAfterTime: 15000, // ✅ 推荐添加超时保险(单位:毫秒) headless: true, skipThirdPartyRequests: true, // ⚡ 避免加载无关资源提升速度 inject: { prerendering: true // 注入预渲染标记 } }, // minify: { // // 压缩 HTML(可选) // collapseWhitespace: true, // removeComments: true, // }, staticDir: path.join(__dirname, "dist"), // 输出目录(默认 dist) }), ], });
- renderAfterDocumentEvent: "render-complete", 代表可以开始预渲染的事件 如果你的页面有动态数据可以在页面接口回来使用这个事件
- 以上已经完美的搞定了 可以愉快的打包了,打包完成是这样的
- 打开一个html 已经有内容了 不在是一个<div id="app"></div>了