如何把控全站静态,比较一下nuxt3 和 vite-plugin-ssr

 本人一向从事后端开发,这几天心血来潮也研究下前端,寻思着用后端写API+前端Vue调用的模式来生成静态化网站,也就是现在都流行的前后端完全分离。同时要兼顾SEO的要求。

参考:服务端渲染 (SSR) | Vue.jsVue.js - 渐进式的 JavaScript 框架https://cn.vuejs.org/guide/scaling-up/ssr.html#higher-level-solutions

一般都会借助Node.js来服务器渲染 ,关于Vue的服务端渲染SSR上面官方网页列出了三种方案:第一个就是大名鼎鼎的Nuxt,第二个Quasar,第三个才是自荐vite自己,而且也推荐使用vite-plugin-ssr。vite-plugin-ssrhttps://vite-plugin-ssr.com/

既然排首位的是nuxt,就先研究这个。看到nuxt3已经是正式发布版本了,应该是能拿来就用了 。而且国内有不少网站采用的就是nuxt,说明在国内还是比较流行的。

具体的配置什么的就不讲了,nuxt3是开箱即用型的,约定也大于配置的,几乎不用怎么配置就满足正常需要,自动引入、自动路由规则,确实写代码起来方便多了。兴高采烈的摸索着写了几个页面,有一个页面是请求接口来渲染的,使用官方文档中useAsyncData来获取数据。尝试着用nuxt build,接下来用nuxt generate来生成完全静态站点。结果发现nuxt能够自动请求接口,将接口内容下载下来渲染成HTML中的内容,利于搜索引擎抓取。但同时发现nuxt非常明显的缺陷,那就是对请求的接口竟然是公开的!如果用nuxt-link来导航网站中的页面,而此页面用到了useFetch或useAsyncData等方法,那请求接口就暴露出来了。

请求nuxt生成的静态页面(SSG)的异样

第一次打开页面(其中包含接口请求代码),就直接返回服务端渲染出来的静态HTML,不会去请求接口。但其代码中竟然包含

<link rel="preload" as="fetch" crossorigin="anonymous" href="/mountains/aconcagua/_payload.json">

也就是说此页面生成时服务端请求的接口内容保存在了_payload.json中,而且暴露给了客户端(浏览器),非常讨人厌,我都生成静态页面了,干么要保存这个?

接着呢,如果页面中含用<nuxt-link to="/mountains/aconcagua">指向这个页面,那么其实浏览器跳转时并不是完全重新请求页面,而是对指定区域重新渲染,此时去请求的就是上面的_payload.json(如果是nuxt build,也即SSR模式),那么其实客户端请求的是真实接口(浏览器请求明显的暴露此接口URL)!翻阅整个nuxt3的文档,不能完全做到由服务端渲染而不暴露接口和接口内容。

以上就明白,nuxt3就是个巨坑啊!nuxt2估计也大体差不多如此。

由此可以清楚了:nuxt3虽然可以SSG生成全静态页面,但对于内部请求接口的内容会直接保存成json,从而暴露接口的原始内容!甚至SSR时请求的接口还是原始接口,并且是由客户端去请求而不是服务端(可能是考虑到服务端压力大吧),从而暴露接口的URL。

因此可以这么说,如果对接口不在乎的话,那用nuxt3生成静态站点没什么关系。但是想一想,如果我要生成几万个页面的静态站点,那么nuxt3就是一个巨坑了,首先静态HTML和JSON文件保存了两份数据,造成了严重浪费。其次,接口内容暴露出去,那么不怀好意的人直接找你的json文件就能轻而易举的把你的内容抓去了。

有人会这要说了,既然只是_payload.json的问题,那就干掉它,可以在nuxt.config.ts 指定

export default defineNuxtConfig({
  experimental: {
    payloadExtraction: true
  }
})

那么在npm run generate时便不会生成_payload.json了嘛,岂不是完美解决了上面说的接口暴露问题了吗?

然而,事实上如果这样做的话,假若使用nuxt-link来导向此页面,你会发现这个页面的接口请求已经不是去请求_payload.json的数据(因为它已经没有了),而是去请求原始地址了!于是接口地址再一次暴露了!!!

那又有人会说了,既然nuxt-link标签导航会产生负作用,那我就不用它了,就只用<a>标签,那不就没事了吗?诚然从页面请示中会看到,确实没有再去请求原始接口地址了,但巨坑在后面:

而事实上去看一下生成的js文件,就有很清楚地把接口地址写在js文件中的代码。

所以这样做其实更加令人郁闷,让客户端去请求本不想暴露的接口,且完全暴露接口地址。

