快速了解 Nextjs 从开发到部署


Next.js 是一个 React 框架,它提供了创建 Web 应用程序的主要模块。

框架,指的是 Next.js 处理 React 所需的工具和配置,并为应用程序提供额外的结构、特性和优化。

构建 Web 应用程序的模块如下

  • User Interface用户界面-用户将如何消费和与您的应用程序交互。

  • Routing路由------用户如何在应用程序的不同部分之间导航。

  • Data Fetching数据获取-你的数据在哪里以及如何获取它。

  • Rendering渲染-在何时何地呈现静态或动态内容。

  • Integrations集成------使用哪些第三方服务(CMS、授权、支付等)以及如何连接它们。

  • Infrastructure基础架构------在这里部署、存储和运行应用程序代码(Serverless、 CDN、 Edge 等)。

  • Performance性能------如何为最终用户优化应用程序。

  • Scalability可伸缩性------随着团队、数据和流量的增长,应用程序如何适应。

  • Developer Experience开发人员经验-团队构建和维护您的应用程序的经验。

可以使用 React 构建 UI,然后逐步采用 Next.js 特性来解决常见的应用程序需求,比如路由、数据获取、集成------所有这些都可以改善开发人员和终端用户的体验。

快速开始

  1. 初始化一个项目 npm init -y
  2. 安装依赖 npm install react react-dom next -S
  3. 在根目录下创建文件 pages/index.tsx
js 复制代码
import React, { useState } from 'react';
function Header({ title }) {
  return <h1>{title ? title : 'Default title'}</h1>;
}

export default function HomePage() {
  const names = ['Ada Lovelace', 'Grace Hopper', 'Margaret Hamilton'];

  const [likes, setLikes] = useState(0);

  function handleClick() {
    setLikes(likes + 1);
  }

  return (
    <div>
      <Header title="Develop. Preview. Ship. 🚀" />
      <ul>
        {names.map((name) => (
          <li key={name}>{name}</li>
        ))}
      </ul>

      <button onClick={handleClick}>Like ({likes})</button>
    </div>
  );
}
  1. package.json中添加启动 "dev": "next dev",本地会打开一个服务 localhost:3000

  2. 查看效果

How Next.js Works

  • 代码运行的环境:开发 vs 生产
  • 当你的代码运行时:构建时 vs 运行时
  • 渲染发生的位置:客户端 vs 服务器

可以将环境视为运行代码的上下文。

在开发期间,将在本地计算机上构建和运行应用程序。进入生产环境是应用程序准备部署了,以及被用户使用的过程。

Next.js 为应用程序的开发和生产阶段提供了一些功能。例如:

  • 在开发阶段,Next.js 针对开发人员及其构建应用程序的体验进行优化。它具有旨在改善开发人员体验的 功能,例如TypeScriptESLint 集成快速刷新等。
  • 在生产阶段,Next.js 针对最终用户及其使用应用程序的体验进行优化。它的目的是转换代码以使其高性能且易于访问。

由于每个环境都有不同的考虑因素和目标,因此需要做很多工作才能将应用程序从开发转移到生产。例如,应用程序代码需要编译捆绑缩小代码拆分

Next.js 处理了大部分代码转换和底层基础设施,使得应用程序更容易投入生产。

这是可能的,因为 Next.js 有一个用 Rust(一种低级别编程语言)编写的编译器,以及SWC(一个可用于编译、缩小、捆绑等的平台)。

编译阶段

在 Next.js 中,编译是在编辑代码的开发阶段进行的,也是为生产准备应用程序的构建步骤的一部分。

压缩

压缩代码是在不更改代码功能的情况下删除不必要的代码格式和注释的过程。目标是通过减小文件大小来提高应用程序的性能。

在 Next.js 中,JavaScript 和 CSS 文件会自动压缩以用于生产。

Code Splitting

代码分割是将应用程序的 Bundler 分割成每个入口点所需的较小块的过程。目标是通过仅加载运行该页所需的代码来改进应用程序的初始加载时间。

