Next.js 9.5 发布:支持 Webpack 5

作者 | Next.js 团队

译者 | 王强

策划 | 李俊辰

Next.js 9.5 发布,具体有这些内容。

Next.js 9.5 今天正式发布了,其改进包括:

  • 稳定的增量静态再生 :部署后以毫秒为单位重建静态页面

  • 可自定义的基本路径 :在域的子路径上轻松托管 Next.js 项目

  • 支持重写、重定向和标头 :重写虚拟 URL,重定向旧 URL,向静态页面添加标头

  • URL 中的可选尾斜杠 :始终强制去除 / 显示尾斜杠

  • 永久缓存页面包 :未更改页面的 JavaScript 文件现在可以在各个版本之间继承

  • 快速刷新增强 :增强了 Next.js 实时编辑体验的可靠性

  • Production React Profiling :衡量项目渲染“成本”的新标志

  • 可选的“捕获所有路由” :动态路由现在为 SEO 驱动的用例提供了更大的灵活性

  • Webpack 5 支持(测试版) :可选地加入 Webpack 5,以改进构建体积和速度

稳定的增量静态再生

Next.js 在 9.3 版中引入了静态网站生成方法,其目标很明确:我们应该获得静态的优势(一直很快,一直在线,全局复制),但是对动态数据的出色支持也不能丢,后者是 Next.js 的看家本领。

为了两全其美,Next.js 引入了 增量静态生成 ,在你构建站点之后更新静态内容。使用 getStaticPaths 中的 fallback: true 选项,可以 在运行时注册新的静态页面

无论你的数据集有多大,Next.js 都可以按需静态地预渲染无数个页面。

今天, 增量静态再生 功能已对所有用户开放了,这是一种在流量进入时于后台重新渲染现有页面来 更新它们 的机制。

受 stale-while-revalidate 的启发,后台再生可确保始终从静态存储中无间断地处理流量,并且仅在生成完成后才推送新建页面。

export async function getStaticProps() {
  return {
    props: await getDataFromCMS(),
    // we will attempt to re-generate the page:
    // - when a request comes in
    // - at most once every second
    revalidate: 1 
  }
}

revalidate 标志是秒数,在此时间内最多有一次生成,以防止:

https://en.wikipedia.org/wiki/Cache_stampede

与传统的 SSR 不同,增量静态再生可为你保留静态的优势:

  • 延迟不会暴涨。页面一直都能快速渲染。

  • 页面永远不会脱机。如果后台页面再生失败,则旧页面保持不变。

  • 数据库和后端负载较低。页面最多同时重新计算一次。

增量功能(添加页面和延迟更新它们)及预览模式现在都已稳定,并得到了 next start 和 Vercel edge 平台的完全支持。

我们创建了一个示例演示了再生静态页面的过程,该页面显示了某个 GitHub 问题的各种互动的计数:

https://reactions-demo.now.sh/

首次访问并点赞后,后台会生成新的页面。整个过程中的每个请求均由静态缓存提供。

接下来团队将开发另外两个增量静态生成功能:

  • 一次再生并作废多个页面(例如你的博客索引或某篇博文)

  • 在用户流量之前监听事件(例如 CMS webhooks)来再生

更多详细信息,请查阅 getStaticProps 文档。

https://nextjs.org/docs/basic-features/data-fetching#getstaticprops-static-generation

可自定义的基本路径

Next.js 项目并非总是从域的根目录提供的。有时,你可能希望将 Next.js 项目托管在 /docs 之类的子路径下,以便 Next.js 项目只覆盖域的这一子部分。

虽然之前我们也可以这样做,但它需要大量额外配置,比如在每个<Link>中添加前缀,并确保 Next.js 从正确的路径提供了 JavaScript 包。

为了解决这个痛点,新版引入了一个新的配置选项 basePath,允许你轻松将 Next.js 项目托管在域的子路径上。

要开始使用 basePath,可以将其添加到 next.config.js:

// next.config.js
module.exports = {
  basePath: '/docs'
}

配置 basePath 之后,你的项目将自动从提供的路径路由。本例中为 /docs。

当使用 next/link 或 next/router 链接到项目中的其他页面时,basePath 将自动添加前缀。这使你无需更改项目即可更改 basePath。

例如,使用 next/link 路由到另一个页面:

