Skip to main content
  1. 笔记/

服务端渲染gatsby简介

·4 mins
Table of Contents

目前react在市面上的渲染方案
#

React 在市场上的渲染方案可以分为:客户端渲染(Client-side Rendering,CSR)和服务端渲染(Server-side Rendering,SSR),静态网站生成器(Static Site Generator,SSG)

  1. 客户端渲染(CSR)客户端渲染是指在浏览器中使用 JavaScript 处理页面的渲染和数据交互。在这种模式下,React 的工作方式是将应用程序的代码打包成一组 JavaScript 文件,浏览器会下载这些文件并在页面上动态渲染。常见的客户端渲染方案有使用 React 自带的 create-react-app 脚手架。

  2. 服务端渲染(SSR)服务端渲染是指在服务器端使用 React 处理页面的渲染和数据交互,服务器将整个渲染好的页面发送给浏览器。这种模式下,React 的工作方式是在服务器上预渲染应用程序并将其传输给浏览器,然后进行客户端渲染。常见的服务端渲染方案有使用 Next.js、Remix等框架。

  3. 静态网站生成器(Static Site Generator,SSG)简单来说,SSG 是一种将动态内容转换为静态站点的技术,可以将动态内容渲染为 HTML、CSS 和 JavaScript 文件,并将其发布到 HTTP 服务器上,从而使之可以像普通静态文件一样访问。与传统的 CMS 不同,SSG 将内容存储在文件而不是数据库中,可以将该文件作为静态资源部署到 Web 服务器或者 CDN 中。使用 SSG 可以实现非常快速的页面加载速度,因为页面需要的数据和 HTML 已经预先生成,而不用等待服务器渲染动态内容。而且,SSG 还可以提升 SEO,因为生成的静态页面对搜索引擎爬虫更加友好。SSG 可以轻松应用于各种 Web 项目中,例如博客、商业网站和电子商务网站等等。常见的静态站点生成器包括 Gatsby、Hugo等。需要注意的是,虽然 SSG 能快速提高 Web 应用的性能和 SEO,但是对于包含动态内容的应用程序,SSG 可能无法满足需求。因此,在选择使用 SSG 技术时,需要考虑项目的实际需求以及业务规模。

需要注意的是,使用不同的渲染方案可能会对页面性能、SEO、开发效率等方面产生不同的影响,具体选择渲染方案时需要根据项目需求进行权衡和选择。

区分一下使用场景
#

对于不同使用场景需要采用不同的渲染方式

  1. 面向C端的动态网站

    • 需要考虑seo的如:网站官网、博客。这时候需要使用Next.js,SSR

    • 不需要seo的如:云服务器控制台,用cra或umi即可,CSR

  2. 需要面向C端的静态网站(天然有SEO)

    • 官网,一般不包含太多的动态信息,SSG

    • 文档类型的网站,SSG

  3. 面向企业的网站

    • 管理后台(完全不需要SEO): CSR

方案对比
#

需要 SSR - Next.js
#

image

  1. 第一步,打开浏览器,访问这个 blog 网站的文章列表页面 (/ 或者 /articles)。

  2. 第二步,请求到达服务器的 nginx,nginx 设置的规则是,如果请求匹配 /api/v1/\*,则转给 API 服务处理,否则如果匹配 /\*,则转给 next.js 服务处理,所以 /articles 请求发送给了 next.js 服务。

  3. 第三步到第六步,next.js 收到 /articles 请求后,会选择渲染文章列表界面,假如这个 page 叫 ArticleListPage,在这个 component 中,next.js 的 getInitialProps() 方法会去访问 API 服务的 /api/v1/articles API,获得所有的 articles 数据 (不考虑分页),然后渲染出 html,html head 中 link 了 bundle 的所有 js 代码,html 返给浏览器。

  4. 第七步,浏览器得到了 html 后,进行首屏渲染,用户马上就看到了内容。浏览器解析完 html 后,会继续下载 html 中 link 的 js 代码并执行,然后该网站就变成了一个 SPA,js 接管剩余的所有路由,并且 js 会把此页面用 js 再重新渲染一遍 (用户没有感知)。

  5. 第八步到第九步,用户点击某篇文章查看详情,比如 /articles/1,由于 js 在客户端已经接管了路由,所以这个请求并不会发送到服务端的 nginx,js 代码根据路由,切换到详情页面 (比如 ArticlePage) 组件,在这个组件在 getInitialProps() 方法中,它会发送 /api/v1/articles/1 的 ajax 请求去访问 API 获取文章的详情数据。

  6. 第十步到第十一步,/api/v1/articles/1 的请求到达服务端的 nginx 后,转发给 API 服务处理,API 从数据库查询得到结果返回给浏览器,浏览器渲染之。整个流程结束。

CSR - CRA/Umijs
#

image

不需要太多解释,典型的 SPA,大家对这个再熟悉不过了。

CRA build 后,得到空白 body 的 index.html 和 bundle.js (不考虑 split) 静态文件,浏览器首次访问任何页面,得到同一个 index.html,然后下载 index.html 中 link 的 bundle.js 并执行,js 在客户端这边接管剩余路由,用 js 渲染相应的页面,在不同的页面通过 ajax 请求访问不同的 API。