Nextjs 内置了对代码分割的支持。在构建步骤中,页面/目录中的每个文件都将自动被分割成自己的 JavaScript 包。

  • 页面之间共享的任何代码也被分割成另一个包,以避免在进一步导航时重新下载相同的代码。
  • 在初始页面加载之后,Next.js 可以开始预加载用户可能导航到的其他页面的代码。
  • 动态导入是另一种手动分割最初加载的代码的方法。

Build Time and Runtime

构建应用程序时,Next.js 会将您的代码转换为生产优化的文件,准备部署到服务器并供用户使用。这些文件包括:

  • 静态生成页面的 HTML 文件
  • 用于在服务器上呈现页面的JavaScript 代码
  • 用于使页面在客户端上具有交互性的 JavaScript 代码
  • CSS 文件

运行时 是指在构建和部署应用程序之后,应用程序响应用户请求而运行的时间段。

File system Routing

在 Next.js 中,页面是从 pages 目录中的文件导出的 React Component。

页面根据其文件名与路由关联,比如:

js 复制代码
pages/index.js 与/path 相关联。

pages/post/first-post.js 与/post/first-post 路由关联。

只需在 page 目录下创建一个 JS 文件,文件的路径就变成了 URL 路径。

Pages Router

Before Next.js 13, the Pages Router was the main way to create routes in Next.js.

它使用一个直观的文件系统路由器来映射每个文件到一个路由。Pages Router 在新版本的 Next.js 中仍然受到支持,但是我们建议迁移到新的 App Router 以利用 React 的最新特性。

页面跳转

在 Nextjs 中,我们可以使用 Link 组件(从 next/link 导入)导航页面。

<Link>允许您进行客户端导航并接受可以让您更好地控制导航行为的Props。

js 复制代码
import Link from 'next/link';

<Link href="/posts/first-post">this page!</Link>

注意: 在 Next.js 12.2之前,Link 组件需要包装 < a > 标记,但是在12.2及以上版本中不需要这样做。

客户端导航意味着页面转换使用 JavaScript进行,这比浏览器完成的默认导航更快。

可以通过以下简单方法进行验证:

  • 使用浏览器的开发者工具将<html>background更改为yellow
  • 单击链接可在两个页面之间来回切换。
  • 会看到黄色背景在页面转换之间持续存在。

这表明浏览器没有加载整个页面,并且客户端导航正在工作。

如果使用<a href="...">而不是<Link href="...">这样做,则点击链接时背景颜色将被清除,因为浏览器会进行完全刷新。

Note: If you need to link to an external page outside the Next.js app, just use an <a> tag without Link.

代码分割和预取

Next.js 自动进行代码分割,因此每个页面仅加载该页面所需的内容。这意味着当呈现主页时,最初不会提供其他页面的代码。

这可以确保即使有数百个页面,主页也能快速加载。

仅加载请求的页面的代码也意味着页面变得孤立。如果某个页面抛出错误,应用程序的其余部分仍然可以工作。

此外,在 Next.js 的生产版本中,只要Link组件出现在浏览器的视口中,Next.js 就会自动在后台预取链接页面的代码。 当单击链接时,目标页面的代码将已在后台加载,并且页面转换几乎是即时的!

Assets, Metadata, and CSS

Next.js 可以在顶级目录的 public 文件夹 下提供静态资源,例如图像。

未优化的图像

使用常规 img

html 复制代码
<img src="/images/profile.jpg" alt="Your Name" />

但是,这意味着必须手动处理一些优化:

  • 确保您的图像在不同的屏幕尺寸上具有响应能力
  • 使用第三方工具或库优化图像
  • 仅在图像进入视口时加载图像

相反,Next.js 提供了一个Image开箱即用的组件来为您处理此问题,扩展了常规的 img

next/image

Next.js 不是在构建时优化图像,而是根据用户的请求按需优化图像。与静态站点生成器和纯静态解决方案不同,无论是传送 10 个图像还是 1000 万个图像,您的构建时间都不会增加。

默认情况下图像是延迟加载的。这意味着您的页面速度不会因为视口之外的图像而受到影响。图像在滚动到视口时加载。

Metadata

如果我们想要修改页面的元数据(例如<title>HTML 标签)怎么办?