import Link from 'next/link'
export default function HomePage() {
  return (
    <>
      <Link href="/documentation-page">
        <a>Documentation page</a>
      </Link>
    </>
  )
}

以这种方式使用 next/link 将导致以下 HTML 渲染到 Web 浏览器:

<a href="/docs/documentation-page">Documentation page</a>

更多详细信息,请参阅 basePath 文档。

https://nextjs.org/docs/api-reference/next.config.js/basepath

支持重写、重定向和标头

重写

在构建 Next.js 项目时,你可能希望将某些路由代理到另一个 URL。例如,如果要逐渐将 Next.js 引入技术栈,则需要路由 Next.js 项目中已有的页面,然后路由所有与要迁移的旧项目不匹配的页面。

Next.js 9.5 引入了一个名为 rewrites 的配置选项,允许你将传入的请求路径映射到其他目标路径上,包括外部 URL。

例如,你可能想重写一条通往 example.com 的路由:

// next.config.js
module.exports = {
  async rewrites() {
    return [
      { source: '/backend/:path*', destination: 'https://example.com/:path*' }
    ]
  }
}

在这里,/backend 下的所有路径都将路由到 example.com。你还可以检查 Next.js 项目的路由是否匹配,如果不匹配,则重写到之前的项目。这非常适合 渐进采用 Next.js 的场景:

module.exports = {
  async rewrites() {
    return [
      // check if Next.js project routes match before we attempt proxying
      {
        source: '/:path*',
        destination: '/:path*'
      },
      {
        source: '/:path*',
        destination: `https://example.com/:path*`
      }
    ]
  }
}

在这里我们首先匹配所有路径。如果没有匹配项,我们将代理到 example.com,也就是先前的项目。更多信息请查看重写文档:

https://nextjs.org/docs/api-reference/next.config.js/rewrites

重定向

多数网站多少需要一些重定向,特别是在更改项目路由的结构时。例如将 /blog 移至 /news 或类似的转换。

以前,在 Next.js 项目中设置重定向列表时,需要设置自定义服务器或自定义 _error 页面,以检查是否为路由设置了重定向。但这会抵消静态优化和无服务器优化(因为有了服务器)的效果。

从 Next.js 9.5 开始,你现在可以在 next.config.js 中的 redirects 键下创建重定向列表:

// next.config.js
module.exports = {
  async redirects() {
    return [
      {
        source: '/about',
        destination: '/',
        permanent: true
      }
    ]
  }
}

更多信息请查看重定向文档:

https://nextjs.org/docs/api-reference/next.config.js/redirects

标头

Next.js 允许你构建同时使用静态生成和服务端渲染的混合项目。使用服务端渲染可以为传入请求设置标头。对于静态页面,之前的版本无法设置标头。

新版在 next.config.js 中引入了 headers 属性,该属性适用于所有 Next.js 路由:

// next.config.js
module.exports = {
  async headers() {
    return [
      {
        source: '/:path*',
        headers: [
          {
            key: 'Feature-Policy',
            // Disable microphone and geolocation
            value: "microphone 'none'; geolocation 'none'"
          }
        ]
      }
    ]
  }
}

headers 选项允许你设置常用的标头,例如 Feature-Policy 和 Content-Security-Policy。更多信息请查看标头文档:

https://nextjs.org/docs/api-reference/next.config.js/headers

URL 中的可选尾斜杠

Next.js 在 3 年前刚时,其默认行为是所有带有尾斜杠的 URL 始终返回 404 页面。

一些用户要求能够更改这一行为。例如,需要迁移的旧项目可能一直强制使用尾斜杠。

Next.js 9.5 在 next.config.js 中引入了一个名为 trailingSlash 的新选项。

这一选项可确保 Next.js 自动处理斜杠行为:

  • 自动将尾斜杠 URL 重定向到没有尾斜杠的 URL,例如:/about/ 到 /about

  • 当 trailingSlash 设置为 true 时,不带斜杠的 URL 将被重定向到带斜杠的 URL,例如:/about 到 /about/

  • 确保 next/link 具有自动应用 / 删除的尾斜杠,以避免不必要的重定向。

// next.config.js
module.exports = {
  // Force a trailing slash, the default value is no trailing slash (false)
  trailingSlash: true
}

更多信息请查看 trailingSlash 文档:

https://nextjs.org/docs/api-reference/next.config.js/trailing-slash)。

持久缓存页面包

编写 Next.js 页面时,所有脚本包、CSS 样式表和 HTML 的创建都是完全自动化并抽象出来的。如果你在 Next.js 之前的版本中检查生成的< script>标志,会发现它们的 URL 遵循以下格式:

/_next/static/ovgxWYrvKyjnlM15qtz7h/pages/about.js

上面的路径段 ovgxWYrvKyjnlM15qtz7h 是所谓的内部版本 ID。尽管这些文件可以在边缘和用户机器上轻松缓存,但是在重新构建应用之后,构建 ID 将会更改并且所有缓存都将被清除。对于大多数项目来说,这种折衷是可以容忍的,但 Next.js 团队希望不再让未更改页面的浏览器缓存失效,以进一步优化这一行为。

与谷歌 Chrome 团队合作开发的代码拆分改进策略在 9.2 版中引入,为 Next.js 页面包生成的这些改进奠定了基础。

从 Next.js 9.5 开始, 所有页面 JavaScript 包都将使用内容哈希代替构建 ID 。这允许在各个部署之间未更改的页面保留在浏览器和边缘缓存中,而无需再次下载。

新的 URL 模式如下所示:

/_next/static/chunks/pages/about.qzfS4o5gIEXRME6sTEahL.js

qzfS4o5gIEXRME6sTEahL 部分是 about.js 包的确定哈希,而不是全局构建 ID,所以是稳定的,因为你站点的这部分代码不会更改。此外,它现在已通过 Cache-Control: public,max-age=31536000,immutable 在各个部署之间实现了长期缓存,Next.js 会自动为你设置。

快速刷新增强

Next.js 9.4 中引入了快速刷新(Fast Refresh),这是一种新的热重载体验,可为你提供对 React 组件所做编辑的即时反馈。

