上启动开发服务器
+
+### 添加首页
+
+使用以下内容填充 `pages/index.js`:
+
+```jsx
+function HomePage() {
+ return Welcome to Next.js!
+}
+
+export default HomePage
+```
+
+`Next.js` 是围绕页面的概念构建的。 页面是从 `pages` 目录中的 `.js`、`.jsx`、`.ts` 或 `.tsx` 文件导出的 `React` 组件
+
+### getServerSideProps
+
+
+```jsx
+function Page({ data }) {
+ // 渲染数据...
+}
+
+// 每个请求都会调用它
+export async function getServerSideProps() {
+ // 从外部 API 获取数据
+ const res = await fetch(`https://.../data`)
+ const data = await res.json()
+
+ // 通过 props 向页面传递数据
+ return { props: { data } }
+}
+
+export default Page
+```
+
+如果您从页面导出一个名为 `getServerSideProps`(服务器端渲染)的函数,`Next.js` 将使用 `getServerSideProps` 返回的数据在每个请求上预渲染该页面
+
+- 当您直接请求此页面时,`getServerSideProps` 在请求时运行,此页面将使用返回的 props 进行预渲染
+- 当您通过 `next/link` 或 `next/router` 在客户端页面转换上请求此页面时,`Next.js` 会向服务器发送 API 请求,服务器运行 `getServerSideProps`
+
+### getStaticPaths
+
+
+```jsx
+// pages/posts/[id].js
+export async function getStaticPaths() {
+ // 当这是真的时(在预览环境中)不要预呈现任何静态页面(更快的构建,但更慢的初始页面加载)
+ if (process.env.SKIP_BUILD_STATIC_GENERATION) {
+ return {
+ paths: [],
+ fallback: 'blocking',
+ }
+ }
+
+ // 调用外部 API 端点以获取帖子
+ const res = await fetch('https://.../posts')
+ const posts = await res.json()
+
+ // 根据帖子获取我们要预渲染的路径 在生产环境中,预渲染所有页面
+ // (构建速度较慢,但初始页面加载速度较快)
+ const paths = posts.map((post) => ({
+ params: { id: post.id },
+ }))
+
+ // { fallback: false } 表示其他路由应该 404
+ return { paths, fallback: false }
+}
+```
+
+如果页面具有动态路由并使用 `getStaticProps`,则需要定义要静态生成的路径列表
+
+- 数据来自无头 CMS
+- 数据来自数据库
+- 数据来自文件系统
+- 数据可以公开缓存(非用户特定)
+- 页面必须预渲染(用于 SEO)并且速度非常快 —— `getStaticProps` 生成 HTML 和 JSON 文件,这两种文件都可以由 CDN 缓存以提高性能
+
+### getStaticProps
+
+
+```jsx
+// 帖子将在构建时由 getStaticProps() 填充
+function Blog({ posts }) {
+ return (
+
+ {posts.map((post) => (
+ - {post.title}
+ ))}
+
+ )
+}
+
+// 这个函数在服务器端的构建时被调用。
+// 它不会在客户端调用,因此您甚至可以直接进行数据库查询。
+export async function getStaticProps() {
+ // 调用外部 API 端点以获取帖子。 您可以使用任何数据获取库
+ const res = await fetch('https://.../posts')
+ const posts = await res.json()
+
+ // 通过返回 { props: { posts } },Blog 组件将在构建时接收 `posts` 作为 prop
+ return {
+ props: {
+ posts,
+ },
+ }
+}
+
+export default Blog
+```
+
+在服务器端的构建时被调用
+
+### 增量静态再生
+
+
+```jsx
+function Blog({ posts }) {
+ return (
+
+ {posts.map((post) => (
+ - {post.title}
+ ))}
+
+ )
+}
+
+// 这个函数在服务器端的构建时被调用
+// 如果启用了重新验证并且有新请求进入,它可能会在无服务器功能上再次调用
+export async function getStaticProps() {
+ const res = await fetch('https://.../posts')
+ const posts = await res.json()
+
+ return {
+ props: {
+ posts,
+ },
+ // Next.js 将尝试重新生成页面:
+ // - 当请求进来时
+ // - 最多每 10 秒一次
+ revalidate: 10, // 片刻之间
+ }
+}
+
+// 这个函数在服务器端的构建时被调用
+// 如果尚未生成路径,则可能会在无服务器函数上再次调用它
+export async function getStaticPaths() {
+ const res = await fetch('https://.../posts')
+ const posts = await res.json()
+
+ // 根据帖子获取我们要预渲染的路径
+ const paths = posts.map((post) => ({
+ params: { id: post.id },
+ }))
+
+ // 我们将在构建时仅预渲染这些路径
+ // { fallback: blocking } 如果路径不存在,服务器将按需呈现页面
+ return { paths, fallback: 'blocking' }
+}
+
+export default Blog
+```
+
+- 在初始请求之后和 10 秒之前对页面的任何请求也会被缓存和即时
+- 在 10 秒窗口之后,下一个请求仍将显示缓存的(陈旧的)页面
+- Next.js 在后台触发页面的重新生成
+- 一旦页面生成成功,Next.js 将使缓存失效并显示更新后的页面。如果后台重新生成失败,旧页面仍将保持不变
+
+### 使用 useeffect 客户端数据获取
+
+```jsx
+import { useState, useEffect } from 'react'
+
+function Profile() {
+ const [data, setData] = useState(null)
+ const [isLoading, setLoading] = useState(false)
+
+ useEffect(() => {
+ setLoading(true)
+ fetch('/api/profile-data')
+ .then((res) => res.json())
+ .then((data) => {
+ setData(data)
+ setLoading(false)
+ })
+ }, [])
+
+ if (isLoading) return Loading...
+ if (!data) return No profile data
+
+ return (
+
+
{data.name}
+
{data.bio}
+
+ )
+}
+```
+
+### 使用 SWR 获取客户端数据
+
+```jsx
+import useSWR from 'swr'
+
+const fetcher = (...args) => fetch(...args).then((res) => res.json())
+
+function Profile() {
+ const { data, error } = useSWR('/api/profile-data', fetcher)
+
+ if (error) return Failed to load
+ if (!data) return Loading...
+
+ return (
+
+
{data.name}
+
{data.bio}
+
+ )
+}
+```
+
+### 静态文件服务
+
+Next.js 可以在根目录中名为 `public` 的文件夹下提供静态文件,如图像。 然后,您的代码可以从基本 URL (`/`) 开始引用 `public` 中的文件
+
+```jsx
+import Image from 'next/image'
+
+function Avatar() {
+ return (
+
+ )
+}
+
+export default Avatar
+```
+
+### 支持的浏览器和功能
+
+Next.js 支持零配置的现代浏览器
+
+- Chrome 64+
+- Edge 79+
+- Firefox 67+
+- Opera 51+
+- Safari 12+
+
+
+Next.js 支持在 `package.json` 文件中配置 `Browserslist`
+
+```js
+{
+ "browserslist": [
+ "chrome 64",
+ "edge 79",
+ "firefox 67",
+ "opera 51",
+ "safari 12"
+ ]
+}
+```
+
+内置 CSS 支持
+---
+
+### 添加全局样式表
+
+
+如果不存在,请创建一个 `pages/_app.js` 文件。 然后,导入 `styles.css` 文件
+
+```jsx
+import '../styles.css';
+
+// 在新的“pages/_app.js”文件中需要此默认导出
+export default function MyApp({
+ Component, pageProps
+}) {
+ return
+}
+```
+
+例如,考虑以下名为 `styles.css` 的样式表
+
+```css
+body {
+ font-family:
+ 'SF Pro Text', 'SF Pro Icons',
+ 'Helvetica Neue', 'Helvetica',
+ 'Arial', sans-serif;
+ margin: 0 auto;
+}
+```
+
+### 从 node_modules 导入样式
+
+对于全局样式表,如 `bootstrap` 或 `nprogress`,您应该在 `pages/_app.js` 中导入文件
+
+```jsx
+// pages/_app.js
+import 'bootstrap/dist/css/bootstrap.css'
+
+export default function MyApp({
+ Component, pageProps
+}) {
+ return
+}
+```
+
+从 Next.js 9.5.4 开始,您的应用程序中的任何地方都允许从 `node_modules` 导入 CSS 文件
+
+### 添加组件级 CSS (CSS Modules)
+
+
+您无需担心 .error {} 与任何其他 `.css` 或 `.module.css` 文件!他将被生成 `hash` 名称
+
+```css
+.error {
+ color: white;
+ background-color: red;
+}
+```
+
+然后,创建 `components/Button.js`,导入并使用上面的 CSS 文件:
+
+```jsx
+import styles from './Button.module.css'
+
+export function Button() {
+ return (
+
+ )
+}
+```
+
+### Sass 支持
+
+Next.js 允许您使用 `.scss` 和 `.sass` 扩展名导入 Sass,可以通过 CSS 模块和 `.module.scss` 或 `.module.sass` 扩展名使用组件级 `Sass`
+
+```shell
+$ npm install --save-dev sass
+```
+
+在使用 Next.js 的内置 `Sass` 支持之前,请务必安装 `sass`
+
+### 自定义 Sass 选项
+
+
+通过在 `next.config.js` 中使用 `sassOptions` 来实现配置 `Sass` 编译器。例如添加 `includePaths`:
+
+```js
+const path = require('path')
+
+module.exports = {
+ sassOptions: {
+ includePaths:
+ [path.join(__dirname, 'styles')],
+ },
+}
+```
+
+#### Sass 变量
+
+```sass
+/* variables.module.scss */
+$primary-color: #64ff00;
+
+:export {
+ primaryColor: $primary-color;
+}
+```
+
+在 `pages/_app.js` 中导入 `variables.module.scss`
+
+```jsx
+import variables from '../styles/variables.module.scss'
+
+export default function MyApp({ Component, pageProps }) {
+ return (
+
+
+
+ )
+}
+```
+
+### CSS-in-JS
+
+最简单的一种是内联样式:
+
+```jsx
+function HiThere() {
+ return (
+ hi 这里
+ )
+}
+
+export default HiThere
+```
+
+使用 [styled-jsx](https://github.com/vercel/styled-jsx) 的组件如下所示:
+
+```jsx
+function HelloWorld() {
+ return (
+
+ Hello world
+
scoped!
+
+
+
+ )
+}
+
+export default HelloWorld
+```
+
+当然,你也可以使用 [styled-components](./styled-components.md)
+
+Layouts
+---
+
+### 基础示例
+
+```jsx
+// components/layout.js
+import Navbar from './navbar'
+import Footer from './footer'
+
+export default function Layout({ children }) {
+ return (
+ <>
+
+ {children}
+
+ >
+ )
+}
+```
+
+### 带有自定义应用程序的单一共享布局
+
+```jsx
+// pages/_app.js
+import Layout from '../components/layout'
+
+export default function MyApp({ Component, pageProps }) {
+ return (
+
+
+
+ )
+}
+```
+
+### 使用 TypeScript
+
+
+```jsx
+// pages/index.tsx
+import type { ReactElement } from 'react'
+import Layout from '../components/layout'
+import NestedLayout from '../components/nested-layout'
+import type { NextPageWithLayout } from './_app'
+
+const Page: NextPageWithLayout = () => {
+ return hello world
+}
+
+Page.getLayout = function getLayout(page: ReactElement) {
+ return (
+
+ {page}
+
+ )
+}
+
+export default Page
+```
+
+```jsx
+// pages/_app.tsx
+
+import type { ReactElement, ReactNode } from 'react'
+import type { NextPage } from 'next'
+import type { AppProps } from 'next/app'
+
+export type NextPageWithLayout = NextPage
& {
+ getLayout?: (page: ReactElement) => ReactNode
+}
+
+type AppPropsWithLayout = AppProps & {
+ Component: NextPageWithLayout
+}
+
+export default function MyApp({ Component, pageProps }: AppPropsWithLayout) {
+ // 使用在页面级别定义的布局(如果可用)
+ const getLayout = Component.getLayout ?? ((page) => page)
+
+ return getLayout()
+}
+```
+
+### 每页布局
+
+```jsx
+// pages/index.js
+import Layout from '../components/layout'
+import NestedLayout from '../components/nested-layout'
+
+export default function Page() {
+ return (
+ /** Your content */
+ )
+}
+
+Page.getLayout = function getLayout(page) {
+ return (
+
+ {page}
+
+ )
+}
+```
+
+```jsx
+// pages/_app.js
+export default function MyApp({ Component, pageProps }) {
+ // 使用在页面级别定义的布局(如果可用)
+ const getLayout = Component.getLayout || ((page) => page)
+ return getLayout()
+}
+```
+
+### 数据请求
+
+```jsx
+// components/layout.js
+import useSWR from 'swr'
+import Navbar from './navbar'
+import Footer from './footer'
+
+export default function Layout({ children }) {
+ const { data, error } = useSWR('/api/navigation', fetcher)
+ if (error) return
Failed to load
+ if (!data) return Loading...
+ return (
+ <>
+
+ {children}
+
+ >
+ )
+}
+```
+
+图片优化
+---
+
+### 本地图片
+
+```jsx
+import Image from 'next/image'
+import profilePic from '../public/me.png'
+
+function Home() {
+ return (
+ <>
+ My Homepage
+
+ Welcome to my homepage!
+ >
+ )
+}
+```
+
+### 远程图片
+
+```jsx
+import Image from 'next/image'
+
+export default function Home() {
+ return (
+ <>
+ My Homepage
+
+ Welcome to my homepage!
+ >
+ )
+}
+```
+
+要使用远程图像,`src` 属性应该是一个 `URL` 字符串,可以是相对的也可以是绝对的
+
+### Priority
+
+您应该将优先级属性添加到将成为每个页面的 [Largest Contentful Paint (LCP) 元素](https://web.dev/lcp/#what-elements-are-considered)的图像。 这样做允许 Next.js 专门确定要加载的图像的优先级(例如,通过预加载标签或优先级提示),从而显着提高 LCP
+
+```jsx
+import Image from 'next/image'
+
+export default function Home() {
+ return (
+ <>
+ My Homepage
+
+ Welcome to my homepage!
+ >
+ )
+}
+```
+
+优化字体
+---
+
+### Google 字体
+
+
+自动托管任何 Google 字体。 字体包含在部署中,并从与您的部署相同的域提供服务。 浏览器不会向 Google 发送任何请求
+
+```jsx
+// pages/_app.js
+import { Inter } from '@next/font/google'
+
+// 如果加载可变字体,则无需指定字体粗细
+const inter = Inter({ subsets: ['latin'] })
+
+export default function MyApp({
+ Component, pageProps
+}) {
+ return (
+
+
+
+ )
+}
+```
+
+### 指定粗细
+
+
+如果不能使用可变字体,则需要指定粗细:
+
+```jsx {5}
+// pages/_app.js
+import { Roboto } from '@next/font/google'
+
+const roboto = Roboto({
+ weight: '400',
+ subsets: ['latin'],
+})
+
+export default function MyApp({
+ Component, pageProps
+}) {
+ return (
+
+
+
+ )
+}
+```
+
+### 数组指定多个 weight 或 style
+
+```jsx
+const roboto = Roboto({
+ weight: ['400', '700'],
+ style: ['normal', 'italic'],
+ subsets: ['latin'],
+})
+```
+
+### 在 \ 中应用字体
+
+```jsx
+// pages/_app.js
+import { Inter } from '@next/font/google'
+const inter = Inter({ subsets: ['latin'] })
+export default function MyApp({ Component, pageProps }) {
+ return (
+ <>
+
+
+ >
+ )
+}
+```
+
+### 单页使用
+
+```jsx
+// pages/index.js
+import { Inter } from '@next/font/google'
+
+const inter = Inter({ subsets: ['latin'] })
+
+export default function Home() {
+ return (
+
+ )
+}
+```
+
+### 指定一个子集
+
+```jsx
+// pages/_app.js
+const inter = Inter({ subsets: ['latin'] })
+```
+
+在 `next.config.js` 中全局使用所有字体
+
+```js
+// next.config.js
+module.exports = {
+ experimental: {
+ fontLoaders: [
+ {
+ loader: '@next/font/google',
+ options: { subsets: ['latin'] }
+ },
+ ],
+ },
+}
+```
+
+如果两者都配置,则使用函数调用中的子集
+
+### 本地字体
+
+
+```jsx
+// pages/_app.js
+import localFont from '@next/font/local'
+
+// 字体文件可以位于“pages”内
+const myFont = localFont({
+ src: './my-font.woff2'
+})
+
+export default function MyApp({
+ Component, pageProps
+}) {
+ return (
+
+
+
+ )
+}
+```
+
+如果要为单个字体系列使用多个文件,`src` 可以是一个数组:
+
+```jsx
+const roboto = localFont({
+ src: [
+ {
+ path: './Roboto-Regular.woff2',
+ weight: '400',
+ style: 'normal',
+ },
+ {
+ path: './Roboto-Italic.woff2',
+ weight: '400',
+ style: 'italic',
+ },
+ {
+ path: './Roboto-Bold.woff2',
+ weight: '700',
+ style: 'normal',
+ },
+ {
+ path: './Roboto-BoldItalic.woff2',
+ weight: '700',
+ style: 'italic',
+ },
+ ],
+})
+```
+
+### 使用 Tailwind CSS
+
+
+```jsx
+// pages/_app.js
+import { Inter } from '@next/font/google'
+const inter = Inter({
+ subsets: ['latin'],
+ variable: '--font-inter',
+});
+export default function MyApp({ Component, pageProps }) {
+ return (
+
+
+
+ )
+}
+```
+
+最后,将 CSS 变量添加到您的 Tailwind CSS 配置中:
+
+```jsx
+// tailwind.config.js
+const { fontFamily } = require('tailwindcss/defaultTheme')
+
+module.exports = {
+ content: [
+ './pages/**/*.{js,ts,jsx,tsx}',
+ './components/**/*.{js,ts,jsx,tsx}',
+ ],
+ theme: {
+ extend: {
+ fontFamily: {
+ sans: ['var(--font-inter)', ...fontFamily.sans],
+ },
+ },
+ },
+ plugins: [],
+}
+```
+
+优化 Scripts
+---
+
+### 页面脚本
+
+```jsx
+import Script from 'next/script'
+
+export default function Dashboard() {
+ return (
+ <>
+
+ >
+ )
+}
+```
+
+### App 脚本
+
+
+要为所有路由加载第三方脚本,导入 `next/script` 并将脚本直接包含在 `pages/_app.js` 中
+
+```jsx
+import Script from 'next/script'
+
+export default function MyApp({
+ Component, pageProps
+}) {
+ return (
+ <>
+
+
+ >
+ )
+}
+```
+
+### 将脚本卸载到 Web Worker(实验性的)
+
+
+此策略仍处于试验阶段,只有在 `next.config.js` 中启用了 `nextScriptWorkers` 标志时才能使用:
+
+```js
+module.exports = {
+ experimental: {
+ nextScriptWorkers: true,
+ },
+}
+```
+
+设置完成后,定义 `strategy="worker"` 将自动在您的应用程序中实例化 `Partytown` 并将脚本卸载到网络工作者
+
+```jsx
+import Script from 'next/script'
+
+export default function Home() {
+ return (
+ <>
+
+ >
+ )
+}
+```
+
+### 其他属性
+
+```jsx
+import Script from 'next/script'
+
+export default function Page() {
+ return (
+ <>
+
+ >
+ )
+}
+```
+
+### 内联脚本
+
+
+```jsx
+
+```
+
+```jsx
+
+```
+
+### 执行附加代码
+
+```jsx
+import Script from 'next/script'
+
+export default function Page() {
+ return (
+ <>
+