<title>是 HTML 标记的一部分<head>,因此让我们深入了解如何修改<head>Next.js 页面中的标记。

html 复制代码
import Head from 'next/head'

...

<Head>
  <title>Create Next App</title>
  <link rel="icon" href="/favicon.ico" />
</Head>

添加第三方 JavaScript

尽管这种方法有效,但以这种方式包含脚本并不能清楚地了解相对于同一页面上获取的其他 JavaScript 代码何时加载。如果特定脚本是渲染阻塞的并且可以延迟页面内容的加载,则这可能会显着影响性能。

html 复制代码
<Head>
  <title>First Post</title>
  <script src="https://connect.facebook.net/en_US/sdk.js" />
</Head>

next/script是 HTML 元素<script>的扩展,并在获取和执行其他脚本时进行优化。

js 复制代码
import Script from 'next/script';

<Script
    src="https://connect.facebook.net/en_US/sdk.js"
    strategy="lazyOnload"
    onLoad={() =>
      console.log('script loaded correctly, window.FB has been populated')
    }
/>

请注意,脚本组件中定义了一些附加属性:

  • strategy控制何时加载第三方脚本。值lazyOnload告诉 Next.js 在浏览器空闲时间延迟加载这个特定的脚本
  • onLoad用于在脚本完成加载后立即运行任何 JavaScript 代码。在此示例中,我们将一条消息记录到控制台,指出脚本已正确加载

css

nextjs 默认支持 css modules 和 scss

从 Next.js 13.1开始,Turbopack 支持 Tailwind CSS 和 PostCSS。

Global Styles

在应用中加载全局 styles,在 pages 下创建 _app.tsx,pages/_app.js

tsx 复制代码
export default function App({ Component, pageProps }) {
  return <Component {...pageProps} />;
}

默认导出的_app.tsx是一个顶级 React 组件,它包装了应用程序中的所有页面。可以使用此组件在页面之间导航时保持状态,或者像我们在这里所做的那样添加全局样式。

Important: You need to restart the development server when you add pages/_app.js.

然后我们可以创建 styles/global.css,在 _app.tsx 中导入全局样式,它会在所有页面生效。

Layout Component

我们可以创建统一的 Layout 组件,用于应用的整体结构。

jsx 复制代码
export default function Layout({ children }) {
    return <div style={{ backgroundColor: '#69c' }}>{children}</div>;
}

_app.tsx 中使用

jsx 复制代码
import '../styles/global.css'
import Layout from '../components/Layout'

export default function App({ Component, pageProps }) {
  return <Layout>
    <Component {...pageProps} />;
  </Layout>
}

Rendering

Rendering 可以在服务器或客户端上进行。它可以在构建时提前发生,也可以在运行时发生在每个请求上。

With Next.js, three types of rendering methods are available: Server-Side Rendering , Static Site Generation , and Client-Side Rendering.

Client-Side Rendering

在标准的 React 应用程序中,浏览器从服务器接收一个空的 HTML,以及构造 UI 的 JavaScript 指令。这称为Client-Side Rendering,因为最初的渲染工作发生在用户的设备上。

pre-render and data fetching

默认情况下,Next.js 预渲染每个页面。这意味着 Next.js 提前在服务端为每个页面生成 HTML,而不是让客户端 JavaScript 完成所有工作。预渲染可以带来更好的性能和搜索引擎优化。

每个生成的HTML都与该页面所需的最小JavaScript代码相关联。当页面被浏览器加载时,它的JavaScript代码会运行,并使页面变得完全交互。这个过程被称为hydration(注水)

Two Forms of Pre-rendering

Next.js has two forms of pre-rendering: Static Site Generation and Server-side Rendering. The difference is in when it generates the HTML for a page.

  • Static Site Generation 是在构建时生成 HTML 的预呈现方法。然后对每个请求重用 pre-rendering HTML。

    使用静态站点生成,HTML 是在服务器上生成的,但与服务器端渲染不同的是,运行时没有服务器。相反,内容在构建时、部署应用程序时生成一次,并且 HTML 存储在 CDN 中,并针对每个请求重复使用。

  • Server-side Rendering 是在每个请求上生成 HTML 的 pre-rendering 方法。

