前记
当接到领导说某某“seo精鲤”(实际上只会搞搞百度推广,连代码都不会写的)要将之前开发好的h5商城适应seo,心里顿时一万只草泥马在奔腾,因为我知道接下来绝B很多坑在等着我去踩。没办法,生活在底层的技术开发为了苟且也只能将这口气憋回去,硬着头皮,一个字,就是干。
技术选型
vue、react等新技术的确是香,这点不能反驳,但在首屏加载和seo上还得另外做优化。如果自己动手做一套服务端渲染还得对node比较熟悉,技术难度上上升了一个量级,而且在时间成本上也会相对应要花费不少精力。像这种开发完的项目再做seo优化的话,一般是建议在不动代码的前提下解决是最好的方案。于是乎,我便一波在网上找解决方案啊,发现自己搭建个服务器借用phanthom.js
在nginx
上做文章,识别爬虫的标识然后将提前渲染好的页面给它爬,正常的用户还是走vue spa页面。这个的确是个可行的方案,我也在测试服务器上试过了,但发现这库竟然没在维护了,然后换成了popputter
,这个是谷歌公司在维护的一个库,实际上是开启一个无头浏览器可进行自动化测试和爬虫,于是,我又一顿写代码参照第一种方案的思路确实能将vue动态页面转为静态化渲染的页面。但这两种方案对于百度蜘蛛都存在着欺骗性,领导和精鲤怕被降权,所以还是被pass掉了(不过这两种方案我是建议可以试试的)这两种对于我们开发来说最轻松的方案。那没办法了,只能上nuxt了。具体环境搭建和部署可参考我之前写的一篇博客nuxt环境搭建部署, 这里就不作过多的阐述。
技术实现
-
工程目录结构
在这个重构项目中我想尽量保持原有工程项目结构不受太大的变化,因为在nuxt默认的脚手架搭建的项目中,路由是自动生成的,而vue项目中是有路由配置文件的。
在nuxt.config.js
指定下源码目录:
module.exports = {
srcDir: 'src/'
}
-
路由配置
在github找到了nuxt社区提供的router-module
可以改写nuxt默认的有page页面组件生成的路由,但项目中组件代码你不能再放在page文件夹下,这里你只需要安装@nuxtjs/router
npm i --save-dev @nuxtjs/router
, 然后再srcDir
目录中新建一个router.js
文件,并在nuxt.config.js
配置文件中module
属性中配置
module.exports = {
modules: [
'@nuxtjs/router'
]
}
但这里示例中直接是直接通过import方式变量引入(非懒加载模式),当组件多的时候会引发性能问题,因为需要采取路由懒加载方式引入。但如果你直接采用vue-router官方提供的
const Index = import('@/views/Index.vue')
或者webpack的require.ensure
{
path: '/home', name: 'home',
component: r =>require.ensure([], () => r(require('@/components/home')), 'demo')
}
再或者是vue异步组件方式
{
path: '/path',
name: 'componentName',
component: resolve => require(['@/componentPath'], resolve),
}
都会触发nuxt报错
我最终在社区中找到了
{
path: '/index',
name: 'Index',
component: () => import('@/views/index').then(m => m.default || m )
}
解决了nuxt自定义路由懒加载的方法。
-
路由钩子
在这里对于路由钩子的前卫和后卫控制,我是写在了plugins
中,因为根据nuxt提供的生命周期我们知道在发生nuxt-link
路由改变时是先加载plugins的,而且在pugins中可以拿到router的实例。
router-guards.js
export default async function ({app, router, redirect}){
app.router.beforeEach((to, from, next) => {
...
})
app.router.afterEach((to, from, next) => {
...
})
}
性能优化
在刚转为nuxt框架时,因路由不是按照nuxt中page文件夹自动生成路由的规则,导致项目首屏渲染和路由切换耗时长,performance下分析主要是js文件parse消耗时间长,我通过脚本nuxt build -a 分析包的大小情况。得出路由未采取懒加载导致进入首页时将整个项目的路由都加载完才执行,这显然是不合理的严重影响性能,于是乎,我采取了上面提到的懒加载方式解决了路由的包文件过大问题。
另外就是引入了大多npm第三方包,其中math.js这个包没有按需加载,导致将全部函数引入包大小也很大,可通过按需加载import { bigNumber , add ,subtract, divide, multiply } from 'mathjs'
还有一些vue-awesome-swiper ,html2canvas等第三方包建议可通过cdn引入,ui框架如element-ui ,vant-ui,iview等可通过按需加载引入。
深坑
- 我这边代码用相对路径访问static文件夹时缺找不到文件,所以我将其放进了src下,
时,得使用绝对路径访问。不过也没问题,nuxt会自动默认去访问static文件下的文件 - vux-ui库不是所有组件支持ssr,所以引用其组件会引发报错You may need an additional loader to handle the result of these loaders.,在github vux库上说要配置vux-loader
但是发现配了之后还是然并卵,之后直接抛弃用了有赞开源的vant-ui,支持ssr。 - 当你的组件中用了大量的v-if会导致nuxt ssr渲染时由于客户端和服务端渲染不匹配导致客户端报错Failed to execute 'appendChild' on 'Node': This node type does not support this method导致页面卡顿.这里在github中找到了用
v-show
替换v-if
,并且可以用nuxt官方提供的<client-only>
标签让其只在客户端渲染来解决这个问题。 - windows、document等引发的问题区分环境就好
if(process.browser){...}
,之前在main.js中的vue全局方法和组件可以通过plugins
中引入
后记
代码重构之路到此告一段落,为了seo收录量后续重点工作将要对url规则优化,采用伪静态化处理。鄙人才疏学浅,有什么不对的地方,欢迎批评指正。