也就是说在nuxt3中,我不过是想要求服务端来请求接口获得数据,你只负责渲染出来,不让客户端知道这数据从哪里来,获得的数据具体又是什么,而nuxt3做不到!

这就完全失去了SSG的意义,没法把控接口请求的安全性。只适合接口本来就想暴露的场景!

所以我觉得nuxt3的思路还是停留在不停ajax请求数据的思维,而忘了本身静态站点的意义。

诚然如果只是想做对接口不敏感的站点,它确实比原生的vue3顺手些。假若nuxt能够改进这点就更好了,然而现在还没有。希望后面的版本能够做到这一点吧。


那么我再看一下vite-plugin-ssr,其实这个像极了next.js,连文档结构都几乎差不多,只不过next.js是只支持react,而vite-plugin-ssr基本不依赖前端框架,vue/react 通通支持。vite-plugin-ssr对页面渲染的把控就高多了,基于vite就充分利用vite的特性。

vite-plugin-ssr(以下简称vps吧)这个上手确实比nuxt要慢些,官方文档里就明确说了:

 

万事开头难

在 vite-plugin-ssr 中,你需要自己集成工具链。 这通常意味着更多的工作量和一些难度,上手可能会慢一些。

但是像 Next.js/Nuxt 这样的黑盒框架限制了解决方案。到最后,你会浪费时间在与框架斗争上

相比之下, vite-plugin-ssr 是透明的:它不会妨碍你集成任何工具,只需遵循该工具的官方安装指南即可

简言之:vite-plugin-ssr 可能没那么容易,但是更简单

 

上文中nuxt的场景,vps是如何解决的呢。因vps是可以分别定义服务端js和客户端js的。

在 *.page.server.js 就可以负责获取接口数据。在onBeforeRender函数中请求接口获得数据,然后传给客户端*.page.client.js 。它的好处是接口请求对用户端来说是完全不可见的。然后在生成之后,也不会去请求接口了,完全静态化。

缺点是,接口获取到的内容还是会写在生成的HTML中的,放在了 <script id="vite-plugin-ssr_pageContext" type="application/json"> 。所以这也会有一个问题产生,也就是内容重复,接口内容以javascript代码的json模式直接写在html页面中。但是在gzip模式下,重复内容多,压缩下来其实占用网络流量还是增加不了多少的。不过试想一下,如果能将这个接口内容给干掉(不暴露出来)岂不是更好吗?因为纯HTML页面用不上呀,目前本人还在研究如何去做这个事情。或许有更好的解决方案了,但是本人还没找到……

顺带提一下预渲染必须开启这个:

import vue from '@vitejs/plugin-vue'
import ssr from 'vite-plugin-ssr/plugin'

export default {
    plugins: [vue(), ssr({
        //开启预渲染
        prerender: true
    })
    ]
}

开启了预渲染之后,意味着最终生成的是全静态页面,随便部署到一个静态服务器即可。如果是对有通配符的路由页面如/pages/movie/@movieId,则必须要在*.page.server.js 手工指定 prerender 函数,此函数需要返回所有预渲染URL。

否则会出现报警告了:

 [vite-plugin-ssr][Warning] Cannot pre-render page `/pages/movie/@movieId/index.page.*` because it has a non-static route, and no onBeforePrerenderStart() hook returned (an) URL(s) matching the page's route. Either use a onBeforePrerenderStart() hook to pre-render the page, or use the option `prerender.partial` to suppress this warning, see https://vite-plugin-ssr.com/prerender-config
 

所以这一步比较麻烦,比不上nuxt的自动化。但这也提供了灵活性,能够把控哪些页面要渲染,哪里不渲染(不渲染的自然还是需要交由服务器处理,部署时还是需要node.js服务,不过渲染过的部分能够减轻服务器的负担)。

采用npm run prod 之后,就可以看到并运行生成的静态站点了。检查生成的HTML和JS,完全看不到原始接口地址。


综上所述,Nuxt无论何种方式,都会暴露出原始接口请求地址。而vps能够完全把控接口请求只在服务端,做到不暴露。这一点大大加强了接口的安全性。这是Nuxt最大的坑了。

nuxt的开箱即用带来很大便利,vps需要自己装配想要的东西,上手门槛较高。


后续想法:

前后数据分离这是一种趋势,单页面无关SEO,包括SSR,算是比较成熟,但我看到其实现在将其完全静态化的生成方案都还是在发展阶段,并没有非常完美的方案,前端技术一直改动较大。诸如vps这种中间件似的产品应该尽快完善,能够达到高可自定义化以及多一些自动化才算完善啊。

 

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值