跳到主要内容

NextJs从搭建到部署(第一篇:搭建)

· 阅读需 13 分钟
chalk

本文前提是你拥有 React 基础, 旨在帮你用Node.js构建服务端渲染的网站。
帮助你开发博客、官网、支持SSR。

NextJs是什么?

Next.js是一个React开发框架。

它为你的React应用程序提供了额外的解决方案和内置功能(包括但不限于):

  • 直观的、 基于页面 的路由系统(并支持 动态路由)
  • 预渲染。支持在页面级的 静态生成 (SSG) 和 服务端端渲染 (SSR)
  • 自动代码拆分,提升页面加载速度
  • 具有经过优化的预取功能的 客户端路由
  • 内置 CSS 和 Sass 的支持,并支持任何 CSS-in-JS 库
  • 开发环境支持 快速刷新
  • 利用 Serverless Functions 及 API 路由 构建 API 功能
  • 完全可扩展

使用它你可以快速的开发React应用程序而不用去捣鼓各种开发工具。

创建Next.js项目

项目创建与2023/6/15

使用的部分版本为: Node.js 16.8、React 18.2.0、TypeScript 5.1.3

安装Next.js

## Installation
npm create-next-app@latest
# or
yarn create next-app

What is your project named? -- my-app

项目名称

Would you like to use TypeScript with this project? -- Yes

项目是否使用TS

Would you like to use ESLint with this project? -- Yes

项目是否使用ESLint

Would you like to use Tailwind CSS with this project? -- Yes

项目是否使用TailwindCSS

Would you like to use src/ directory with this project? -- Yes

项目是否使用src/目录

Use App Router (recommended)? -- Yes

项目是否使用路由(推荐使用)

Would you like to customize the default import alias? -- No

是否要自定义默认导入别名(Yes or No 都可)

