标签: ssr

  • 解决跨时区 Nuxt SSR 导致的页面离奇 Bug

    解决跨时区 Nuxt SSR 导致的页面离奇 Bug

    打开后台一看,如果本周再不写博客,就三周没更了,还是抽点时间分享点东西吧。今天结合近期解决的问题,分享一下出海服务全球用户,并且使用 SSR 时可能遇到的问题。

    问题

    我厂的 AI 日记产品 DailyLift 遇到一个非常奇怪的问题。合伙人发现,在午夜过后,打开我们的网页,界面会渲染得非常奇怪。

    这里的问题很多,不管是文字样式还是背景图案,都很奇怪,只看错误截图和代码完全没有思路。给不了解我厂产品的读者介绍一下上图中的 bug:

    1. No data 表示当天无数据,正常情况时字体很小。
    2. 只有具体的数字才应该显示成这么大的字体。
    3. 配图也不对,no data 对应的应该是其它图片。
    4. No data 自然不应该有弧形进度条。

    难以复现的 bug

    我们是远程工作,我一般会把工作时间固定在早上 9:30~晚上 6:30。当我次日开始工作,打开开发环境开始 debug,这个 bug 完全无法重现。对合伙人来说,这个 bug 也是时有时无。所以,这个 bug 在我们的任务列表里开了关关了开,反反复复,非常难搞。

    但是随着时间发展,我们还是总结了一些问题特征:

    1. 此问题只在午夜零点之后出现
    2. 此问题只在刚发布过日志之后出现(这个很关键,可惜我解决 bug 那天才发现)
    3. 此问题只在新加载页面时出现
    4. 此问题只在线上(生产 / 测试)环境中出现

    至此,我还是没有什么思路,只是觉得,可能要午夜的时候来调试一下。

    捕获 bug

    上上周,儿子考试结束,我们带他去长沙武汉各玩两天,逛街三天,赶车三次,日均 1w 步之后,我的膝盖很累。导致周三的力量举 PR 测试状态奇差,离既定目标差了一半。(感兴趣的同学可以看下:年中测试新极限,逛街三天赶车两次,状态很差,只完成目标的一边。下次继续努力吧

    晚上睡觉前,我心情比较低落,毕竟努力了半年,之前的运动表现估算起来,肯定不止这个数字。于是我就随手打开 DailyLift,写了篇日志。然后,我鬼使神差地想起这个 bug,随手刷新了一下页面,正所谓失之东隅,收之桑榆,竟然复现了这个 bug!

    简单介绍一下我们的技术选型:

    1. Nuxt
    2. Supabase
    3. 部署在 Vercel,非企业用户,只能选择特定区域,于是我们选择美西服务器

    开发环境无法复现,线上环境稳定复现。虽然表象无法推测问题所在,但也是巨大进步。我思来想去,突然想到,会不会跟服务器端渲染(SSR)有关?于是我查看源代码——注意,是源代码,不是 DOM 树;因为 DOM 树可能会被 Vue(Nuxt)修改过,不是初始状态——一看,果然,服务器端渲染的结果跟我页面的效果不一样。而这样的结果,是由于时区导致的。

    我的博客发表在 12 点之前,刷新页面在 12 点之后。如果大家观察上图,可以发现,我们是按照日期来分割数据的。我身处 +8 时区,所以我的 N 日 0 点,是 UTC N-1 日 16 点;Vercel 服务器位于美西,差不多是 -7 时区。于是,Vercel 在服务器端渲染页面的时候,他认为我的这篇日志,应该是 N-1 日 9 点钟写的,N-1 天还没结束,所以是当天(Today)的日志。 但是当我在本地运行 Vue 的时候,我已经是 N+1 日了,于是我本地的代码认为日志发表在昨天,今天还没写过日志。

    于是,Nuxt 尝试对 DOM 进行修改,但不知为何,它复用了服务器端传回来的部分 HTML,修改了部分 HTML,所以就出现了前面的 bug。

    解决 Bug

    找到问题根源之后,解决问题就没那么难了。唯一的难点就是克服测极限带来的身体疲劳,不过找到问题的兴奋感冲淡了这份疲劳。

    查阅文档之后我发现,Vercel 倒是早就帮我们准备了解决方案,我们只需要用useRequestHeader('x-vercel-ip-timezone') 就可以获取到用户所在的时区,接下来,只要保证整个 SSR 在这个时区里进行就好。

    我使用的 dayjs 来处理时间,它自带 timezone 功能,所以给所有 dayjs() 后面加上 dayjs().tz(tzHeader) 就可以。

    总结

    最后,困扰我们一个月之久的 Bug 终于解决。我也意识到处理时区在全球化应用开发时的重要性。合伙人问我有没有办法确保类似的问题不再发生,我回他:我这辈子都不会忘了处理时区了……

    希望这篇博客对你的出海应用开发有帮助。如果你对 Nuxt、服务器端渲染、云服务器等有问题,欢迎留言讨论。

  • 【视频教程】技术栈大升级:Vue3 到 Nuxt3(4)深入理解 SSR 和 `useAsyncData`

    【视频教程】技术栈大升级:Vue3 到 Nuxt3(4)深入理解 SSR 和 `useAsyncData`

    2023 年,我个人最大的变化,是从 Vue3 SPA 应用向 Nuxt3 SSR 应用过渡,在预期可能存在 SSR 需求的项目中,都尽量使用 SSR。包括 React 应用,也尽量使用 Next.js,而不是 React SPA。

    这个过程中,面临很多问题,很多思路需要转换,很多以前没关注的点需要关注。本系列视频试图快速教会大家这些要点,帮助大家顺利从 SPA 切换到 SSR。

    这次的视频更偏理论,重点讲解 Nuxt3 如何处理 useAsyncData,以及为了兼顾 SSR 和前端开发所做的渲染策略设计。这部分知识我其实很晚才掌握,因为文档里说的也不太详细;所以既是好消息也是坏消息。好消息是,哪怕你没有掌握,也不太耽误使用 Nuxt3 开发项目;坏消息是,保不齐就会遇到一些奇怪的问题,难以复现和排错。

    视频要点:

    1. 现代化 SSR 的优势
    2. 深入理解 useAsyncData
    3. 使用 Pinia 传递数据
    4. 理解生命周期钩子变化

    如果你对 Vue3 开发、Nuxt3 开发、SSR 感兴趣,欢迎关注我的本系列。如果你对这些话题有疑问,欢迎留言讨论。

  • 【视频教程】技术栈大升级:Vue3 到 Nuxt3(2-3)升级实战 – 基础知识,适配 SSR,页面路由

    【视频教程】技术栈大升级:Vue3 到 Nuxt3(2-3)升级实战 – 基础知识,适配 SSR,页面路由

    2023 年,我个人最大的变化,是从 Vue3 SPA 应用向 Nuxt3 SSR 应用过渡,在预期可能存在 SSR 需求的项目中,都尽量使用 SSR。包括 React 应用,也尽量使用 Next.js,而不是 React SPA。

    这个过程中,面临到很多问题,很多思路需要转换,很多以前没关注的点需要关注。本系列视频试图快速教会大家这些要点,帮助大家顺利从 SPA 切换到 SSR。

    继上次的知识科普视频之后,我们开始实战。连续三次直播都比较失败,所以更新比较慢。第二期视频包含以下升级要点:

    1. 处理项目开发脚手架
    2. 迁移静态资源
    3. 修改引用地址
    4. 利用 process.client<client-only> 组件处理不能 SSR 的功能
    5. 处理 TailwindCSS
    6. 使用 useCookie 替代 localStorage

    第三期视频包含以下要点:

    1. 处理页面路由,理解页面嵌套
    2. 全局使用 css
    3. 附赠内容(拖时长):关于读源码

    后面应该还会再录制两期,分别是:服务器 API 开发;深入理解 SSR 与 useAsyncData+Pinia。

    如果你对 Vue3 开发、Nuxt3 开发、SSR 感兴趣,欢迎关注我的本系列。如果你对这些话题有疑问,欢迎留言讨论。

  • 【视频】技术栈大升级:Vue3 到 Nuxt3(1)基础知识篇

    【视频】技术栈大升级:Vue3 到 Nuxt3(1)基础知识篇

    2023 年,我个人最大的变化,是从 Vue3 SPA 应用向 Nuxt3 SSR 应用过渡,在预期可能存在 SSR 需求的项目中,都尽量使用 SSR。包括 React 应用,也尽量使用 Next.js,而不是 React SPA。

    这个过程中,面临到很多问题,很多思路需要转换,很多以前没关注的点需要关注。本系列视频试图快速教会大家这些要点,帮助大家顺利从 SPA 切换到 SSR。

    本期视频主要介绍 SSR 所需的知识和概念,为下一阶段正式重构项目做准备。

    1. 什么是 SSR?为什么要用 SSR?
    2. SSR 的一般构成
    3. Nuxt3 的 SSR 组件
    4. Nuxt3 的渲染规则与缓存处理
    5. 如何鉴别用户身份

    视频中的课件:从 SPA 到 SSR,从 Vue3 到 Nuxt3

    有任何问题、意见、建议,欢迎留言弹幕私信与我交流。如果你觉得视频对你有所帮助,还请留下宝贵的一键三连,并完播分享,谢谢。

  • SSR,云平台,ChatGPT——我的 2023 技术关键词

    SSR,云平台,ChatGPT——我的 2023 技术关键词

    前言

    2023 年,因为换工作,启动新项目等原因,我对我的技术栈进行了比较大的更新,主要集中在这三个方向:

    1. SSR(Server Side Rendering,服务器端渲染)。之前我开发的项目基本上都是 SPA(Single Page Application),比如 Vue,但之后我会越来越多开始用 Nuxt。由于基础设施的发展,以后 SSR 会更方便更好用。
    2. 云平台。以前我大概买了 3、4 台云服务器用来做各种尝试,在上面各种折腾。去年使用 Vercel、Supabase、CloudFlare 平台之后,我已经不打算再在服务器上浪费时间了,云平台实在太好用了。未来我会努力把所有服务都迁移到云平台上,新增产品都直接云原生。
    3. ChatGPT。相信不只是我,很多人都会把 ChatGPT 作为去年技术的首选关键词。如今我不仅在上面完成产品开发,日常也会使用它替代大部分的搜索;甚至我家孩子写作业也会使用它来帮忙。我认为,未来 ChatGPT 就像是搜索引擎一样,决定了一个人的起点和成长速度。

    接下来逐个分享。

    服务器端渲染,SSR

    起初我不是很看重 SSR,我总觉得,我当年也写过 PHP,有什么“服务器端渲染”我没见过?实际用过之后,我承认:真香……

    首先,使用 SSR 可以提升用户体验,且有利于 SEO,这点相信大家都知道。如果对其原理不太清楚的话,欢迎观看我的视频:从浏览器渲染机制理解 Web 性能——“在浏览器地址栏输入 URL,按下回车后会发生什么?”

    其次,如今的 SSR 与当年 PHP 模版套页面的实现有很大区别:

    1. 语言同构化:开发难度大大降低,没有心智负担。
    2. 数据传递与状态管理:虽然数据不能完全通用,但是框架尽量会帮我们处理好,让我们在服务器端和客户端都能自由使用。
    3. 渲染由边缘计算负责:这一点有点依赖云平台,不过考虑到浏览器的渲染机制,SSR 并不会拖慢渲染速度,用户体验只会更好。
    4. 页面切换不需要重新加载。对于旧的编程语言来说,因为前后端环境割裂,所以页面切换的时候都是重新加载完整页面;但是新框架下,则只需要加载数据即可,此处跟 SPA 的体验无二。

    第三,如今的 SSR 框架都很好的整合了服务器,包括中间件等功能,还有各种官方第三方模块支持,能大大降低我们开发服务器软件的成本。所以已经是我启动新项目的不二之选。

    云平台

    以前我长期维护好几台服务器,一方面可以部署自己做的产品 demo,另一方面也可以部署一些开源项目方便日常使用。因为各种云都有面向新用户的优惠活动,所以成本不高,我觉得值得一搞。

    自己的服务器当然比较比较自由,坏处就是免不了产生运维成本,即使使用 docker 也一样。部署新代码至少要去跑一遍拉取脚本,对吧?我的一位老板朋友甚至请我帮忙写了一套服务器脚本,用来做 CI/CD。

    初期这么搞没问题,但后来就越来越觉得功能不够,性价比也太低,开始寻求替代方案。之前我参加 Hackathon 的时候了解到 Vercel 云平台。它与 GitHub Pages 不同,支持 SSR、支持云函数,配合一些云数据库,比如 Upstash,可以快速搭建起来一套可用的服务。去年年初,我的那位老板朋友想做一套打分系统,放在他的静态网站里,于是,我就尝试用 Nuxt.js + Upstash 开发了一套,并且部署在 Vercel 上,效果非常好,免运维,多环境,推到 GitHub 自动部署,实在太好用。

    我把这个过程制作成了系列课程:Nuxt3+Vercel+Serverless 数据库全栈开发。大家感兴趣不妨看一看。

    后面一发不可收拾,过去一年我不再采购新的单体服务器,旧的服务器用完也不再续费。新产品都部署在 Vercel 等云平台上面,帮我节省了大量的时间。

    Vercel 去年年中的时候开通了存储功能,实际上就是打包了几家云数据库服务来卖,我也很快获准开通。从此,云平台使用就更加顺利了。临近年底,我尝试 CloudFlare Pages,效果也非常好。他们家的优势是自带统计分析功能,远比 Vercel 大方,一站式解决更省心。

    云数据库方面,我使用 Upstash 的 Redis,KV 数据库足以满足大部分产品需求。数据库用 Supabase 和 TiDB 比较多。前者支持 PG Vector,方便我们进行 LLM Embedding & Search;后者则提供 5GB 免费额度,比较好用。云存储有 CF 的 R2,空间和流量也相当充足。如果不是 PHP 太老没人支持,我都想把博客这台机器退掉了。

    ChatGPT,以及其它

    ChatGPT 更是值得大书特书的一个技术关键词。不过考虑到大家去年一整年应该已经被类似的内容淹没了,所以我这里就少写一些,只说说我的情况。

    我目前订阅了 ChatGPT+,方法是借用国外亲戚的手机号注册,并且用他的手机号注册 PayPal,通过 Google Play 订阅。订阅的原因是 ChatGPT 4 + DALL-E 都可以随便用,比 API 便宜得多。

    在编程领域,GPT-4 比 GPT-3.5 好太多了,知识库更新到去年 4 月份之后,除了 next.js 14 的内容外,我日常的编程问题大多可以用 GPT-4 解决,比如:

    • 写正则
    • 写 SQL
    • 查函数、查第三方库
    • 纠正函数错误

    帮我节省了大量的 Google 时间,单凭这点,每月 $19.99 的订阅费用就很值得。

    除此之外,我还在继续使用 GitHub Copilot。Copilot 也很好用,除了生成工具函数、编写测试外,我发现翻译语言和框架方面也有很大的作用。去年我就完全靠它开发了一个 flutter 应用,方法就是把 TS+Vue 写好的代码丢给它让它翻译。

    所以,无论是学习新东西,保障日常开发,还是扩展新领域,AI 对我都帮助巨大。

    总结

    总而言之,如果再有同学问,前端想学后端,应用学什么语言框架以及是否需要搭自己的服务器?我都会建议他们:不要学 Express、Koa;习惯用 Vue 就学 Nuxt,习惯用 React 就学 Next.js;不需要搭建服务器,就用云存储就能解决绝大多数问题。

    我还建议大家,尽快想办法开通 ChatGPT,再不济国产大模型也要用起来,未来是 AI 的时代,学会用 AI,效率会大幅度提升。半年的初入门新人,善用 AI 可以赶上 3 年的老程序员;而老程序员学会用 AI 之后,可以快速把自己的能力扩展到其它领域。

    以上,就是我去年关键的技术栈总结,希望对大家有所帮助。如果大家有什么意见建议,想说的想聊的,欢迎留言。

  • Nuxt3 如何传递 Token

    Nuxt3 如何传递 Token

    昨天我在思否上看到这个问题:nuxt3 请求 token 要怎么传?我之前也被这个问题困扰过,我猜测不少刚刚从 Vue3(SPA) 转向 Nuxt3(SSR) 开发的同学也会受困于这个问题,所以就把答案扩展一下,写成博文,分享给大家。

    Vue3(SPA)里使用 Token

    在 Vue3 开发的单页应用(Single Page Applicati,SPA)里使用 Token 比较简单。一般来说,我们会在项目初始化的时候读取 localStorage,拿到标记用户身份的 token,然后放到内存当中,在请求时放到 header 里面发出。如果找不到 token,就认为用户没有登录,那么就通过路由将用户指引到登录页,或者不需要登录也能看的页面。

    使用 Token 可以避免 CSRF 攻击,因为从外部网站无法同时满足访问 localStorage,和将信息放入 http header 这两个条件。所以在单页应用里,使用 token 验证用户身份非常常见,有着各种开源、强壮、高效的实现。

    这个过程相信做过 SPA 的同学都很熟悉,不多说了。

    Nuxt3 请求的特点

    从 Vue3(SPA) 到 Nuxt3(SSR),主要涉及一个思路的转换。

    在 Vue(SPA)里,所有请求都是  请求,即完成网页加载、JS 执行完毕后,再发起请求。这些请求,有以下特点:

    1. 可以认为完全由开发者控制,即开发者确定请求发起的条件,然后在基本确定的时候发起请求。
    2. 这些请求大部分只请求数据,且有明显的特征,比如 HTTP Header 里包含 Authorization
    3. 这些请求里基本不包含静态资源。

    在 Nuxt 里,因为 SSR 的存在,所以请求至少可以分成两类:

    1. 数据交互类,跟 SPA 里基本一致。
    2. 页面渲染类,SSR 核心所在。

    后者最大的变化是:它会影响到 HTML 的内容,而通常来说,HTML 会被视作静态资源。我们知道,在网络环境里,存在大量缓存节点,假如跟用户相关的敏感数据渲染成 HTML,缓存到 CDN 当中,会是非常严重的安全问题。所以 Nuxt 在 SSR 时,不会携带 cookie;只有当页面渲染完成,由于用户操作而主动发起的请求里,才会携带 cookie。

    怎么识别 SSR 请求

    Nuxt2 时期,使用 Option API 的时候,有一个很明确的 asyncData() 函数,它会在 SSR 阶段被调用,发起请求获取数据。

    Nuxt3 时期,Composition API 会稍嫌模糊一些。这个时候,整个 setup() 函数都会在 SSR 期间执行,而 useFetchuseAsyncData 则负责在这个阶段发起请求,获取数据。因为这个阶段是在服务器的 node.js 环境里执行的,所以自然无法使用用户的 localStorage,也无法使用用户本地存储的 token。

    但是因为打开网页的请求是由用户发起的,所以其实用户有把自己的 cookie 发给服务器。如果我们希望 SSR 阶段用 cookie 鉴别用户身份,可以手动将 cookie 放在 useFetchuseAsyncData 产生的请求当中,参考 官方文档 useRequestHeaders

    基本上,假如我们不了解 Nuxt3 的设计思路,简单看了眼文档就上手写代码,大概率所有页面数据相关的请求都会是 SSR 请求。至少我是如此。

    使用 server: false 仅在网页里发起请求

    当然,Nuxt3 提供了只在网页里发起请求的方法,也就是基本等效于我们之前在 SPA 里发起请求的方法,那就是在 useFetchoptions 里标记 server: false

    const { pending, data: posts } = useFetch('/api/comments', {
    server: false
    })

    再演示个更扣题的方式

    const { pending, data: posts } = useAsyncData(
    'posts',
    async () => {
    const token = localStorage.getItem('token');
    const data = await $fetch('/api/comments', {
    headers: {
    Authorization: `Bearer ${token}`,
    },
    });
    return data;
    },
    {
    server: false,
    }
    );

    (代码高亮插件还是崩的,大家凑合看,等我回头修……)

    详情请看 官方文档

    这样的请求就会在页面完成渲染后,才会发起请求。在这些请求里,如果需要使用 token,就按照以往的方式使用,即可。

    server: falselazy: true 的区别

    如果大家仔细看 Nuxt3 官方文档,会发现还有一个参数:lazy: true,以及两个语法糖函数:useLazyFetchuseLazyAsyncData

    这两个函数也是先加载页面,再加载数据。它们与 server: false 的区别在于,后者是把全部请求都放在网页端进行;而 lazy: true 则只在网页跳转的时候起作用。

    不使用 lazy: true 的情况下,当我们从 A 页面进入 B 页面时,如果 B 页面里需要加载数据,Nuxt3 就会等待数据加载完成之后,再进行页面渲染。如果你使用一个比较慢的网络,页面切换就会卡卡的,体验非常明显。

    如果使用 lazy: true,页面切换一下就完成了,但是数据可能还没加载到,此时我们需要手动处理加载状态。比如放个转转的菊花在页面中间。但是如果我们直接打开 B 页面,Nuxt3 还是会先把数据请求回来,完成页面渲染,然后呈现完整的 HTML 给我们,这样可以确保 SEO 效果。

    server: false,则会彻底放弃这部分数据的 SSR,对于用户身份相关的数据,就比较合适。

    总结

    其实就跟当年从前端学 Node.js 一样,新技术最大的挑战在于:使用场景不同、运行环境不同,思路需要很大变化,需要不同的理解,不能照搬以前的做法。

    Nuxt3 涉及到网页渲染,涉及到网络链路上的缓存层,为了防止出现信息泄漏,它会主动放弃一些数据传输。同时,由于它的一部分运行环境在服务器上,所以有一些用户数据它没法使用。于是在开发 Nuxt3 应用的时候,我们必须搞清楚这些变化,然后作出适当的调整。

    希望上面文章对大家有所帮助。如果文中有问题,请不吝指出。如果你对 Vue3、Nuxt3 开发有兴趣,有疑问,欢迎留言评论。

  • Nuxt 3 最佳实践与常见问题

    Nuxt 3 最佳实践与常见问题

    最近比较忙,也有些犯懒,所以博客视频都没怎么更新。今天一看,竟然断更将尽一个月,那无论如何得攒点东西。就把前阶段的笔记贴出来吧,是我使用 Nuxt3 的一些经验心得,希望对大家有所帮助。

    如果大家在使用 Nuxt3 期间有经验可以分享,或者问题需要讨论,欢迎留言。

    Nuxt 3 简介

    Nuxt.js 是一个基于 Vue.js 的服务端渲染应用框架,可以帮助开发者快速构建出高性能、SEO 友好的 Web 应用。Nuxt.js 3 是该框架的最新版本,它具有更快的启动时间、更快的构建时间和更先进的开箱即用功能。

    然而,在使用 Nuxt.js 3 进行项目开发时,我遇到了不少问题。本文会记录这些问题,以及我的经验。

    最佳实践

    下面是我从之前的问题里找到的最佳实践,应该问题不大,可以照搬。

    部署

    Nuxt 3 可以直接部署在 Vercel,兼具 SEO 与高用户体验。

    Serverless function

    默认情况下 Nuxt3 /api 和渲染都走 serverless function,理论上要弱于 Edge Function。我曾试着切换到 Edge Function,服务立刻就挂了,回头找个小服务摸索一下试试看。

    目前来看效能还可以,暂时没有体感延迟。我建议大家不要强求,把切换功能留给 Nuxt 核心团队来处理吧。

    加载远程数据

    SSR

    使用 useFetchuseAsyncData,Nuxt 会先加载远程数据,然后渲染页面,再进行页面的跳转。

    注意:SSR 阶段,组件发出的请求不会携带 cookie,这个设计是有意为之,避免个性化数据错误的出现在缓存层里面。如果希望 SSR 中包含个性化数据,可以手动操作,但请务必小心,不要泄漏不必要的请求头,因为可能带来安全隐患。

    具体做法可以参考官方文档:Passing Headers and cookies

    先跳转,再加载

    使用 useLazyFetchuseLazyAsyncData,Nuxt 不会等待请求完成,它会先渲染页面并跳转,然后在数据加载完成之后,更新视图。

    平时加载数据

    如果我们要像平时使用 Vue 那样加载数据并渲染,最好使用 $fetch

    使用 pendingrefresh 等复用请求代码

    比如页面里我们远程加载了一个对象,然后接下来,我们要重新加载这个对象,或者我们要根据某个参数加载别的对象,就可以利用 useFetchuseAsyncData 等返回的 pending 来渲染状态,或者用 refresh 重新发起请求,复用请求代码。

    尽量使用 default() 返回默认值

    很多时候我们远程加载的数据不是简单对象(文本、数字等),而是某个比较复杂的对象,比如一篇文章、一组人员数据。通常来说组件里的模版就负责渲染这组数据,如果不返回默认值,渲染可能会出错,可能导致页面跳转失败。

    所以我建议大家尽量返回默认值。

    配置 routes

    Nuxt 默认会对每个页面进行服务器端渲染,但很多时候我们并不需要,比如各种后台页面。所以我建议项目起始阶段就把各页面的渲染策略制定好。

    参考文档:Rendering Modes · Nuxt Concepts对首页、关于我们之类的纯静态页面,可以启用预渲染(preredering);对后台页面,就禁用 ssr;等。

    但是,大家也要小心错误的缓存机制,可能会把不应该缓存的页面缓存下来,造成渲染出错。

    使用 localStorage

    我们知道,Nuxt3 最大的特性就是 SSR,它会在服务器端渲染完页面,再返回给客户端。而 localStorage 顾名思义,只存在于用户本地,服务器端并不知道它的存在,也无法使用。所以如果我们要像平时那样使用 localStorage,我们必须控制好只在用户本地使用。如果要在 Nuxt3 里读取 localStorage 里的数据,我建议在 layout 里进行。经我测试,这是我们最初能插入 JS 的位置。

    // <script setup>
    import useStore from '~/store';
    
    const store = useStore();
    // 只有在客户端的时候才执行
    if (process.client) {
      store.init();
    }

    已有解,寻求最优解

    接下来的问题,我的方案能解决,但我不确定是否是最好的方案。所以我也在寻找更好的做法。

    1. useAsyncData 难以打断点

    问题

    useAsyncData 会在服务器端执行,所以在 Devtools 里打断点可能拦截不到。

    解法

    我目前的解法是在里面插入 console.log() ,利用热更新,切换页面,让断点生效。

    2. onBeforeMount 读取 localStorage 会丢失响应式

    版本

    v3.4(新版本待测试)

    问题

    非常诡异。

    我有一个变量 myRate ,因为一些理由,所以要把数据存在 localStorage 。我们知道 nuxt 在服务器端渲染的时候没有 window 对象,所以我就把它放在 onBeforeMount 。

    但是这样就会导致 myRate 丢失响应式,且只在 input className 丢失,非常诡异。

    解决

    我暂时放在 onMounted,虽然会造成页面抖动,但是工作正常。

    问题

    页面中有一个 nuxt-link 生成的 <a> ,点击无效,没有报错,浏览器和开发环境均无报错。

    解决

    实际上是 Vue 模版中某个变量名拼错了,渲染失败。但是不知道为何没有错误信息。找到并修正后,使用正常。

    暂时无解

    使用 route.hash 加载数据的话,SSR 会缺少数据

    当我们请求包含 hash 的地址,route.hash 在服务器端可能为空,导致无法正常启动服务器端渲染。请求会在渲染后再发出,造成界面抖动 CLS。

    解决方案就是不要用 hash 作为数据标记。

    @nuxtjs/i18n no_prefix 策略下,无法 SSR

    版本

    Nuxt@3.5 + @nuxtjs/i18n@8.0.0-beta.12

    问题

    1. 使用 no_prefix 策略
    2. detectBrowserLanguage: false
    3. 没有 SSR,渲染出来的是 key,然后变成目标语言

    Tips

    GET 请求里不能包含 body,否则可能 405

    如果用 useFetch 发起的 GET 请求包含 body/server/api 的接口会报告 405 Method Not Allowed 错误。

    这个问题主要不好排查。


    总结

    开始用 Nuxt 的时候,我没想到会有这么多问题:不就是提前渲染一下模版嘛,能麻烦到哪儿去?实际操作之后,发现很多熟悉的操作都不好处理,比如从 localStorage 里面取数据然后渲染到页面去,就要区分函数执行环境,否则就会报错;要渲染用户相关数据,得考虑服务器运行环境的复杂性,包括网络和多层缓存,不能想当然的使用 cookie 与 token。

    总之,心怀敬畏,持续学习,多看文档。有问题,欢迎提问;有建议,欢迎指教。大家一起进步。

  • 【视频】Nuxt3+Vercel+Serverless 全栈开发(4):投票接口+数据处理+了解服务器端渲染

    【视频】Nuxt3+Vercel+Serverless 全栈开发(4):投票接口+数据处理+了解服务器端渲染

    课程继续。仍然结合近期的开发经验,分享最近我比较喜欢的全栈+高效+免费+云原生技术方案。

    本次课程内容:

    • 创建 Post 接口,完成投票
    • 显示投票结果数据
    • 了解服务器端渲染

    我们先利用 Nuxt3 的路由机制,创建 /api/rate.post.ts 接口,用来处理用户投票,将数据记录进入 Redis 数据库的动作。

    为了保证数据安全,我每次会写入两次数据,一个键值是 $$$_{uid},主 key,用来日常显示;另一个键值是 {uid}_{小时},用来备份。这样假如某些情况下我们的投票系统被攻击,也能快速会滚到最近一小时的数据。并且这个备份频率也可以按需调整。

    然后我们在前端使用 $fetch 方法调用接口完成投票。并介绍了计算成绩的逻辑。

    最后介绍了 SSR 的结果,这样就能解释,为什么我们要使用 Nuxt3 内建的 useAsyncDatauseFetch 而不是平时常见的远程请求库手动请求。

    这期视频也剪得很细,还做了字幕,希望大家能学到东西。

    如果你有任何问题、建议,欢迎留言讨论。请 b 站有号的同学帮忙分享完播一键三连,谢谢大家。

    另外,我也在 YouTube 上上传了一份,大家有空的话,麻烦帮忙关注下我的油管频道,感谢感谢。肉山全栈小课堂 – YouTube

  • 【视频】Nuxt3+Vercel+Serverless 全栈开发(3):实现投票效果,使用 Redis

    【视频】Nuxt3+Vercel+Serverless 全栈开发(3):实现投票效果,使用 Redis

    课程继续。仍然结合近期的开发经验,分享最近我比较喜欢的全栈+高效+免费+云原生技术方案。

    本次课程内容:

    • CSS 里使用 ~ 兄弟选择器实现投票效果
    • 使用 Upstash Redis
    • 使用 Nuxt3 风格的加载方法读取数据

    打分组件,我们需要用到 ~ 选择器选择某个节点后面的所有弟弟节点,配合蒙版属性 mask-* 可以实现我们要的打分效果。

    接下来我们开始接触远程数据的操作。Vercel 免费版 Redis 每天只有 1k 的请求数,不太够用;如果升级付费版,也没法针对某个部分单独升级。所以很明显,Upstash 这样专门的服务商更合适。

    Nuxt3 为实现 SSR,对远程请求进行了封装,提供 useFetchuseLazyFetchuseAsyncDatauseLazyAsyncData 这 4 个新方法。其中前两者可以视作后两者的封装。在本节课里,我们先实现了读取数据的 API,然后用 useFetch 加载数据,实现服务器端渲染。

    这期视频也剪得很细,还做了字幕,希望大家能学到东西。

    如果你有任何问题、建议,欢迎留言讨论。请 b 站有号的同学帮忙分享完播一键三连,谢谢大家。

    另外,我也在 YouTube 上上传了一份,大家有空的话,麻烦帮忙关注下我的油管频道,感谢感谢。肉山全栈小课堂 – YouTube