Next.js 9.5 进一步完善了快速刷新实现,并为你提供了很多好用的工具:

  • 易于理解的错误 :所有编译和运行时错误均已更新,仅显示相关信息,包括导致错误的代码的代码框架。

  • 保持组件状态的开发时提示 :Next.js 现在为你提供有用的提示,以确保“快速刷新”在尽可能多的场景中保持组件状态。Next.js 提供的每个提示都是 完全可动作 的,并带有实施前后的示例对比!

  • 重置组件状态时的警告 :现在,当 Next.js 在文件编辑后无法保持组件状态时将打印详细警告。此警告将帮助你诊断为什么项目必须重置组件状态,从而可以修复相关问题并充分利用快速刷新。

  • 新的文档 :新版添加了内容丰富的文档( https://nextjs.org/docs/basic-features/fast-refresh),这些文档解释了什么是快速刷新,其工作机制以及你可以期望的内容!该文档还解释了错误恢复的机制,教你如何更好地利用“快速刷新”。

  • 用户代码故障排除指南 :新文档还包括常见的故障排除步骤,以及关于如何充分利用快速刷新的提示。

Production React Profiling

React 不久前引入了 Profiler API,通过它可以跟踪 React 组件中的性能问题。尽管此功能在开发中会自动运行,但它需要使用单独的 ReactDOM 版本在生产中做 profile。

在 Next.js 9.5 中,你现在可以在 next bulid 中使用 --profile 标志启用 React 的生产 profiling:

next build --profile

之后,你可以像开发环境中那样使用 profiler。更多信息,请阅读 React 团队关于 React Profiler 的文章:

https://reactjs.org/blog/2018/09/10/introducing-the-react-profiler.html

可选捕获所有路由

Next.js 9.2 添加了捕获全部(catch-all)动态路由的支持,且已被社区广泛用于各种用例。捕获全部路由使你能够灵活地创建由无头 CMS、GraphQL API 和文件系统等支持的高度动态的路由结构。

用户希望有更大的灵活性来匹配路由的最根部层。新版为这些高级场景提供了 可选的捕获全部动态路由

要创建可选的捕获全部路由,可以使用 [[...slug]] 语法创建页面。

例如,pages/blog/[[...slug]].js 将匹配 /blog 及其下面的任何路由,如:/blog/a、/blog/a/b/c 等。

与捕获全部路由一样,在路由器查询对象中将以各个路径部分的数组形式提供 slug。因此,对于 /blog/foo/bar 路径,查询对象将为{slug: ['foo', 'bar']}。对于路径 /blog,查询对象将省略 slug 键:{ }。

更多信息见可选的捕获全部路由文档:

https://nextjs.org/docs/routing/dynamic-routes#optional-catch-all-routes

Webpack 5 支持(测试版)

Webpack 5 当前处于测试状态。它包括一些重大改进:

  • 改进的摇树优化:嵌套的导出,内部模块和 CommonJS 会被摇树优化

  • 持久缓存:允许重复使用以前版本中的工作

  • 确定性块和模块 ID:解决 Webpack 模块 ID 在构建之间更改的问题

Next.js 9.5 提供了 webpack 5 的 beta 版支持。

要试用 webpack 5,可以在 package.json 中使用 Yarn resolutions:

{
  "resolutions": {
    "webpack": "^5.0.0-beta.22"
  }
}

Webpack 5 beta 已推到 nextjs.org 和 vercel.com 的生产环境。你可以渐进尝试它,并在 GitHub 上报告你的发现。

https://github.com/vercel/next.js/issues/13341

编译基础架构改进

为了支持 webpack 5,新版重写了许多编译管道,使其更适合 Next.js:

  • Next.js 不再依赖 webpack-hot-middleware 和 webpack-dev-middleware,而是直接使用 webpack 并专门针对 Next.js 项目做了优化。这意味着更简单的架构和更快的开发编译。

  • On-demand-entries 这个系统(Next.js 必须允许它在开发过程中的某个时间被访问的页面上进行编译)也已被重写,并且现在利用了专为新的用例优化的 webpack 行为,因此更为可靠。

  • React Fast Refresh 和 Next.js Error Overlay 现在与 webpack 5 完全兼容。

  • 将来的 beta 版本中将启用磁盘缓存。

向后兼容

Webpack 4 将继续得到完全支持。Next.js 团队正在与 webpack 团队紧密合作,以确保从 webpack4 到 5 的迁移尽可能顺利。

如果你的 Next.js 项目没有自定义 webpack 配置,则无需更改项目即可充分利用 webpack 5。

重要提示:如果你的项目具有自定义的 webpack 配置,则可能需要进行一些更改才能过渡到 webpack 5。建议你留意迁移说明,或尽量少用 webpack 扩展程序,以实现无缝升级。

改进了 macOS 上的文件监视

Webpack 上有一个问题是,对代码进行一些更改后,macOS 上的文件监视将停止。你必须手动重新启动项目才能再次查看更新。再做一些更改后又会停止监视,如此循环。

这个问题不仅发生在 Next.js 项目中,还发生在基于 webpack 的所有项目和框架中。

其根本原因在于 webpack 使用的称为 chokidar 的文件监视实现,chokidar 是 Node.js 生态系统中广泛使用的文件监视实现。

开发团队向 chokidar 发送了补丁以解决此问题。补丁发布后,Webpack 新版中打上了它。

升级到 Next.js 9.5 时,将自动使用这个修补过的 webpack 版本。

    小结    

Next.js 的采用率正在持续增长:

  • 自 9.4 版本以来,项目已经有 1200 多位独立贡献者,其中有超过 135 位新贡献者。

  • 在 GitHub 上,项目已经有超过 51,100 星。

你可加入 GitHub Discussions 的 Next.js 社区。这是一个社区空间,你可以与其他 Next.js 用户联系,并自由提问或分享你的工作。

https://github.com/vercel/next.js/discussions

延伸阅读

https://nextjs.org/blog/next-9-5

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
index.js:4130 Cannot find module './uni_modules/uview-ui/components/u-navbar/u-navbar.vue' Qld0 @ index.js:4130 __webpack_require__ @ index.js:854 fn @ index.js:151 JLrY @ index.js:1430 __webpack_require__ @ index.js:854 fn @ index.js:151 eval @ kyBj:2 kyBj @ index.js:4897 __webpack_require__ @ index.js:854 fn @ index.js:151 eval @ main.js:36 Tglg @ index.js:4322 __webpack_require__ @ index.js:854 fn @ index.js:151 1 @ index.js:1057 __webpack_require__ @ index.js:854 checkDeferredModules @ index.js:46 (anonymous) @ index.js:994 (anonymous) @ index.js:997 index.js:4131 1. 排查组件名称拼写是否正确 Qld0 @ index.js:4131 __webpack_require__ @ index.js:854 fn @ index.js:151 JLrY @ index.js:1430 __webpack_require__ @ index.js:854 fn @ index.js:151 eval @ kyBj:2 kyBj @ index.js:4897 __webpack_require__ @ index.js:854 fn @ index.js:151 eval @ main.js:36 Tglg @ index.js:4322 __webpack_require__ @ index.js:854 fn @ index.js:151 1 @ index.js:1057 __webpack_require__ @ index.js:854 checkDeferredModules @ index.js:46 (anonymous) @ index.js:994 (anonymous) @ index.js:997 index.js:4132 2. 排查组件是否符合 easycom 规范,文档:https://uniapp.dcloud.net.cn/collocation/pages?id=easycom Qld0 @ index.js:4132 __webpack_require__ @ index.js:854 fn @ index.js:151 JLrY @ index.js:1430 __webpack_require__ @ index.js:854 fn @ index.js:151 eval @ kyBj:2 kyBj @ index.js:4897 __webpack_require__ @ index.js:854 fn @ index.js:151 eval @ main.js:36 Tglg @ index.js:4322 __webpack_require__ @ index.js:854 fn @ index.js:151 1 @ index.js:1057 __webpack_require__ @ index.js:854 checkDeferredModules @ index.js:46 (anonymous) @ index.js:994 (anonymous) @ index.js:997 index.js:4135 3. 若组件不符合 easycom 规范,需手动引入,并在 components 中注册该组件 Qld0 @ index.js:4135 __webpack_require__ @ index.js:854 fn @ index.js:151 JLrY @ index.js:1430 __webpack_require__ @ index.js:854 fn @ index.js:151 eval @ kyBj:2 kyBj @ index.js:4897 __webpack_require__ @ index.js:854 fn @ index.js:151 eval @ main.js:36 Tglg @ index.js:4322 __webpack_require__ @ index.js:854 fn @ index.js:151 1 @ index.js:1057 __webpack_require__ @ index.js:854 checkDeferredModules @ index.js:46 (anonymous) @ index.js:994 (anonymous) @ index.js:997 Request.js:53 Uncaught TypeError: f is not a function at Request.setConfig (Request.js:53:23) at Object.install (http.interceptor.js:4:24) at Vue.use (chunk-vendors.js:7461:22) at eval (main.js:160:5) at Object.Tglg (index.js:4322:1) at __webpack_require__ (index.js:854:30) at fn (index.js:151:20) at 1 (index.js:1057:18) at __webpack_require__ (index.js:854:30) at checkDeferredModules (index.js:46:23)解决
07-14
根据你提供的错误信息,可以看出出现了以下问题: 1. `Cannot find module './uni_modules/uview-ui/components/u-navbar/u-navbar.vue'`:无法找到`u-navbar`组件的模块。 2. `Uncaught TypeError: f is not a function`:f不是一个函数的类型错误。 针对这些问题,可以尝试以下解决方法: 1. 检查组件路径和拼写是否正确:确保路径中的文件名和文件夹名拼写正确,并且确保文件存在于指定的路径中。特别注意大小写是否匹配。 2. 检查组件是否符合easycom规范:uview-ui是否符合uni-app的easycom规范。可以参考[uni-app文档](https://uniapp.dcloud.net.cn/collocation/pages?id=easycom)了解easycom规范,并确保u-navbar组件符合规范。 3. 如果组件不符合easycom规范,尝试手动引入和注册组件:如果u-navbar组件不符合easycom规范,需要手动引入并在组件的`components`选项中注册该组件。检查你的代码中是否正确引入了u-navbar组件,并且在组件的`components`选项中注册了它。 4. 检查依赖项:确保你在项目中正确安装了uview-ui,并且版本与你的代码兼容。可以尝试重新安装uview-ui依赖项,以确保依赖项正确安装。 5. 检查其他错误:检查其他代码中的错误,确保没有其他导致该错误的问题。查看控制台中的其他错误信息,以获取更多线索。 如果上述解决方法无法解决问题,请提供更多关于你的项目结构、代码示例和错误信息的详细信息,以便我能够更准确地帮助你解决问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值