阅读 428

NextJS - React 服务器端渲染框架

介绍

Next.js 是 React 服务端渲染框架,用于构建 SEO 优化的 SPA 应用程序,具有以下特点:

  • 基于页面的路由系统,无需配置,并支持动态路由
  • 支持两种渲染方式,静态生成(SSG)和服务器端渲染(SSR)。
  • 自动代码拆分,优化页面加载速度。
  • 支持静态导出,可将应用导出为静态网站。
  • 内置 CSS 和 Sass ,并支持任何 CSS-in-JS 库。
  • 开发环境内置热更新。
  • 完全可扩展。
  • 方案成熟,世界上很多最大的品牌都在使用Next.js。

基于页面的路由系统

创建页面

  • 在 Next.js 中,页面是一个 React 组件,需要将其放置在 pages 文件夹中,每个页面都基于其文件名与路由关联,将文件添加到 pages 目录后会自动用作路由。
  • 组件需要被默认导出。
  • 组件文件中不需要引入 React。

页面跳转

  • Next.js 提供了 Link 组件来进行页面跳转,类似 SPA 应用程序的跳转方式,如果浏览器中的 JavaScript 被禁用则使用链接跳转。

  • Link 组件在生产环境中通过预取功能自动优化应用程序以获得最佳性能。

静态资源

Next.js 可以在应用程序根目录中的 public 文件夹下提供静态资源,例如图像、CSS文件等。

public 名称不能被更改,并且是提供静态资源的唯一目录。

public 文件夹中的静态文件不能与 pages 文件夹中的静态文件重名,因为 URL 上只能驻留一种资源,因此要保证公共文件夹中的文件路径和页面文件的路径是唯一的。

公用文件和页面文件之间的冲突示例:

public/
  hello
pages/
  hello.js
复制代码

无冲突的公共文件和页面文件:

public/
  hello.txt
pages/
  hello.js
复制代码

修改页面元数据

Next.js 公开来一个内置组件 Head ,通过 Head 组件可以修改元数据,并追加到页面到 header 中。

CSS 样式

Next.js 提供了三种方式使用 CSS,CSS in JS 、CSS Module、以及全局的 CSS 样式文件。

styled-jsx

Next.js 中内置来 styled-jsx,它是一个 CSS in JS 的库,允许在 React 组件中编写 CSS ,也可以使用现有的任何 CSS in JS 解决方案。使用 styled-jsx 如下所示:

function HelloWorld() {
  return (
    <div>
      Hello world
      <p>scoped!</p>
      <style jsx>{`
        p {
          color: blue;
        }
        div {
          background: red;
        }
        @media (max-width: 600px) {
          div {
            background: blue;
          }
        }
      `}</style>
      <style global jsx>{`
        body {
          background: black;
        }
      `}</style>
    </div>
  )
}
export default HelloWorld
复制代码

全局 CSS 样式

  • 在项目的根目录下添加 styles 文件夹,并在其中添加 global.css,文件名称可以自定义。
  • 在 _app.js 中使用 import 导入文件路径即可。
  • 在生产环境中,所有的 CSS 文件都会自动合并为一个缩小版的 .css 文件,从而提高程序的性能。

CSS 模块

  • Next.js 使用文件名约定来支持 CSS模块,例如 [name].module.css 。
  • 使用组件级 CSS 的好处是 CSS模块会通过自动创建唯一的类名在本地范围内重新定义 CSS,无需担心在不同文件夹中使用相同 CSS 类名称冲突的问题。
  • 在生产环境当中,所有的 CSS 模块文件将自动合并为很多缩小和代码分割的 .css 文件,这些文件代表应用程序中的热执行路径,从而提供程序性能,让页面渲染时加载的 css 文件最少。

Sass 支持

Next.js 允许同时使用 .scss 和 .sass 扩展名倒入 Sass,也可以通过 CSS 模块和 .module.scss 或 .module.sass 扩展名使用组件级 Sass。

在使用 Sass 之前,我们需要确保项目中已经安装了 Sass,安装方式如下:

npm install sass
复制代码

如果需要配置 Sass 编译器,可以在 next.config.js 中的 sassOptions 属性中进行配置。

预渲染

预渲染概述

  • 预渲染是指数据和 HTML 的拼接在服务器端直接完成。
  • 预渲染可以让 SEO 更加的友好。
  • 预渲染可以无需允许 JavaScript 即可查看应用程序的UI,会带来更好的用户体验。

预渲染的两种方式

  • 在 Next.js 中提供了两种方式来实现预渲染,静态生成和服务端渲染。
  • 静态生成和服务端渲染的区别是渲染时机不同。
  • 静态生成是在构建的时候生成 HTML,会存储到磁盘中,以后的每个请求都共用构建时生成好的 HTML。
  • 服务端渲染会在请求时生成 HTML,每个请求都会重新生成 HTML。

无数据的静态生成

  • 如果组件不需要在其他地方获取数据,直接进行静态生成。

