Nuxt

ssr

前段时间主负责了一个项目,是一个官网加配置官网展示数据的管理后台,因为产品敲黑板特地的强调了官网seo的重要性,因为之前从来没做过官网,特别是强seo的网页;找前端各大佬帮忙、一起讨论后,最终采用nuxt2.x+vue2+ts技术方案。开始压力还是大大的,再踩了无数个坑之后,终于要上线了,想了想赶紧记录下来,避免以后忘记。

nuxt.config

  • mode改为’universal’。模式选择-SPA/Universal(告诉服务器为ssr渲染)

  • 由于是第三方渲染,如果使用了第三方插件,默认ssr项为true,需要手动更改。否则启动项目页面会变成 document is no defined 。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    plugins: [
    'antd-ui',
    'antv-g2plot',
    'api',
    'inject',
    'axios',
    'antd/icons',
    'vue/component',
    'vue/config'
    ].map(*fileName* *=>* {
    return {
    src: '@/plugins/' + fileName,
    ssr: false // 重点,只在client被打包引用
    }
    })
  • 在使用ssr渲染的时候如果使用的是asyncData方法,则要保存到本地,因为页面只会刷新的时候去请求接口,从客户端点击菜单路由跳转则是只读缓存的数据。(在created生命周期函数之前执行,所以拿不到this实例)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     // 如果是在首次加载首页,则从服务器读取数据。
    if (process.server) {

    }else{
    // 读取本地缓存数据
    }

    mounted() {
    // 不论是从哪里获取的数据,都再次存一遍。
    if (this.baseInfo) localStorage.setItem('baseInfo', JSON.stringify(this.baseInfo))
    }
  • 如果是使用fetch方法的话,每次进入页面都会执行这个方法,与store配合食用更佳。

缓存

在一次无聊之际我手贱狂刷新使用了ssr做的首页,突然发现与别的spa发送network请求的页面不一样,没有出现白的闪屏效果,再次感叹ssr的巅峰速度之后,快速按command+R不停刷新着,结果突然眼前一灰,出现了下图错误,然后一顿操作猛如虎排查,发现是node服务出问题了,与后端、产品、前端的小伙伴一讨论,决定采用页面缓存,减轻服务器的压力;在调研之后觉得页面缓存最适合目前我的需求,缓存时间为五分钟。

当整个页面与用户数据无关,依赖的数据基本不变的情况下,可以对整个页面做缓存,减小页面获取时间

http://cdn.ruoyao.live/life/wLu2EK4uoR.jpg

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
middleware/page-cache.js
const LRU = require('lru-cache')
d
let cachePage = new LRU({

max: 100, // 缓存队列长度

maxAge: 1000 * 60 // 缓存1分钟

})

export default function(req, res, next){

let url = req._parsedOriginalUrl

let pathname = url.pathname

// 通过路由判断,只有首页才进行缓存

if (['/home'].indexOf(pathname) > -1) {

const existsHtml = cachePage.get('homeData')

if (existsHtml) {

return res.end(existsHtml.html, 'utf-8')

} else {

res.original_end = res.end

// 重写res.end

res.end = function (data) {

if (res.statusCode === 200) {

// 设置缓存

cachePage.set('homeData', { html: data})

}

// 最终返回结果

res.original_end(data, 'utf-8')

}

}

}

next()

}
1
2
3
4
nuxt.config.js配置项修改,引入服务端中间件
serverMiddleware: [
{ path: '/home', handler: '~/middleware/page-cache.js' },
]

大坑特坑

  • 在ssr中使用vue-awesome-swiper,不能以传统方式去编写,否则是无法顺利编译成对应的html被爬虫捕捉到。

    • 以下常规写法在此场景中不适用,如果不需要被捕捉可用标签包裹:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    <swiper
    ref="mySwiper"
    :options="swiperOption"
    class="['swiper']"
    @someSwiperEvent="callback"
    >
    <swiper-slide
    v-for="(item, index) in cureentKey"
    :key="item"
    :class="['swiper-slide', { active: currentImage === index }]"
    >
    内容
    </swiper-slide>
    <div slot="button-prev" class="swiper-button-prev"></div>
    <div slot="button-next" class="swiper-button-next">

    </div>
    </swiper>
    • 以下是正确ssr写法,需要用到**v-swiper这个指令 **:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<div
v-if="bannerList && bannerList.length > 0"
ref="videoSwiper"
v-swiper:mySwiper="swiperOption"
class="swiper-no-swiping(// 此命名是为了禁止轮播图被拖拽滑动) banner"
>
<div class="swiper-wrapper">
<div
v-for="(banner, i) in bannerList"
:key="i"
class="swiper-slide"
>
内容
</div>
</div>
<div class="swiper-pagination"></div>
</div>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 轮播图参数
swiperOption = {
autoplay: {
delay: this.autoplay,
stopOnLastSlide: false,
disableOnInteraction: false // 当用户滑动图片后继续自动轮播
},
slidesPerView: 1, // 个数
loop: false, // 是否循环
btnplay: true,
pagination: {
el: '.swiper-pagination', // 与slot="pagination"处 class 一致
clickable: true, // 轮播按钮支持点击
bulletClass: 'my-bullet',
bulletActiveClass: 'my-bullet-active',
// 自定义分页器
renderBullet(index: any, className: any) {
return '<div class="' + className + '" >' + '</div>'
}
}
};