React笔记五:使用Next.js实现React SSR的优雅降级

前言

React SSR最成熟的开源框架是Next.js,这么多年保持着强劲的生命力,它的创始团队vercel(曾用名zeit),如今更关注于SSR和serverless的结合。随着服务端的容器化技术以及serverless技术不断完善,在国外可能SSR的降级已经不是一个必要命题。但是,考虑到国内的服务环境,今天我们还是有必要从前端的技术点讨论一下如何去实现SSR的优雅降级。

旧版本的Next.js是利用getInitProps实现服务端渲染以及静态站点生成。在Next.js 9.3版本后,getInitProps这个api被替换成为三个不同的api,分别是:

  • getStaticProps (静态页面生成SSG): 构建的时候生成页面
  • getStaticPaths (静态页面生成SSG): 根据构建内容去生成动态路由
  • getServerSideProps (服务端渲染SSR): 在每个请求中在服务端获取数据渲染页面

这三个api的使用是对一个项目中不同页面的更细程度的划分,它可以有效区分哪些页面走SSR、哪些页面走CSR和SSG。高效的划分了这三种不同的渲染模式。

What is JAMstack ?

静态页面生成SSG这种模式更加符合JAMstack的标准,所有的页面都是提前预渲染的,静态的页面可以直接托管在CDN上,有效降低运维成本,有助于你“高效下班”。Next.js官方建议你优先使用静态页面生成,不得已才使用服务端渲染。但是静态页面不能满足你的所有case。只有以下情况才比较适合静态页面生成:

  • 数据能通过CMS接口有效渲染
  • 数据能够公开缓存,并且不能用户特有的
  • 页面必须预渲染,并且SEO敏感

Next.js已经能够在一个项目不同路由支持不同的渲染模式。

源码参考 brandonxiang/example-nextjs ,页面的逻辑放在modules文件夹里面,用一个自定义的函数getPrerenderProps来保证页面的预渲染逻辑。这个预渲染逻辑如下,即获取数据传递到组件当中与Next.js的预渲染api类似。

// modules/Home.tsx
export const getPrerenderProps =  async (ctx) => {
  // SSG读取环境变量,并作为兜底参数
  const defaultLimits =  process.env.limits || 0;
  // SSR和CSR动态渲染从URL上获取参数
  const _limits =  (ctx?.query?._limits) || defaultLimits;
  // 获取远程动态数据
  const res = await axios.get(
   'https://jsonplaceholder.typicode.com/photos?_limit=' + _limits
  )
  // 传递给各种渲染模式
  return { props: { photos: res.data } }
}

自定义页面渲染函数Page来保证页面dom的渲染,这里的目标是“一份核心代码,多种渲染模式”。数据photos则会在页面中渲染。

// modules/Home.tsx
function Home({ photos }) {
  let _photos =  photos || []
  return (
    <div className="photos">
      {
        _photos.map((photo, index) => (
          <figure key={index}>
            <img src={photo.thumbnailUrl} alt={photo.title} />
            <figcaption>{photo.title}</figcaption>
          </figure>
        ))
      }
    </div>
  )
}

export const Page = Home;

然后将它渲染到三种不同的模式当中。由于 Next.js 的文件路由设定,页面需要被设置成为三种:

  • index.js SSR模式
  • index_ssg.js SSG模式
  • index_csr.js CSR模式

Next.js如何实现SSR

SSR模式需要将自定义的getPrerenderProps 输出到页面级别Next.js API的getServerSideProps当中,获取数据的逻辑将会提前在服务端完成。此时,服务端可以实现页面的动态渲染。Page则返回给整个页面的渲染函数。

// index.js
export { 
  Page as default, 
  getPrerenderProps as getServerSideProps 
} from '../modules/Home';

Next.js如何实现CSR

CSR模式则是自定义的getPrerenderProps 在useEffect中渲染,在页面加载之后,重新对页面进行渲染,达到一个客户端渲染的效果。路由参数发生变化,页面会重新进行渲染,保证的页面的动态可用。这种模式页面的渲染会比较慢,时长主要是请求时长。

// index_csr.js
export default () => {
    const router = useRouter();
    const [extraProps, setExtraProps] = useState({});

    useEffect(() => {
        getPrerenderProps(router).then(({props}) => {
            setExtraProps(props);
        }) 
    }, [router]);

    return <Page {...extraProps}/>
}

Next.js如何实现SSG

SSG则是静态预渲染,参数不能动态从路由传入,只能构建的时候以环境变量的形式传入,所以页面渲染需要采用特殊的兼容读取方式。

将自定义的getPrerenderProps 输出到页面级别Next.js API的getStaticProps当中,实现静态渲染。

// index_ssg.js
export { 
  Page as default, 
  getPrerenderProps as getStaticProps 
} from '../modules/Home';

如何将SSR降级成为CSR

SSR服务端渲染由于是依赖服务器资源,在流量过大的情况下,有可能会出现服务不可用的情况,返回特殊的错误码例如500等。这时候我们可以实现优雅降级,利用 nginx 做对应的流量分发,当SSR页面返回异常错误的时候,nginx会将流量导入到CSR页面当中。

SSR页面和CSR页面基于Next.js采用同样的业务逻辑编写方式,有效保证页面逻辑的一致性,一份代码两端复用。

SSR优雅的降级

总结

Next.js是非常成熟高效的服务端渲染框架,本文通过一些取巧的方式来实现“一份代码,多种渲染方式”,既能提高页面的性能,也能够保证页面的优雅降级。多种渲染模式采用同一份代码,保证了逻辑的一致性,有效地为QA节省了回归人力。在“质量”和“性能”上找到了一个很好的平衡点。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,026评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,655评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,726评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,204评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,558评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,731评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,944评论 2 314
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,698评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,438评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,633评论 2 247
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,125评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,444评论 3 255
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,137评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,103评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,888评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,772评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,669评论 2 271

推荐阅读更多精彩内容