静态网站 - Gatsby
#

image

工作流程:

  1. gatsby 从各处数据源获取数据,build 后一次性生成所有静态页面,包括 html / json / bundle.js,一个页面就有一个 html 和 json,比如 articles.html / articles-$hash.json, hello.html / hello-$hash.json,然后把这些静态文件扔到 CDN 上即可 (比如 netlify)

  2. 浏览器首次访问某个页面,比如 /articles,则得到的是 /articles.html,如果是 /hello,则得到的是 /hello.html,假定这里我访问的是 /articles

  3. 每个 html 的 head 都 link 了 bundle.js (实际做了 split,拆成了很多个 js,这里做简化处理),浏览器解析并渲染 html 后,下载并执行 bundle.js,接管所有剩余路由。

  4. 接下来就是 gatsby 相比 jekyll/hugo 这些静态建站工具的特别之处了,如果此时我点击某篇文章的详情,假如是 /hello,jekyll/hugo 会去 CDN 访问相应的 html 文件,但 gatsby 不会,前面说到,它会在客户端这边接管所有剩余的路由,因此 gatsby 会根据 /hello 路由在客户端这边用 js 渲染相应的页面,那数据来自何处,前面说到每一个 html 都有一个相应的 json 文件,json 文件存储的就是各页面对应的数据,因此 gatsby 在客户端渲染不同的页面时,会通过 ajax 请求去取相应的 json 文件,取回来后解析成 object 作为各个 component 的 props。详细的分析看这篇文章 -  gatsby 是如何做到无刷新的页面跳转以及瞬间加载

基于以上三种渲染方式的分析,我们可以看出,SSR的速度取决于服务器渲染出页面的速度,而CSR则是在客户端获取JS以后再进行渲染的,而SSG则是生成好的html后续通过json获取数据。

由于CSR首屏渲染白屏的问题,因此可以不考虑CSR来作为官网开发。SSR是服务端渲染因此速度上会逊色于静态网站,可以看出三个对比下来使用Gatsbyjs来开发官网是个很不错的选择。使用nginx来做静态文件服务器,可以轻松实现高并发、良好的SEO。

使用Gatsby
#

快速开始
#

  1. 创建一个新的 Gatsby 项目

    npm init gatsby

这个命令会要求您填写站点标题和项目目录的名称。继续按照提示选择您喜欢的语言(JavaScript 或 TypeScript)、CMS、样式工具和其他功能。

  1. 下载完成后,您将看到一条消息,其中包含导航到您的站点并在本地运行它的说明。

命令行界面(CLI)创建了一个新文件夹,该文件夹的名称与您在第 1 步中选择的名称相同。

请先进入该文件夹目录:

cd my-gatsby-site
  1. 启动开发服务器

    npm run develop

Gatsby 将启动一个热加载的开发环境,默认情况下可以访问 http://localhost:8000

创建页面
#

  1. 在 src/pages 目录下创建一个新的页面,比如 about.js

    import React from “react”

    const AboutPage = () => { return

    About Us

    }

    export default AboutPage

2.   访问 http://localhost:8000/about 页面,你应该可以看到 About Us 字样

查询数据
#

  1. Gatsby 通过 GraphQL 来管理数据

  2. 在页面组件中添加一个 GraphQL 查询:

    import React from “react” import { graphql } from “gatsby”

    const BlogPost = ({ data }) => { const post = data.markdownRemark

    return (

    {post.frontmatter.title}

    <div dangerouslySetInnerHTML={{ __html: post.html }} />
    ) }

    export const query = graphqlquery ($slug: String!) { markdownRemark(fields: { slug: { eq: $slug } }) { frontmatter { title } html } }

部署
#

  1. 在 package.json 文件中添加一个脚本

    { “scripts”: { “build”: “gatsby build” } }

  2. 执行以下命令生成静态文件

    npm run build

  3. 将 public 目录下的文件上传到服务器

结合Wordpress CMS
#

由于目前的需求是一个官网程序,并且需要文章或者公告之类的功能,因此需要引入成熟的CMS。 要在 Gatsby 中集成 WordPress CMS,可以使用 gatsby-source-wordpress 插件。该插件提供了将 WordPress 数据源转换为 Gatsby 数据层查询类型的方法,从而可在 Gatsby 网站中使用 WordPress 数据。

