uni-app ssr(服务器渲染) + 动态路由(伪静态) + seo优化
uni-app主要用于小程序开发 也支持H5开发。由于使用的是vue单页面。所以想要搜索引擎seo优化的难度是相当大。uni-app只提供了一个托管云函数的ssr方式,作用相当有限。所以这个轮子必须得自己来造。
这些坑帮你们踩过了 不要去踩了。
1:ssr(服务器渲染) 只支持托管代码到uni-app云函数上。
2:路由是pages.json写死的单页面不支持伪静态
3:路由不能使用自己的vue-router@4
4:路由不能自行增加addRouters uni-app会去自己的对象检测路由是否存在。
5:哪怕检测路由你都绕过了 你会发现页面不会调用onLoad这些生命周期。当普通组件而不是页面级组件。而且ssr服务端也不支持。
1:解决动态路由:
就是一个页面组件 实现多个路径都可以访问。
比如/pages/index/id /id/:id 定义这样的动态高级路由。
有人会想到使用url参数不就可以了。
我的哥既然做seo优化。H5页面还在使用动态参数这样的动态路径。权重根本不高。
如果一个个的手动pages.json增加页面。那商城 文章这样的 怎么办。
所以要解决seo 必须要解决动态路由。
这条路坑很多。网上没有一个能用的。
都是解决路由守卫这些功能。并没有动态高级路由
但看都在说有个能用 但是价格有点小贵. 收费的。
因为这些我觉得我花时间研究uni-app源码自然可以解决。
最终功夫不负有心人找到了解决办法。
const hookRoute = (routes) => {
if (!routes && typeof __uniRoutes !== 'undefined') routes = __uniRoutes
if (!Array.isArray(routes)) return routes
const needPush = []
for (const route of routes) {
let seoPath = route?.meta?.seoPath || seoRoutes[route.path];
if (!seoPath) {
if (!route.path || route.alias) continue;
const seoPathSplit = route.path.split('/')
seoPath = `/${seoPathSplit[seoPathSplit.length-1]}`
}
const newRoute = {}
for (const k in route) newRoute[k] = route[k];
newRoute.path = seoPath
if (pathKeys[seoPath]) continue;
pathKeys[seoPath] = newRoute
needPush.push(pathKeys[seoPath])
}
routes.push(...needPush);
return routes
}
就这么简单。路由就增加好了。
但新的问题来了。测试普通路由这样动态添加没问题。
但动态高级路由这样添加就有问题。
上面说过就算增加了路由又能怎样。
uni-app有判断路由是否存在。 像 /id/:id 这样的路由 怎么能通过判断呢。
使用:alias
动态变更这个alias就能通过uni-app判断路由是否存在。
那就使用uni.addInterceptor 拦截器拦截请求之前动态设置这个alias就实现。
function seoHook(path) {
if (!path || typeof path !== 'string') return null
path = path.split("?")[0];
if (pathKeys[path]) return pathKeys[path]
const hookData = matchPath(path, pathKeys);
if (hookData) hookData.alias = path;
return hookData
}
//该拦截器如果跟你的守卫有冲突 需要自行合并到你的守卫代码里 seoHook(args.url)
function addInterceptor() {
// 要拦截的页面跳转方法列表
const navigationMethods = ['navigateTo', 'redirectTo', 'reLaunch', 'switchTab'];
// 设置拦截器
navigationMethods.forEach(method => {
uni.addInterceptor(method, {
invoke(args) {
const seoHookData = seoHook(args.url);
return true; // 允许跳转
},
fail(e) {
console.error(e)
}
});
});
}
测试通过一切正常
2:解决seo优化
这个简单直接在页面里增加即可
<page-meta>
<head>
<title>标题</title>
<meta name="description" content="uniapp h5 seo搜索引擎优化 支持伪静态" />
<meta name="keywords" content="uniapp seo,uniapp ssr,uniapp 伪静态" />
</head>
</page-meta>
那么动态如何实现呢:
//uniapp_seo/pages/index/id.vue 具体看这个演示代码
export default {
data() {
const idData={
"1": {
"title": "这是文章1的标题 黑神话悟空",
"keywords": "这是文章1的关键词",
"description": "这是文章1的description",
"content": "文章1:黑神话悟空"
},
"2": {
"title": "这是文章2的标题 全红婵",
"keywords": "这是文章2的关键词",
"description": "这是文章2的description",
"content": "文章2:全红婵"
},
"default": {
"keywords": "这是默认的关键词",
"description": "这是默认的描述",
"content": "我是默认的内容"
}
}
return {
...idData[this.$route?.params?.id||"default"]
}
}
}
需要注意写data函数里 其他地方ssr不会渲染。
我之前还说过如果是商城 文章系统上面这样的肯定无法满足了必须服务器上渲染了
这部分放文档里说。 太复杂不是好事。
3: 解决ssr(服务器渲染)
上一篇文章有详细的如何解决非托管使用uni-app的ssr。 这里不再多说。
可以看上一篇文章
最终打包全部源码开源给需要的人 不要再去踩坑造轮子。
仅支持uni-app Vue3项目 不支持Vue2 (因为uni-app vue2不支持ssr)
用途:
实现uni-app的h5项目的搜索引擎seo优化提高网站排名终极解决方案。
功能:
- uni-app h5项目(Vue3)动态路由 也就是伪静态路由(网上并没有相关的功能 据说有一家支持但收费)
- ssr(服务器渲染)将uni-app项目在服务器上转为静态页面并实现服务端的动态路由。
- 突破uni-app官方ssr必须托管代码并使用uniCloud(云函数)的限制 可以任何平台运行
- seo优化 支持每个页面设置meta 关键词 描述等 (动态路由设置页面关键词有单独的说明)
开始使用:
- 下载安装
git clone https://github.com/fzl51/uniapp-router-h5.git
cd uniapp-router-h5
npm install
- 运行
npm start
或者
node main.js
此时打开 http://localhost:8080 鼠标右键查看源码看seo效果
演示:https://v.yy2169.com
使用文档:
uniapp_seo目录
uni-app项目源码 里面是演示如何使用。
- 在main.js导入路由 会自动hook路由增加动态路由(伪静态)
//uniapp_seo/main.js
import './router'
- 配置路由方法1: uniapp_seo/router.js (推荐) 2选1
//uniapp_seo/router.js
const seoRoutes = {
"/pages/index/id": "/id/:id"
}
- 配置路由方法2: 直接在pages.json 设置简单(微信小程序端会有提示 可以加条件编译)
{
"path": "pages/index/seo",
"style": {
// #ifdef H5
"seoPath":"/seo/:name",
// #endif
"navigationBarTitleText": "uni-app seo 动态路由 伪静态"
}
}
- 路由格式:支持动态高级路由(伪静态) /id/:id 这种路径也支持 /h5 这样的静态路径
- seo优化 在页面级组件直接写下面代码即可
#uniapp_seo/pages/index/seo.vue
<page-meta>
<head>
<title>标题</title>
<meta name="description" content="uniapp h5 seo搜索引擎优化 支持伪静态" />
<meta name="keywords" content="uniapp seo,uniapp ssr,uniapp 伪静态" />
</head>
</page-meta>
- 动态页面设置不同的meta关键词 页面数据等信息
//uniapp_seo/pages/index/id.vue 具体看这个演示代码
export default {
data() {
const idData={
"1": {
"title": "这是文章1的标题 黑神话悟空",
"keywords": "这是文章1的关键词",
"description": "这是文章1的description",
"content": "文章1:黑神话悟空"
},
"2": {
"title": "这是文章2的标题 全红婵",
"keywords": "这是文章2的关键词",
"description": "这是文章2的description",
"content": "文章2:全红婵"
},
"default": {
"keywords": "这是默认的关键词",
"description": "这是默认的描述",
"content": "我是默认的内容"
}
}
return {
...idData[this.$route?.params?.id||"default"]
}
}
}
- 也可以在服务端写代码实现动态路由seo优化 我们演示项目在服务端实现的.
为了减少复杂度我们删除了服务端实现部分代码。
不然一会uni-app项目设置一会在服务端代码设置 人都醉了。
服务端设置动态路由seo 优点是每次更改不需要重新编译。
注意:⚠️服务端实现seo优化就不要在页面组件实现
//routes.js
const meta={
"/": {
"keywords": "这是默认的关键词",
"description": "这是默认的描述",
},
"/id/1": {
"title": "这是文章1的标题 黑神话悟空",
"keywords": "这是文章1的关键词",
"description": "这是文章1的description",
}
}
const head = meta["/id/1"];// /id/1 根据请求页面动态获取
if (head) {
let headStr = ''
for (const key in head) {
headStr += key==='title'?`<title>${head[key]}</title>\n`: `<meta name="${key}" content="${head[key]}">\n`
}
//finalHtml是routes.js文件里的
if (headStr) finalHtml = finalHtml.replace(/(<head[^>]*>)(?!.*<head[^>]*>)/i, `$1\n${headStr}\n`);
}
8. uniapp-router-h5 使用了 uni.addInterceptor 拦截器。可以扩展实现路由前置守卫。
如果你也使用此拦截器造成冲突。可以将你的拦截器合并进了。也可以删除我们的拦截器 在你的代码里调用 seoHook(args.url);
uni-app HBuilder X设置
1.在uniapp设置路由mode: history
2.发布的时候设置ssr发行 (Vue3才支持)
web 目录
web是uniapp HBuilder X选择ssr发行H5项目后生成。直接复制到网站目录即可
ssr(服务器渲染)注意事项
- 不能有环境代码。详情可以看官方的说明 比如 window document
- 还有很多api不支持 比如 uni.getSystemInfoSync uni.createSelectorQuery uni.createAnimation
- 注意链接是否是onclik事件 需要使用navigator
- 如果有不兼容的代码 会node报错 不会服务器渲染 但不影响网页运行
- ssr很多代码不兼容 多到让你怀疑人生 做好心里准备。