在开发模式下(当您运行 npm run dev 或 yarn dev 时) ,每个页面都是针对每个请求预先呈现的------即使是对于使用 static generation 的页面也是如此。

ISR/SSG/SSR

ISR(Incremental Static Regeneration),SSG(Static Site Generation)和SSR(Server-Side Rendering)是用于前端渲染的不同策略,每种策略有其独特的特点和适用场景。

  1. SSG(Static Site Generation):

    • 在SSG中,页面的渲染是在构建时(编译时)完成的,而不是在每次用户请求时动态生成。
    • 在构建过程中,静态站点生成器会预先获取数据并根据页面模板生成静态HTML文件。
    • 运行时,服务器仅需提供预生成的静态文件,无需进行动态的数据处理和页面渲染。
    • 静态文件可以被缓存并通过CDN(内容分发网络)进行分发,以提供更快的加载速度和更好的用户体验。
    • SSG适用于内容不经常变动、不需要实时数据更新的应用,如博客、文档网站等。
  2. SSR(Server-Side Rendering):

    • 在SSR中,页面的初始渲染是在服务器端完成的。当用户请求页面时,服务器会动态生成HTML内容,并将完整的HTML响应发送给客户端。
    • 在服务器端渲染的过程中,服务器会执行应用的逻辑、获取数据并将其注入到HTML模板中,然后将生成的HTML发送给客户端。
    • 客户端收到HTML响应后,可以立即显示页面的内容,包括初始化的数据和交互功能。
    • SSR适用于需要动态内容、实时数据或与服务器密切交互的应用,如社交媒体站点、电子商务网站等。
  3. ISR(Incremental Static Regeneration):

    • ISR是Next.js框架中的一项功能,结合了SSG和SSR的优势。
    • 在ISR中,页面在构建时被静态生成,但与SSG不同的是,页面在首次访问后可以被缓存,并且可以在后续的请求中进行增量更新。
    • 当用户请求被缓存的页面时,Next.js会尝试在后台重新生成该页面,并在生成完成后进行替换,从而实现页面的更新。
    • 这样,用户可以在不重新构建整个站点的情况下获取到最新的内容,提供了更好的性能和用户体验。
    • ISR适用于需要定期更新的页面,如新闻网站、博客的文章列表等。

ISR(Incremental Static Regeneration)在SSG的基础上提供了增量更新的能力,适用于需要定期更新的页面。

SSG(Static Site Generation)在构建时生成静态HTML文件,适用于内容较为静态且不经常变动的应用。

SSR(Server-Side Rendering)在服务器端动态生成HTML响应,适用于需要动态内容和实时数据的应用。

根据项目的需求和特点,选择适合的渲染策略可以提供更好的性能和用户体验。Next.js框架提供了在不同场景下灵活使用这些策略的能力。

API Routes

创建的 API routes 的 关键api/**/** 必须是在 pages 文件夹下。

我们创建一个 url 为 /api/people 的 API Route

js 复制代码
/pages/api/people/index.ts

import { NextApiResponse, NextApiRequest } from "next";
import { people } from "../../api-routes/data";
import { Person } from "../../api-routes/interface";

export default function handler(
  _req: NextApiRequest,
  res: NextApiResponse<Person[]>
) {
  return res.status(200).json(people);
}

上面的路径为 /pages/api/people/index.ts,就将 /api/people 作为请求路径。组件中的用法如下:

js 复制代码
fetch(url).then((res) => res.json());

const { data, error, isLoading } = useSWR<Person[]>("/api/people", fetcher);