What import alias would you like configured? -- @/*

若要自定义默认导入别人则会出现此项用于配置(默认配置@/*)

安装完毕后你有了一个Next.js项目,现在让我们进入项目:

VsCode 打开项目,你的目录结构应该如下:(.next文件夹在项目启动后会自动生成)

image-20230614224950931

运行 npm run devyarn dev 来启动开发服务端, 默认访问地址为 http://localhost:3000

打开 http://localhost:3000,你的页面默认如下所示:

image-20230614225107710

恭喜!你的Next.js应用程序创建成功!

目录介绍

创建页面及路由

基础路由

src/ 目录下 app/pages/ 目录选择一个作为你的路由目录,你的所有路由都与此有关。

在NextJs13版本中 默认使用app/目录,不同的目录配置也不相同

app/ 目录下默认 page.tsx 文件就是你的根路径展示文件。

app/ 目录中的 每一个定义了page文件的文件夹 都是你的路由。

app/ 目录中创建一个命名为app/dashboard/page.tsx 的文件并导出(export)一个如下所示的React组件:

// app/dashboard/pages.tsx
const DashBoard = () => {
return <div>这是DashBoard页面</div>;
}
export default DashBoard;

通过 /dashboard 路径,你可以访问该页面。

组件层次结构

  • layout

    该文件作为你的页面布局,在 app/layout.tsx 中,你始终应该创建一个<html><body> 标签,这是必需的!

    你的全局样式表应该在此处导入。

  • page

    这里是你的页面内容,尝试更改内容,你的页面对应处也会更改。

  • template

    这个作为你的模板文件

  • error

    这个是你的报错处理

  • loading

    加载时的loading态

  • not-found

    没找到页面时的展示页面

  • route

    返回路由地址

对应的层次结构如下所示

Component Hierarchy for File Conventions

在一个嵌套路由中,一个组件将被嵌套在它的父级组件中。

Nested File Conventions Component Hierarchy

当然,除了特殊文件,你还可以选择将你自己的文件(例如组件、样式、测试等)放在app/ 目录下的文件夹中。

但我建议你最好不要这么做,保证路由的清晰程度很重要!

An example folder structure with colocated files

动态路由

动态路由可以通过将文件夹的名称用方括号括起来创建, 例如[id][slug]

app/ 目录中创建一个命名为app/blog/[id]/page.tsx 的文件并导出(export)一个如下所示的React组件:

// app/blog/[id]/page.tsx
const Page = ({ params }: { params: { id: string } }) => {
return <div>My Post: {params.id}</div>
}
export default Page;

通过 /blog/a 路径,你可以访问该页面。

其中,params 参数为{ id: 'a' }

组件模式

服务端组件和客户端组件有何区别?我该在什么情况下使用?

服务端组件

为什么使用服务端组件?与客户端组件相比,使用它的优势是什么?

服务端组件允许开发人员更好地利用服务端基础设施。例如,您可以将数据获取移到离数据库更近的服务端上,并保留以前会影响服务端上客户端JavaScript包大小的大型依赖项,从而提高性能。

服务端组件使编写React应用程序感觉类似于PHPRuby on Rails,但具有React的功能和灵活性以及用于模板UI的组件模型。

async function getData() {
const res = await fetch('https://api.example.com/...')
// The return value is *not* serialized
// You can return Date, Map, Set, etc.

// Recommendation: handle errors
if (!res.ok) {
// This will activate the closest `error.js` Error Boundary
throw new Error('Failed to fetch data')
}

return res.json()
}

export default async function Page() {
const data = await getData()

return <main></main>
}

要在TypeScript中使用async Server组件,请确保你使用的是TypeScript 5.1.3或更高版本和@types/react 18.2.8或更高版本。

使用服务端组件,初始页面加载速度更快,并且减少了客户端JavaScript包的大小。基本客户端运行时的大小是可缓存和可预测的,并且不会随着应用程序的增长而增加。

只有在通过客户端组件在应用程序中使用客户端交互时,才会添加额外的JavaScript。

当用Next.js加载路由时,初始HTML就会在服务端端呈现。然后这个HTML在浏览器中逐渐增强,允许客户端接管应用程序并添加交互性,通过异步加载Next.jsReact客户端运行时。

为了更容易过渡到服务端组件,App Router中的所有组件默认都是服务端组件,包括特殊文件和配置的组件。这允许您自动采用它们,而不需要额外的工作,并获得开箱即用的出色性能。你也可以通过在文件顶部 use client 指令选择加入客户端组件。

客户端组件

客户端组件使您能够向应用程序添加客户端交互性。

Next.js中,它们在服务端上预渲染,并在客户端上进行渲染。您可以将客户端组件视为Pages Router中的组件一直以来的工作方式。

使用 use client use client 指令是一种约定,用于声明服务端组件和客户端组件模块图之间的边界。

在文件的顶部,在import的上方加入 use client 即可启用,一旦启用则其中的所有导入的模块,包括子组件都被视为客户端包的一部分。

Use Client Directive and Network Boundary

使用场景

你需要做什么服务端组件客户端组件
获取数据✔️
直接访问后端资源✔️
将敏感信息保存在服务端上(访问令牌、API密钥等)✔️
在服务端上保持大量的依赖性/减少客户端的JavaScript✔️
增加互动性和事件监听器(onClick(), onChange()等)✔️
使用状态和生命周期效果(useState()、useReducer()、useEffect()等)✔️
使用仅适用于浏览器的API✔️
使用依赖于状态、效果或纯浏览器API的自定义钩子✔️
使用React类组件✔️

使用建议

服务端组件和客户端组件可以组合在同一个组件树中。

在客户端,React呈现客户端组件,并在服务端组件的呈现结果中插入插槽,合并在服务端和客户端上完成的工作。

与其将整个文件做成一个客户端组件,不如尽可能的将交互式组件抽离,这意味着你不必将所有JavaScript组件发送到客户端。

路由页面跳转

现在你已经能够创建页面及路由,也了解了服务端组件和客户端组件的区别,接下来让我们在路由中跳来跳去~

\<Link>是一个React组件,它扩展了HTML \<a>元素,在路由之间提供预取和客户端导航。这是Next.js中导航路由的主要方式。

import Link from 'next/link'

export default function Page() {
return <Link href="/dashboard">Dashboard</Link>
}

客户端跳转 useRouter

useRouter钩子允许你以编程的方式改变客户端组件中的路由。

建议你始终使用\<Link>组件进行路由跳转,除非你有使用useRouter的特殊需求。

'use client'

import { useRouter } from 'next/navigation'

export default function Page() {
const router = useRouter()

return (
<button type="button" onClick={() => router.push('/dashboard')}>
Dashboard
</button>
)
}

配置项目

参考next.config.js

SSR

元数据 Metadata

Next.js有一个元数据API,可以用来定义你的应用元数据(例如,HTML head元素中的metalink标签),以提高SEO和网络可共享性。

layout.tsxpage.tsx文件中导出静态元数据对象或动态generateMetadata函数。

import { Metadata } from 'next'

export const metadata: Metadata = {
title: '...',
description: '...',
}
// or

export async function generateMetadata({ params, searchParams }: Record<string, any>) {
...

return {
title: '...',
description: '...',
keywords: '...',
};
}

总结

本文通过创建一个Next.js应用程序以及所需的页面、目录、路由、组件模式、元数据的配置等介绍了其基本内容。

如果你即将构建服务端渲染应用,不妨试试Next.js, 相信绝对不会让你失望!