有数据的静态生成

  • 如果组件需要在其他地方获取数据,在构建时会预先获取组件需要的数据,然后对组件进行静态生成。

静态生成

  • 在 Next.js 中,提供了 getStaticProps 方法来帮助组件获取静态生成所需要的数据,并用过 props 的方式将数据传递给组件,该方法是一个异步函数,需要在组件内部中进行导出。
  • getStaticProps 方法是在服务器端运行,永远不会在客户端中运行,所以可以从文件系统、API、或者数据库中获取数据。
  • 开发模式下,该方法会在每个请求上运行。
  • 生产模式下,该方法会在构建时运行。
export const getStaticProps: GetStaticProps = async (context) => {
  let { data: general } = await axios({
    url: 'http://strapi.codeuin.com/general'
  })

  let { data: posts } = await axios({
    url: 'http://strapi.codeuin.com/posts'
  })

  return { props: { general, posts } }
}

export default Blog
复制代码

基于路由的静态生成

  • 基于路由参数生成 HTML页面,有多少个参数就会生成多少个 HTML页面。
  • 在构建时,先获取用户可以访问的所有路由参数,在根据路由参数获取具体数据,然后根据数据生成静态 HTML。
// 返回用户可以访问到的所有路由参数
export const getStaticPaths: GetStaticPaths = async (context: any) => {
  const res = await axios('http://strapi.codeuin.com/posts')
  const posts = res.data
  const paths = posts.map((post) => `/blog/post/${post.id}`)
  
  // path: 返回固定格式的路由
  // fallback:当用户访问的参数没有在当前函数中返回时,false 会显示 404 页面,true 不会显示
  return { paths, fallback: false }
}

// 返回路由参数所对应的具体数据内容
export const getStaticProps: GetStaticProps = async (context: any) => {
  const { data: post } = await axios({
    url: `http://strapi.codeuin.com/posts/${context.params.id}`,
  })

  return {
    props: { post }
  }
}
复制代码

服务端渲染

  • 如果我们需要预先获取数据, Next.js 提供了 getServerSideProps 方法,会在接收每个请求时构建 HTML,该过程在服务器端完成。
  • 使用方式和 getStaticProps 类似。

API Routes

  • API Routes 可以理解成客户端向服务端获取数据中的接口。
  • Next.js 允许 React 开发者编写服务器端代码创建数据接口。
  • 不要在 getStaticPaths getStaticProps 这两个函数中访问 API Routes,因为这两个函数本身就是在服务器端中运行的,可以直接写服务器端中的代码。
  • pages/api 文件夹内的任何文件都将被映射到 /api/*
export default (req, res) => {
  res.status(200).json({ code: 200, data: 'Hello World!' })
}
复制代码

部署方式

NodeJS 服务器

Next.js 可以部署到任何支持 Node.js 的托管供应商,也可以采用自定义服务器,在项目根目录下新建 server.js 文件,文件内容如下:

const { createServer } = require('http')
const { parse } = require('url')
const next = require('next')
const fs = require('fs')
const path = require('path')
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()
const express = require('express')
const port = 8080

app.prepare().then(() => {
  const server = express()

  server.get('*', (req, res) => {
    // Be sure to pass `true` as the second argument to `url.parse`.
    // This tells it to parse the query portion of the URL.
    const parsedUrl = parse(req.url, true)
    const { pathname, query } = parsedUrl

    handle(req, res, parsedUrl)
  })

  const httpServer = createServer(server)

  httpServer.listen(port, (err) => {
    if (err) throw err
    console.log('> Ready on http://localhost:8080')
  })
}).catch((e) => {
  // 写入错误日志
  fs.writeFileSync(path.resolve(__dirname, 'logs/error_logs.txt'), e.stack);
  console.error(e.stack)
  process.exit(1)
})
复制代码

然后在 package.json 文件中的 scripts 新增 buildstart 脚本:

{
  "scripts": {
    "dev": "next",
    "build": "next build",
    "start": "next start"
  }
}
复制代码

使用 next build 命令会在 .next 文件夹中构建生产环境的应用程序,构建之后, 使用 next start 命令可启动一个支持混合页面的 Node.js 服务器,该服务器同时服务于静态生成的页面和服务端呈现的页面。

Docker 镜像部署

Next.js 可以部署到任何支持 Docker 容器的托管厂商,如果要使用 Docker 方式部署,需要在项目的根目录下新建 Dockerfile 文件,文件内容如下:

# build stage
FROM node:lts-alpine as build-stage
RUN mkdir -p /app
COPY . /app
WORKDIR /app
RUN npm config set registry https://registry.npm.taobao.org
RUN npm config set npm_config_sharp_dist_base_url https://npm.taobao.org/mirrors/sharp-libvips
RUN npm install
CMD  [ "npm","start" ]
复制代码

通过 docker build . -t my-nextjs-app 来生成镜像,并通过 docker run -p 3000:3000 my-nextjs-app 命令来运行它

参考文档

Next.js 官网:nextjs.org

Next.js 中文网:www.nextjs.cn

文章分类
前端
文章标签