背景
公司有个官网项目需要对网页做seo优化。至于为啥选择预渲染没用服务端渲染主要原因是:1、方便,对已有项目基础上做预渲染相对重新弄个nuxt项目更方便;2、项目中大部分都是静态资源,服务端渲染有点小题大做。出于以上考虑就最终选择了预渲染。
结果,开发过程中遇到挺多的坑。相关的资料也不多,现在好像很少有用预渲染了,所以在这里还是比较建议直接使用服务端渲染的方式,感觉其实也没有麻烦很多。
所以写一篇文章来记录一下过程和遇到的问题,以便其他想要用预渲染的小伙伴们参考一下。
简单说下我的项目情况:项目分为移动端和web端,项目独立。通过/m/路由区分。都要做预渲染。
prerender-spa-plugin 使用
prerender-spa-plugin 具体使用就不过多介绍了,很多文章都介绍的比较清楚。 直接上使用的代码,后面主要介绍其中的坑。
vue-router必须是History模式。
js
// vue.config.js
const PrerenderSPAPlugin = require("@dreysolano/prerender-spa-plugin");
// 这里为啥是"@dreysolano/prerender-spa-plugin"而不是"prerender-spa-plugin"是因为我项目是webpack5,这个库已经没更新了不支持。
const Renderer = PrerenderSPAPlugin.PuppeteerRenderer;
......
new PrerenderSPAPlugin({
staticDir: path.join(__dirname, "dist"),
routes: ["/", "/home"],
server: {
// 这里是因为我的页面中有些数据是接口请求回来的,所以这里加上代理。
proxy: {
"/fcc": {
target: "https://www.fcc.com",
secure: false,
},
},
renderer: new Renderer({
inject: {
foo: "bar",
},
headless: true,
renderAfterTime: 12000,
maxConcurrentRoutes: 12,
}),
}),
js
// main.js
import { createApp, onMounted } from "vue";
app.mount("#app");
onMounted(() => {
document.dispatchEvent(new Event("custom-render-trigger"));
});
查看是否成功直接打包看下目录结构是否有 /home/index.html,并且这个.html的内容中,#app内是有东西的就表示成功。或者打包后运行一下,页面右击查看源代码也能看出是不是预渲染成功了。
遇到的坑
1、webpack5 使用 prerender-spa-plugin 时打包报错
打包时遇到报错:
js
# [prerender-spa-plugin] Unable to prerender all routes!
解决方案:使用 @dreysolano/prerender-spa-plugin 而不是原版的prerender-spa-plugin
参考:[prerender-spa-plugin]无法预渲染所有路线!将 webpack 升级到 v5+ 时 ·问题 #414
2、线上环境发布时,jenkins日志报错无法启动Chrome
js
# Error : Failed to Launch chrome!
这是因为linux环境中没有安装Chrome。需要运维帮忙安装一下就好。
安装方法:linux安装谷歌浏览器(Chrome)
安装完之后记得启动检查一下是否缺少必要的库。
js
cd node_modules/puppeteer/.local-chromium/[linux-579032]/[chrome-linux]
ldd chrome | grep not
如果有缺少百度安装一下就好
3、刷新路由或者通过url跳转路由后面会多个/
发布成功之后,页面内通过点击实现的路由跳转是正常的,但是刷新路由或者通过url跳转会自动加上斜杆后缀。查看控制台静态资源可以看到正常的路由/home会重定向到/home/。这种情况会影响搜索引擎爬取,不利于seo
解决方案:修改ng配置,在第二个 $uri/
前面加上 $uri/index.html
js
location / {
try_files $uri $uri/index.html $uri/ /index.html;
}
参考文章:Vue Router history 模式 Nginx 配置目录文件刷新不自动添加斜杆 - 柯灰小栈 (kohai.top)
4、移动端和web端使用同一个域名的时候,会有指向问题或者页面为空的情况
先简单看下ng配置
js
location / {
alias /usr/nginx/fcc/;
try_files $uri $uri/index.html $uri/ /index.html last;
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
}
// 注意是/m/而不是/m,如果写/m那么如果web端中有/m开头的路由也会走到这。
location /m/ {
alias /usr/nginx/m_fcc/;
try_files $uri $uri/index.html $uri/ /index.html last;
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
}
移动端前端项目:
js
// router/index.ts
const router = createRouter({
history: createWebHistory("/m"),// 通过这种方式添加 base router
});
js
// vue.config.js
publicPath: "/", // 预渲染环境必须使用绝对路径
assetsDir: "m/", // 打包的静态资源需要在/m目录下,否则页面访问移动端的时候,静态资源会去找web项目的路径下。添加了之后打包出来的.html文件中,可以看到静态资源的路径前面会以/m开头。
//同web一样正常配置route
new PrerenderSPAPlugin({
staticDir: path.join(__dirname, "dist"),
routes: ["/", "/home"],
server: {
// 这里是因为我的页面中有些数据是接口请求回来的,所以这里加上代理。
proxy: {
"/fcc": {
target: "https://www.fcc.com",
secure: false,
},
},
renderer: new Renderer({
inject: {
foo: "bar",
},
headless: true,
renderAfterTime: 12000,
maxConcurrentRoutes: 12,
}),
}),
配置后打包出来的目录结果是
markdown
dist
- m
- js
- css
- img
- home
index.html
favicon.png
index.html