Isomorphic SSR 的第一哩路: Next.js

1,661 阅读4分钟

什么是 SSR?为什么要 SSR?

SSR 是 Sever-side Render 的缩写,意思是指「在 Server 端就产生(Render)出画面」。目前大概有几种产生画面的时机点:

  1. Server Side Render: 在后端接收到 Request 即产生 HTML 画面,需要新的资料则需要重新发送 Request ,也会产生一个新的画面。后端的 Framework 通常都会有一个 HTML Template 的机制就是在产生画面的动作。
  2. Client Side Render: 在前端进行 Render,后端作为资料供应的 API 层。当需要新的资料时,前端发送 Request 后只需要部份更新画面就好。
  3. Isomorphic: 网站能够同时考虑 SSR 与 CSR 两种方式,之前有整理过关于 Isomorphic 的介绍。

最早期的网站都是 SSR 的方式进行,但每次的重新 Render 会造成后端的负担提升也让使用者的体验变差。而后来的 React/Vue 之类的 Framework 则是基于 CSR 的方式让使用者体验,并达到了前后端分离的优点。但 CSR 还是伴随着几个问题:

  1. 有些 CSR 的网站会造成爬虫取得的页面不是那么完整,造成 SEO 的问题
  2. 第一次载入画面是等到前端载入后,会有一段时间的空白

因此,如果能够兼具 CSR 与 SSR 的 Isomorphic ,成了一条新的解法。以下我们讲的 SSR 都是 Isomorphic 同时兼具两种方式的 SSR。

Next.js

「Next.js is a lightweight framework for static and server‑rendered applications.」

Next 是一个基于 React 的 SSR 解决方案,更多的细节可以参考官网

开始第一个 Next.js 专案吧!

方法 ①: 手动安装

根据官方的教学,可以透过 NPM 的方式手动安装:

$ npm install --save next react react-dom

接着再把 package.json 中执行的方式改成 NEXT:

{
  "scripts": {
    "dev": "next",
    "build": "next build",
    "start": "next start"
  }
}

然后建立一个页面在 /pages/index.js 档案:

export default () => <div>Welcome to next.js!</div>

最后,运行指令就会将专案跑在 3000 PORT:

npm run dev

方法 ②: create-next-app

许多人开发 React 会搭配 create-react-app 的 scaffold 来跳过复杂的环境设定,Next.js 也有:

$ npm install -g create-next-app

$ create-next-app my-app
$ cd my-app/
$ yarn start

来看一个简单 Isomorphic 范例

增加一个新页面

Next 是根据 /pages 目录作为 Route 的分配,举例来说 /pages 的 index 就会对应到 Root URL。我们先在 /pages 目录下建立一个 hello.js 的档案:

const Hello = (props) => (
    <div>
        <h1>Hello Next</h1>
    </div>
)

export default Hello

此时就会多了一个 Route 在 /hello 。

两个页面彼此连结

在 Next 中提供了 Link 的 Component 让我们可以进行页面间的 Client Side 换页:

import Link from 'next/link'

const Hello = (props) => (
    <div>
        <Link href={`/`}>
          <a>index</a>
        </Link>
        <Link href={`/hello`}>
          <a>hello</a>
        </Link>
    </div>
)

export default Hello

CSR 与 SSR 判断

我们现在有一个页面,上面有连结。我们前面有说过 Next.js 是一个兼具 CSR 与 SSR 的框架,那他是怎么处理的呢?先区分一下两种来源:

  • 如果直接点 Link 连结,是在 Client Side 换页 => CSR
  • 重新整理,或是第一次到这个画面上,必须先发 Request 到后端 => SSR

Next 的做法是透过 getInitialProps 的方式,在 Render 之前就先透过 req 来判断来源为何:

import Link from 'next/link'

const Hello = (props) => (
    <div>
        <h1>{props.text}</h1>
        <Link href={`/hello`}>
            <a>reload</a>
        </Link>
    </div>
)

Hello.getInitialProps = async function({req, query}) {
  if (req)
    return { text: 'hello server' }
  return { text: 'hello client' }
}

export default Hello

这样执行之后,我们可以发现:

  • 如果是 SSR 的话,会在 getInitialProps 取得 req
  • 如果是 CSR 的话,getInitialProps 中不会得到 req

小结论

Next 可以优雅地替我们解决 Isomorphic 的复杂机制,达到同时有 SSR 与 CSR 的解法。透过了简单的实作来了解如何开始,如果之后新专案有需要是直得考虑导入的!

Reference

  1. Next.js
  2. create-next-app

License

本著作由Chang Wei-Yaun (v123582)制作, 以创用CC 姓名标示-相同方式分享 3.0 Unported授权条款释出。