以下是一个简单的集成 WordPress CMS 的步骤:

  1. 安装 gatsby-source-wordpress 插件:可以通过 npm 安装该插件:npm install –save gatsby-source-wordpress

  2. 配置插件:在 gatsby-config.js 文件中添加以下配置信息:

    module.exports = { plugins: [ { resolve: “gatsby-source-wordpress”, options: { url: “https://your-wordpress-site.com/graphql”, nodeUpdateInterval:60000 // 本地运行时刷新的时间 }, }, ], };

可以根据需要自定义配置,包括 WordPress 网站的 URL、GraphQL 的 schema 和 type 等。

3.  在 GraphQL 查询中使用 WordPress 数据:创建并在src/templates/blog-post.js使用graphql查询信息,

import React from "react"
import { Link, graphql } from "gatsby"
import { GatsbyImage } from "gatsby-plugin-image"
import parse from "html-react-parser"

// We're using Gutenberg so we need the block styles
// these are copied into this project due to a conflict in the postCSS
// version used by the Gatsby and @wordpress packages that causes build
// failures.
// @todo update this once @wordpress upgrades their postcss version
import "../css/@wordpress/block-library/build-style/style.css"
import "../css/@wordpress/block-library/build-style/theme.css"

import Bio from "../components/bio"
import Layout from "../components/layout"
import Seo from "../components/seo"

const BlogPostTemplate = ({ data: { previous, next, post } }) => {
  const featuredImage = {
    data: post.featuredImage?.node?.localFile?.childImageSharp?.gatsbyImageData,
    alt: post.featuredImage?.node?.alt || ``,
  }

  return (
    <Layout>
      <Seo title={post.title} description={post.excerpt} />

      <article
        className="blog-post"
        itemScope
        itemType="http://schema.org/Article"
      >
        <header>
          <h1 itemProp="headline">{parse(post.title)}</h1>

          <p>{post.date}</p>

          {/* if we have a featured image for this post let's display it */}
          {featuredImage?.data && (
            <GatsbyImage
              image={featuredImage.data}
              alt={featuredImage.alt}
              style={{ marginBottom: 50 }}
            />
          )}
        </header>

        {!!post.content && (
          <section itemProp="articleBody">{parse(post.content)}</section>
        )}

        <hr />

        <footer>
          <Bio />
        </footer>
      </article>

      <nav className="blog-post-nav">
        <ul
          style={{
            display: `flex`,
            flexWrap: `wrap`,
            justifyContent: `space-between`,
            listStyle: `none`,
            padding: 0,
          }}
        >
          <li>
            {previous && (
              <Link to={previous.uri} rel="prev">
                ← {parse(previous.title)}
              </Link>
            )}
          </li>

          <li>
            {next && (
              <Link to={next.uri} rel="next">
                {parse(next.title)} →
              </Link>
            )}
          </li>
        </ul>
      </nav>
    </Layout>
  )
}

export default BlogPostTemplate

export const pageQuery = graphql`
  query BlogPostById(
    $id: String!
    $previousPostId: String
    $nextPostId: String
  ) {
    post: wpPost(id: { eq: $id }) {
      id
      excerpt
      content
      title
      date(formatString: "MMMM DD, YYYY")
      featuredImage {
        node {
          altText
          localFile {
            childImageSharp {
              gatsbyImageData(
                quality: 100
                placeholder: TRACED_SVG
                layout: FULL_WIDTH
              )
            }
          }
        }
      }
    }
    previous: wpPost(id: { eq: $previousPostId }) {
      uri
      title
    }
    next: wpPost(id: { eq: $nextPostId }) {
      uri
      title
    }
  }
`

以上是一些基本的 wp 集成设计,如果你想获取更多的数据信息,请参考 gatsby-source-wordpress 的官方文档。

以上是一个 Gatsby 的基本使用流程,如果你想深入了解 Gatsby,可以参考官方文档:https://www.gatsbyjs.com/docs/

问题
#

使用这种前后端分离的CMS时候,gatsby并不支持动态生成,这里指的是如果文章更新了,生产上不会实时更新,需要重新走一遍CI/CD的过程。跟预期的新增文章,相应的网站内容也需要更新是不符合的。这时候可以选择使用next.js或者使用wordpress本身的webhook触发CI/CD。

总结
#

Gatsby 是一个基于 React 的静态网站生成器,它可以帮助开发人员快速构建高性能、可扩展的静态网站,不需要手动处理复杂的构建过程。

以下是 Gatsby 框架的特点和优势:

1. 基于 React
#

Gatsby 是一个基于 React 的静态网站生成器,它使用 React 组件来构建页面布局并处理数据。由于 React 具有出色的性能和可重用性,因此 Gatsby 的代码结构非常简洁、模块化和易于维护。

2. 静态网站生成器
#

Gatsby 是一个静态网站生成器,它可以将您的 React 组件和数据转换为静态 HTML、CSS 和 JavaScript 文件。与传统的动态网站相比,静态网站的优点在于速度快、安全性高、可缓存性强。

3. 内置优化
#

Gatsby 内置了多项性能优化功能,如懒加载、图片压缩、响应式图片、代码分割、缓存等。这些功能可以大大提高网站的加载速度、交互体验和搜索引擎优化。

4. 插件生态
#

Gatsby 拥有庞大的插件生态,开发者可以通过插件轻松地实现各种功能,如数据源集成、样式处理、SEO、社交分享等。这些插件极大地提高了开发效率和代码质量。

5. 部署易用性
#

Gatsby 的静态文件可以轻松地部署到各种托管服务上,如 Github Pages、Netlify、AWS S3 等。无需繁琐的服务器配置和部署流程,大大降低了网站的部署难度和成本。

综上所述,Gatsby 框架是一个灵活、高效、易用的静态网站生成器,适合各种类型的静态网站和 Web 应用的开发。

docker入门使用
·1 min