动态路由 /pages/api/people/[id].ts,就将 /api/people/** 作为请求路径。比如 /api/people/1 这种。

js 复制代码
/pages/api/people/[id].ts

import { NextApiRequest, NextApiResponse } from "next";
import { people } from "../../api-routes/data";
import type { Person, ResponseError } from "../../api-routes/interface";

export default function personHandler(
  req: NextApiRequest,
  res: NextApiResponse<Person | ResponseError>
) {
  const { query } = req;
  const { id } = query;
  const person = people.find((p) => p.id === id);

  // User with id exists
  return person
    ? res.status(200).json(person)
    : res.status(404).json({ message: `User with id: ${id} not found.` });
}

组件中的用法如下

跳转到详情页

js 复制代码
import Link from "next/link";
import { Person } from "../../pages/api-routes/interface";

type PersonProps = {
  person: Person;
};

export default function PersonComponent({ person }: PersonProps) {
  return (
    <li>
      <Link
        href="/api-routes/person/[id]"
        as={`/api-routes/person/${person.id}`}
      >
        {person.name}
      </Link>
    </li>
  );
}

详情页获取路由参数 id,根据 id 查询 api route。

js 复制代码
export default function PersonDetails() {
  const { query } = useRouter();
  const { data, error, isLoading, isValidating } = useSWR<
    Person,
    ResponseError
  >(() => (query.id ? `/api/people/${query.id}` : null), fetcher);

  if (error) return <div>{error.message}</div>;
  if (isLoading) return <div>Loading...</div>;
  if (!data) return null;
  
  return (...)
}

App Router

App Router 是一种使用 React 的最新功能构建应用程序的新范例,它是 Pages Router 中现有的基于文件系统的路由器的自然演变。

对于新的应用程序,推荐使用 App Router。对于现有的应用程序,也可以增量地迁移到 App Router。

Route Groups

app目录中,嵌套文件夹通常映射到 URL 路径。但是,您可以将文件夹标记为路由组 (Route Group),以防止该文件夹包含在路由的 URL 路径中。

这允许您在不影响 URL 路径结构的情况下将route group和project files组织成逻辑组。

用法

Route group 可以通过将文件夹的名称包装在括号中来创建: (folderName)

example

若要在不影响 URL 的情况下组织路由,创建一个组以将相关路由保持在一起。括号中的文件夹名将从 URL 中省略。/about 或者 /blog

默认渲染

默认渲染最后后一个 Route Group,这里的 (me) page.

想要访问其它的 Route Group,我们可以添加文件夹

部署

Pre-requisite(先决条件): 需要有一个 GitHub 帐户。

  • 如何将 Next.js 应用程序部署到 Vercel。
  • Vercel 的 DPS 工作流: 开发、预览和发布。(D evelop, P review, and Ship.)

部署到 Vercel

www.nextjs.cn/learn/basic...

将 Next.js 部署到生产环境的最简单方法是使用由 Next.js 的创建者开发的 Vercel 平台。

Vercel 是一个一体化的全球 CDN 平台,支持静态和 JAMstack 部署和无服务器功能。Vercel 是部署 Next.js 应用程序的最佳地点。

参考

about-nextjs

nextjs-course-code

nextjs-app-playground

Notus Nextjs------Free Tailwind CSS UI Kit and Admin.

一起交流

不管你遇到什么问题,或者是想交个朋友一起探讨技术(=。=),都可以加入我们的组织,和我们一起 ~

喜欢这部分内容,就加入我们的QQ群,和大家一起交流技术吧~

QQ群1032965518

相关推荐
过往记忆4 小时前
告别 Shuffle!深入探索 Spark 的 SPJ 技术
大数据·前端·分布式·ajax·spark
高兴蛋炒饭5 小时前
RouYi-Vue框架,环境搭建以及使用
前端·javascript·vue.js
m0_748240445 小时前
《通义千问AI落地—中》:前端实现
前端·人工智能·状态模式
ᥬ 小月亮5 小时前
Vue中接入萤石等直播视频(更新中ing)
前端·javascript·vue.js
神雕杨6 小时前
node js 过滤空白行
开发语言·前端·javascript
网络安全-杰克7 小时前
《网络对抗》—— Web基础
前端·网络
m0_748250747 小时前
2020数字中国创新大赛-虎符网络安全赛道丨Web Writeup
前端·安全·web安全
周伯通*7 小时前
策略模式以及优化
java·前端·策略模式
艾斯特_7 小时前
前端代码装饰器的介绍及应用
前端·javascript
Sokachlh7 小时前
【elementplus】中文模式
前端·javascript