经过足足70个canary版本之后,Next.js 9终于正式发布了!

2020-12-23 19:27

阅读:700

  • 内置零配置 TypeScript 支持:开发者可以借助自动化 TypeScript 支持和集成的类型检查更方便地构建应用。
  • 基于文件系统的动态路由:无需自定义服务器即可通过文件系统表达复杂的应用路由需求。
  • 自动静态优化:利用默认的服务端渲染和静态预渲染提升网站速度,同时不牺牲功能。
  • API 路由: 利用热重载和统一的构建管道快速构建后端应用程序端点。
  • 更多生产优化:通过视口内预取等优化提升应用的响应能力。
  • 提升开发体验:一系列细微、易用的改进,改善开发工作体验。
    这些优势都会尽可能向后兼容。大多数 Next.js 应用只需运行下列代码即可升级到新版:

    npm i next@latest react@latest react-dom@latest

    应用代码库需要改动的情况很少。详细信息可参阅升级指南: https://github.com/zeit/next.js/blob/canary/UPGRADING.md
    基于 Next.js 的网站案例很多,包括 IGN、Bang&Olufsen、Intercom、Buffer 和 Ferrari 等等。更多案例可参见: https://nextjs.org/showcase。

    内置零配置 TypeScript 支持

    一年前的 Next.js 6 通过名为 @zeit/next-typescript 的插件引入了 TypeScript 的基础支持。用户还必须自定义他们的.babelrc 并在 next.config.js 中启用它。
    这个插件配置好后允许 Next.js 构建.ts 和.tsx 文件。但它没有集成类型检查,也没有 Next.js 核心提供的类型。于是开发者必须在 DefinitelyTyped 中单独维护社区包,可能没法及时更新内容。
    据调研,大多数新老用户都对使用 TypeScript 非常感兴趣。他们需要一种更可靠、更标准化的解决方案,从而将 TypeScript 轻松集成到现有或新的代码库中。
    所以 Next.js 核心开始集成 TypeScript 支持,改善了开发人员的体验,并加快了相关流程。
    自动安装
    在 Next.js 中使用 TypeScript 非常简单:将任何文件、页面或组件从.js 重命名为.tsx,然后运行 next dev 即可。
    随后 Next.js 就会知道项目中正在使用 TypeScript 了。Next.js CLI 将指导开发者为 React 和 Node.js 安装必要的类型。
    Next.js 还将创建一个默认的 tsconfig.json,其中包含一些默认值(如果尚未存在)。此文件可以用来在 Visual Studio Code 等编辑器中进行集成类型检查。
    技术图片
    Next.js 9 自动 TypeScript 设置

    集成类型检查

    Next.js 会在开发者开发和生产构建时处理类型检查。
    在开发过程中,Next.js 会在保存文件后显示类型错误。类型检查在后台执行,应用更新会立即反映在浏览器中。类型错误一旦可用就会传到浏览器中。
    技术图片
    Next.js 9 开发时类型检查
    如果存在类型错误,Next.js 会自动让生产构建失败(例如下图中的“next build”)。这样错误的代码就不会进入生产版本。
    技术图片
    Next.js 9 生产类型检查
    用 TypeScript 编写的 Next.js 核心
    现在 Next.js 的大部分代码库已经迁移到 TypeScript 上,不仅增强了 Next.js 的代码质量,而且现在所有核心模块都提供了类型。
    例如,当导入 next/link 时,支持 TypeScript 的编辑器将显示允许的属性以及它们接受的值。
    技术图片
    Next.js 核心类型

    动态路由

    动态路由(也称为 URL Slugs 或 Pretty/Clean URL)是两年半前 Next.js 发布后,GitHub 上的第一批功能请求之一。
    Next.js 2.0 引入了自定义服务器 API,开发者能以编程方式使用 Next.js,“解决”了这个需求。Next.js 可以作为呈现引擎,启用传入 URL 的抽象和映射以呈现某些页面。
    据官方调研,许多应用都使用了自定义服务器。自定义服务器最常见的用途是动态路由。
    但是自定义服务器也有自己的缺陷:路由在服务器级而不是代理级处理,它作为整体部署和扩展,并且容易出现性能问题。
    由于自定义服务器要求整个应用程序跑在一个实例上,通常很难把它部署到无服务器环境来解决上述问题。无服务器请求是在代理层路由的,并独立扩展 / 执行以消除性能瓶颈。
    开发者创建一个名为 pages/blog.js 的文件后就能在 /blog 下面有一个可访问页面了,然后就进入了 Next.js 的魔法世界。那么为什么用户需要创建自己的服务器,还要学习 Next.js 的可编程 API 才能支持像 /blog/my-first-post (/blog/:id)这样的路由呢?官方开始探索新的路由映射方案,新的解决方案从 pages/ 目录入手。
    创建动态路由页面
    Next.js 支持使用基本命名参数创建路由,这是一种由 path-to-regexp(Express 的库)推广的模式。
    现在开发者可以在 pages 目录中创建名为:pages/post/[pid] .js 的文件来创建与 /post/:pid 路由匹配的页面了。
    Next.js 将自动匹配 /post/1、/post/hello-nextjs 等请求,并呈现 pages/post/[pid] .js 中定义的页面。匹配的 URL 段将作为查询参数传递到你的页面,其名称在 [方括号] 之间指定。
    例如: 给定以下页面和 /post/hello-nextjs 请求,查询对象将是{pid:‘hello-nextjs‘}:

    static async getInitialProps({ query }) {
    //pid = ‘hello-nextjs‘
    const { pid } = query
    
    const postContent = await fetch(
    `https://api.example.com/post/${encodeURIComponent(pid)}`
    ).then(r => r.text())
    
    return { pos
    ```tContent }
    }
    新版还支持多个动态 URL 段。
    目录名称和文件名支持 [param] 语法,示例如下:

    ./pages/blog/[blogId]/comments/[commentId].js
    ./pages/posts/[pid]/index.js

    更多信息可参考Next.js 文档或Next.js 学习部分。
    相关链接:
    Next.js 文档: https://github.com/zeit/next.js#dynamic-routing
    Next.js 学习部分: https://nextjs.org/learn/basics/clean-urls-with-dynamic-routing
    ### 自动静态优化
    Next.js 在大约两年前发布的 v3 版本中增加了对静态网站生成的支持。
    理由很简单:静态网站速度很快,它们不需要服务器端计算,数据可以立即从 CDN 服务器传输到最终用户。
    但是,之前的版本中服务端呈现或静态生成的应用程序不可兼得,要么选择服务端呈现要么是静态生成,没有中间答案。
    实际上应用可以有不同的需求。这些需求需要不同的呈现策略和取舍。
    例如,主页和营销页面通常包含静态内容,是静态优化的理想场景。
    另一方面,产品介绍页可能更适合数据频繁更新的服务端呈现。
    于是官方开始探索更好的方案,试图为每个场景自动选择最快的途径,比如为宣传页面静态输出,为介绍页面做动态服务端呈现。
    从 Next.js 9 开始,用户无需在完全服务器呈现或静态导出其应用之间做二选一了。新版可以在不同页面上使用不同的策略。
    **自动部分静态导出**
    新版引入了一种启发式方法来自动确定页面是否可以预呈现为静态 HTML。
    程序使用 getInitialProps 判断页面是否有阻止数据的需求来作出选择。
    这样一来,Next.js 就可以创建 同时包含服务器呈现和静态生成页面的混合应用。
    内置的 Next.js 服务器(next start)和编程 API(app.getRequestHandler())都 透明地 支持这种构建输出。无需配置或特殊处理。
    静态生成的页面仍然是反应式的:Next.js 将为应用客户端进行 hydrate 操作,使其具有完整的交互性。
    此外,如果页面依赖于 URL 中的查询参数,Next.js 将在 hydrate 操作后更新你的应用程序。
    在开发期间静态生成页面时 Next.js 会弹出通知告知开发者。单击通知即可隐藏。
    ![](https://s4.51cto.com/images/blog/202012/18/fbee3ec6345f31b5f298f771ec9be371.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=)
    Next.js 静态优化指标
    静态生成的页面也将显示在 Next.js 的构建输出中:
    ![](https://s4.51cto.com/images/blog/202012/18/6fb43223bb8e9fb33b047ecf0520c46c.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=)
    Next.js 构建输出类型指示
    ### API 路由
    许多情况下,开发者在构建 React 应用程序时需要某种后端,用来从数据库检索数据或处理用户提供的数据(例如联系表单)。
    官方调研发现许多需要后端的用户使用自定义服务器构建了他们的 API,结果遇到了很多问题。例如,Next.js 不编译自定义服务器代码,这意味着开发者无法使用导入 / 导出或 TypeScript。
    因此许多用户最后在自定义服务器之上实现了他们自己的自定义编译管道。虽然这解决了他们的需求,但也容易出现许多陷阱:例如,树抖动(tree shaking)配置不正确时会在整个应用程序中禁用。
    现在 Next.js 9 引入了 API 路由,为开发者构建后端带来了最佳体验。
    要开始使用 API路由,请在 pages/ 目录中创建名为 api/ 的目录。
    此目录中的任何文件都将自动映射到 /api/,就像其他页面文件映射到路由一样。
    例如,pages/api/contact.js 将映射到 /api/contact。
    注意:API 路由也支持动态路由。
    pages/api/ 目录中的所有文件都导出一个请求处理函数,而不是 React 组件:

    export default function handle(req, res) {
    res.end(‘Hello World‘)
    }

  • req 指的是扩展 http.IncomingMessage 的 NextApiRequest。
  • res 指的是扩展 http.ServerResponse 的 NextApiResponse。
    通常来说,API 端点接收一些传入数据,例如查询字符串、请求正文或 cookie,并使用其他数据响应。
    官方调研发现,许多情况下用户没有直接使用 Node.js 请求和响应对象。相反,他们使用了像 Express 这样的服务器库提供的抽象。
    这样做的原因是,在许多情况下传入数据是某种形式的文本,必须首先解析才有用。因此用这些服务器库后就不用手动解析数据了,最常见的方式是通过中间件。最常用的中间件提供了查询字符串、正文和 cookie 解析的功能,但是它们仍然需要做一些设置才能用。
    Next.js 中的 API 路由将默认提供这些中间件,以便开发者快速高效地创建 API 端点:
    export default function handle(req, res) {
    console.log(req.body)//The request body
    console.log(req.query)//The url querystring
    console.log(req.cookies)//The passed cookies
    res.end(‘Hello World‘)
    }

    除了使用传入数据,API 端点通常也会返回数据,通常返回的是 JSON。默认情况下,Next.js 提供 res.json() 以简化发送操作:

    export default function handle(req, res) {
    res.json({ title: ‘Hello World‘ })
    }

    在开发中更改 API 端点时,代码会自动重新加载,因此无需重新启动服务器。

    生产优化

    预取视口内的
    Next.js 9 将自动预取出现在视口内(in viewport)的组件。
    此功能可以加快跳转到新页面的速度,从而提高应用程序的响应速度。
    Next.js 使用 Intersection Observer 预取后台必需的资源 : https://www.w3.org/TR/resource-hints/#prefetch
    这些请求优先级较低,并且产生 fetch() 或 XHR 请求。如果用户启用了数据保护,Next.js 将避免自动预取。
    在用户很少访问的页面上将 prefetch 属性设置为 false 即可关闭此功能:

    
    Terms of Service
    

    默认的 AMP 优化
    Next.js 9 现在默认为 AMP(移动页面加速)优先和混合 AMP 页面呈现优化的 AMP。
    虽然 AMP 页面是可选的,但 Next.js 会自动优化其输出。这些优化可以使呈现速度提高 50%。
    这里要感谢 Sebastian Benz 为 AMP Optimizer 带来的改进: https://github.com/ampproject/amp-toolbox/tree/master/packages/optimizer
    typeof window 分支的无效代码清理
    Next.js 9 在服务器和客户端构建期间用适当的值(undefined 或 object)替换 typeof window。此更改使 Next.js 可以自动从生产构建的应用程序中删除无效代码。
    如果用户在 getInitialProps 或应用程序的其他部分中写了纯服务端代码,那么就能注意到客户端包变小了。

    改善开发体验

    编译指示器
    在之前的版本中,开发者只能查看开发者控制台才能知道热代码替换即将执行(并且 Next.js 编译工具链正在工作)。
    然而很多时候,人们正在查看生成的呈现,很难知道 Next.js 是否仍在编译。例如,开发者可能正在对页面上的样式做些小改动,结果没法第一时间知道它们是否已更新过。
    官方为此创建了一个 RFC/“第一个好问题” 的页面,以探讨这个问题的可行解决方案: https://github.com/zeit/next.js/issues/4626
    官方收到了许多设计师和工程师在 RFC 上的反馈。其中 Rafael Almeida 借此机会与官方团队合作,实现了一个全新的指标,并引入了 Next.js 9。
    现在每当 Next.js 执行编译工作时,开发者会看到页面右下角出现一个小三角形。
    技术图片
    Next.js 编译指标
    控制台输出
    传统上,开发者在开发中进行更改时,Next.js 会显示一个编译指示器状态,并在开发者作出更改时清屏。
    这种行为会导致一些问题。最值得注意的是,它会从应用程序代码中清除控制台输出,例如,当你将 console.log 添加到组件时就会这样。使用外部工具将日志输出拼接在一起时也会清除控制台输出,如 Now CLI 或 docker-compose。
    从 Next.js 9 开始日志输出跳跃变少,也不再清屏。这样可以提供更好的体验,因为终端窗口将显示更多相关信息,闪烁也更少了,同时 Next.js 能更好地与你正在使用的工具集成。
    技术图片
    Next.js 开发控制台输出
    这里特别感谢 Justin Chase 的贡献: https://github.com/justinmchase
    构建输出统计
    使用 next build 构建生产应用时,它将为你提供所有已构建页面的详细视图。
    每个页面都会自动收到一些统计信息
    最显眼的是包大小。随着应用程序的增长,你的 JavaScript 包也会变大,这个构建时指示可以告诉开发者生产包变大了多少。将来的版本中开发者还可以为生产构建失败的页面设置性能预算: https://addyosmani.com/blog/performance-budgets/
    技术图片
    Next.js 构建出的页面大小
    除了包大小,新版还展示了每个页面中使用了多少个项目组件和 node_modules 组件,以帮助开发者了解页面的复杂度。
    技术图片
    Next.js 页面包计数
    每个页面还有一个指示,告诉开发者它是静态优化还是服务端呈现,因为每个页面的行为都可能不一样。
    技术图片
    Next.js 构建页面类型
    每页配置对象
    现在每个页面都可以导出配置对象。一开始这个配置允许你选择启用 AMP,但将来你能配置更多页面特定选项。

    
    //pages/about.js
    export const config = { amp: true }


评论


亲,登录后才可以留言!