Next.js: 无服务器下一步:制作“next”仅开发依赖项,为较小的构建和更快的启动引入“next-server”

创建于 2018-05-29  ·  52评论  ·  资料来源: vercel/next.js

问题:在针对生产构建进行优化时,调用next start或在自定义server.js使用require('next') server.js涉及引入整套next依赖项,包括专门与开发相关的,例如webpack

从构建映像的角度和生成生产构建时的下载时间性能来看,这不仅是有问题的,而且还可能会影响启动时间。 _注意:由于我们在开发模式下小心地延迟加载诸如webpack类的重依赖项这一事实而减少了这种情况。_

对于注重性能和对_冷启动时间_敏感的人(参见例如:https://twitter.com/rauchg/status/990667331205447680),我们可以引入一个next-server包。

它将具有与require('next')相同的功能减去所有开发时间设置,加上一个非常小的next-server CLI,可以打开一个端口并执行正常关闭。

我们要优化的内容:

  • next-server的总依赖集必须尽可能小
  • 我们必须大量优化启动时间以尽快启动

此外,我们应该在examples/中提供一个示例,说明如何结合使用next-serverpkg将您的 Next.js 应用程序导出为自包含的 ELF 二进制文件

p1 feature request

最有用的评论

我们在 Now 2.0 上看到的前端冷启动时间为 1.5 秒,图像大小为 80mb IIRC

2018-05-29 16 50 37

应该有可能使它更接近1s,而无需对 Node 或 V8 或任何冷评估花费大量时间的依赖项进行任何更改(例如reactreact-dom

所有52条评论

我们在 Now 2.0 上看到的前端冷启动时间为 1.5 秒,图像大小为 80mb IIRC

2018-05-29 16 50 37

应该有可能使它更接近1s,而无需对 Node 或 V8 或任何冷评估花费大量时间的依赖项进行任何更改(例如reactreact-dom

哇,这太棒了!! :o

哇……太好了。

next-server一些问题。

  1. 它会是一个轻型快递服务器吗?
  2. 是的,它是否可以使用快速路由和next-routes进行配置?

@Nishchit14如果您试图减小构建大小,则不会添加express

我确信next-routes仍然可以正常工作。

所以我们在这里谈论的是将现有服务器提取到它自己的包中。 所以它会像以前一样工作,但不是导入 next,而是导入 next-server。

这太棒了! 我和我认识的其他人一直在使用使用本指南)在 AWS Lambda 之上运行 Next.js,一些主要问题是:

1)包装尺寸。 Lambda 为您提供了 50MB 的硬限制,使用包含的所有开发工具很容易接近。

2)冷启动。 快速启动非常重要,因为 Lambda 可以决定随时启动更多服务器。 现有服务器最多也可以使用约 4 小时,因此冷启动在应用程序的整个生命周期中都很重要。

很高兴看到这个倡议并乐于提供帮助!

这是一个好主意,我们对 Nuxt.js 也有同样的做法,我们称它为nuxt-start因为它是您运行nuxt start -> nuxt-start

密切关注这一点。 作为可能的数据点, www.bustle.com是 AWS Lambda 上的 SSR 。 整个部署的生产 zip 文件为 166kb。 这就是所有的应用程序和库代码。 Webpack 用于捆绑。

感谢分享@southpolesteve。 那是超级令人印象深刻。 #目标

用户案例看起来与micromicro-dev非常相似。

为什么不使用相同的命名法? nextnext-dev

我正在使用这个示例来处理 next.js 和无服务器,并且很好奇现在是否有任何方法可以完成较小的构建。 是否有我们在生产中绝对不需要的 node_modules 列表,并且可以在无服务器或repack-zip等打包程序中使用配置文件排除?

@Enalmada我正在运行带有多个 deps 的 next.js, material-ui是其中之一,我有一个规模相当大的应用程序,但我上传到 Lambda 的内置 zip 大约为 45MB。 你在找什么尺寸?

@albinekb我受到了 Southpolesteve bustle.com 对 166kb 以上响应的启发,想知道我的“45MB”中有多少是无用的并且很容易删除,如果我只知道在此优秀票完成之前将什么放入 dist 排除文件中作为黑客攻击.

@albinekb强烈建议您考虑使用 webpack、parcel 或 rollup 为 lambda 捆绑 JS。 您将节省大小,但也会节省启动时间,因为通过普通节点要求访问文件系统非常慢。

如果你正在部署到 ZEIT Now 并且你想要保持你的镜像小以便快速冷启动,你可以使用像 Package Phobia 这样的工具在安装之前检查 npm 依赖项的大小(或者只检查当前依赖项的大小以减少膨胀)。

自述文件还有许多类似的工具可以帮助您解决膨胀问题。 在这里查看: https :

这不应该在 Next 7 版本中解决吗? :(

如果您现在要部署到 zeit 并且希望保持较小的映像以进行快速冷启动,则可以使用 Package Phobia 之类的工具

该死的 antd: https ://packagephobia.now.sh/result = antd

@Enalmada负责的可能是 antd 的依赖项,而不是库本身。 我一直在研究https://packagephobia.now.sh/result?p=%40material-ui%2Fcore。 大部分权重来自一两个依赖项。

这不应该在 Next 7 版本中解决吗? :(

为了明确这一点,Next.js 7 为 Serverless Next.js 奠定了基础,我们删除了大约 5 条路线,只留下 2 条真正需要生产。

有没有人让 next.js 与 rollup 一起工作? 我觉得我已经非常接近了......在我的 60m dist 文件上运行汇总使大小减小到 6m。 不幸的是,dist 文件实际上不会启动,我认为这是由于 next.js 代码中的单个循环依赖导致汇总期间的警告。 如果有人可以考虑在 next.js 代码中删除循环依赖的可能性,我们可能都非常接近更小的构建和更快的启动:
https://github.com/zeit/next.js/issues/5392

密切关注这一点。 作为可能的数据点, www.bustle.com是 AWS Lambda 上的 SSR 。 整个部署的生产 zip 文件为 166kb。 这就是所有的应用程序和库代码。 Webpack 用于捆绑。

@southpolesteve你能分享关于你的 webpack 包配置的任何东西吗?

@shauns不幸的是,我不再在 Bustle 并且没有代码可以查看了:/

@southpolesteve不用担心! 很高兴至少知道它在 webpack 中的位置。

我们可以在下一个服务器上有一些消息吗? 我在这个月前看到了一些提交。

检查金丝雀分支。

你打算什么时候发布?

我目前无法分享时间表。

刚落地#5927

@timneutkens我应该将next到 devDependencies 并将next-server到我的依赖项中,还是您通过 babel 自动执行此操作?
https://github.com/zeit/next.js/blob/canary/packages/next/build/babel/plugins/next-to-next-server.ts

@Skaronator如果您使用 #5927 实现,则两者都不是,根据规范,它将每页输出一个包,不需要依赖项。 这意味着您可以使用.next/serverless/index.js require 它( require('./.next/serverless/index.js') )然后调用它的render方法:

const page = require('./.next/serverless/index.js')

page.render(req, res)

这将呈现页面并完成响应

棒极了!
我正在尝试这个,但在 aws lambda 上运行时遇到了一些麻烦。 有没有人有任何提示?

我想我们不应该再需要自定义快递服务器了,我们可以只需要基于路径的无服务器文件🤔

编辑
这似乎有效,但需要更深入地了解如何优化构建步骤:

const serverless = require("serverless-http");
const http = require('http');
const app = require('./.next/serverless/index.js');
const server = new http.Server((req, res) => app.render(req, res))
app.prepare().then(() => {
    const handler = serverless(server, {
        binary: binaryMimeTypes
    });
    return handler(event, context, callback);
});

看起来您将“自定义服务器”与“无服务器”混淆了,它们的 API 是完全独立的,无服务器中没有.prepare方法,因为没有任何准备,我们立即将页面呈现为 html 并完成调用render时的响应。

const serverless = require("serverless-http");
const http = require('http');
const page = require('./.next/serverless/index.js');
const server = new http.Server((req, res) => page.render(req, res))
const handler = serverless(server, {
  binary: binaryMimeTypes
});
handler(event, context, callback);

确实,我不知道为什么上面的代码有效(也许只是缓存)但我的或你的代码都不起作用,因为serverless-http似乎不支持http.Server和我不能只返回page.render(req, res)因为 lambda event对象不能替换必要的渲染req参数..

另外,我不想使用 express/koa/whatever,因为它会破坏下一个新功能的全部目的..( serverless-http是无依赖的,所以可以使用)

我没有想法:/

谢谢@timneutkens ,感谢您的帮助。
但目前它也不起作用,我仍然有这个错误: typeError: Parameter "url" must be a string, not undefined

我会停止污染这个线程并继续挖掘,如果我找到解决方案,我会写一个例子😄

我有点不清楚。 这个线程看起来适用于两个场景:无服务器应用程序和预编译服务器,其中包含所有必要的服务器端 npm 包 webpack'd 在一起。

该线程的第一条评论中的 gif 似乎考虑了后一种情况,这是我感兴趣的情况。看起来它使用了next-server这可能是也可能不是这个 npm 包——它没有没有附加存储库,我无法通过 google 或 GitHub 搜索找到一个,尽管版本标签之一是 8.0.0-canary.7--下一个版本标签--所以我怀疑它是正确的包。

到目前为止,我写的内容准确吗? 如果是这样,即使它在金丝雀中,我有什么办法可以抢先获得它吗?

我目前的解决方案(这对于明显的原因,我没有在督促使用)是删除从功能config.externals在我的next.config.js

很想能够产生预构建的服务器,这样我就不需要安装node_modules的200MB,然后花2分钟编制上我那可怜的,小生产的每一个我推的更新时间VM。


* "prod" 使用松散,因为这个项目不是关键任务或所有专业

密切关注这一点。 作为可能的数据点, www.bustle.com是 AWS Lambda 上的 SSR 。 整个部署的生产 zip 文件为 166kb。 这就是所有的应用程序和库代码。 Webpack 用于捆绑。

Next.js 8 无服务器目标的 zip 大小默认为 42Kb 😌

棒极了! 期待这个!

我和@doverdx 有完全相同的问题。 我想做一个服务器构建,其中还包括运行所需的所有 node_modules。 我正在使用带有 express 的自定义服务器,因此我不希望这些依赖项包含在包中,但是现在您也必须在服务器上安装 _all_ 依赖项(react、next、axios 等)。

我不明白这不是默认情况?
打包所有依赖项并能够最小化它们应该会带来显着的服务器端性能改进,还是我在这里完全错了?

如下覆盖 webpack 配置的externals部分包括大多数依赖项

module.exports = {
  webpack: (config, { dev }) => {
    config.externals = [];
    return config;
  })
};

但是服务器上仍然需要 react 和 react-dom 。 我不知道如何也包括这些......

不幸的是,无法使用当前的无服务器模式创建自定义服务器。 如果您使用普通模式,则需要包含 next 及其所有依赖项,因为在 .next 中生成的 _app.js 取决于例如 next/router

为什么非无服务器模式也不能捆绑?

不幸的是,无法使用当前的无服务器模式创建自定义服务器。 如果您使用普通模式,则需要包含 next 及其所有依赖项,因为在 .next 中生成的 _app.js 取决于例如 next/router

请注意,从下一个 8 开始,您可以在 server.js 中使用“next-server”而不是“next”,并且这样做只会在本地开发期间丢失热重载。 从理论上讲,它使您能够在中间服务器上进行 CI 构建,而不是将与 Webpack 相关的依赖项复制到生产实例。 但是我们还没有在我们的项目中尝试过。

@ElvenMonky一年以来一直在等待这样的事情,但在文档或示例中找不到任何关于此的信息。

@timneutkens你能验证一下吗?

如果是这样,我可能会尝试这样的设置,并为文档/示例发送 PR。

请注意,从下一个 8 开始,您可以在 server.js 中使用“next-server”而不是“next”,并且这样做只会在本地开发期间丢失热重载

不幸的是,这不起作用。

首先,使用服务器目标运行无服务器构建会被主动阻止,并显示以下消息:“目标不是服务器时无法启动服务器。https://err.sh/zeit/next.js/next-start-serverless

然后,如果您决定进行正常构建,那么构建文件将直接引用next包中的内容(如服务器端编译的 _app.js 文件中的next/router )。 这意味着nextwebpack东西无论如何都需要在生产构建中。

@ElvenMonky

请注意,从下一个 8 开始,您可以在 server.js 中使用“next-server”而不是“next”,并且这样做只会在本地开发期间丢失热重载。

接下来是作为 Babel 插件在内部执行此操作,如下所示:
https://github.com/zeit/next.js/blob/709850154754278d2fc86b987eebe1b3f0565255/packages/next/build/babel/plugins/commonjs.ts#L5 -L32

@sheerun正如我在 #7011 中也提到的,您可以通过使用next-transpile-modules插件转译next模块来消除未解决的next/router依赖项。

我已经分叉并调整了自定义快递服务器的示例来说明解决方案: https :

PS:无论如何,我仍然对#5927 感到非常兴奋,我的应用程序需要 TODO 中列出的所有内容,更不用说动态路由和提供静态内容了。
好消息是,上述解决方案似乎与https://www.npmjs.com/package/next-serverless自定义服务器设置配合得很好,可以在没有上述限制的情况下部署到例如 AWS Lambda 中。

请注意,从下一个 8 开始,您可以在 server.js 中使用“next-server”而不是“next”,并且这样做只会在本地开发期间丢失热重载。

我一直在使用这个建议,但不幸的是不能使用运行时配置,因为它需要next/config而需要next

我不知道为什么,但是require('next/config')过去可以在没有next安装在下一个版本 8.0.3 的 node_modules 中的情况下工作,但在下一个版本 8.1.0 中不起作用

是否可以将 next/config 移动到不同的包,例如next-runtime-config
next-runtime-vars (避免使用术语 config 以避免与 next.config.js 混淆)。

如果可以接受,请告诉我,我将创建一个 PR。

嘿大家! 这个问题从 Next.js 8 开始就已经实现了,并且在 Next.js 9 中仍然存在。我将在完成时关闭它。 😌

抱歉,我对这个问题感到困惑: https :
我还没有检查目标:“无服务器”


查看已删除的评论

某些"next/*"可以替换为"next-server/*" ,例如:

  • 下一个/配置 -> 下一个服务器/配置
  • 下一个/放大器 -> 下一个服务器/放大器
  • 下一个/动态 -> 下一个服务器/动态
  • 下一个/常量 -> 下一个服务器/常量
  • 下一个/头 -> 下一个服务器/头

但是有一些不支持此问题的 OP 提到的此类优化。

  • next/router -> next-server/dist/lib/router/router (也许)? (如果在服务器上使用,应该为空或应该抛出错误)
  • 下一个/链接?

不需要,因为它们甚至在服务器(AKAIK)中也是内联的

  • 下一个/应用程序
  • 下一个/文件

嘿大家! 这个问题从 Next.js 8 开始就已经实现了,并且在 Next.js 9 中仍然存在。我将在完成时关闭它。

@Timer - 您是指无服务器目标,还是将“next”替换为“next-server”?

如果我们将 next 替换为下一个服务器,则不会更改 node_modules 文件夹大小,除非 packages.json 依赖项也更新。

是否有两种方法可用的示例? 使用无服务器,我的用例正在部署到 AWS Lambda。

最初问题中概述的方法演变为serverless目标,我们建议您使用它。

@timneutkens serverless目标没有也不能解决使用动态路由的自定义服务器的问题。 #5927 对于许多现实世界的商业应用程序来说,这不是一个解决方案,比如在我的情况下,我们必须使用动态生成的页面、资产前缀、自定义 _app、_document 和 _err:基本上所有在 TODO 列表中说明的内容。
next-server为我们提供了部署到生产环境的部分解决方案,而没有奇怪的开发依赖,比如 webpack 和 babel。 然而,这可以通过我们在这里讨论的一些技巧和木头舞来完成。

我的印象是您理解这种差异,并希望有一天能看到更强大的解决方案来解决@rauchg所描述的初始问题

此页面是否有帮助?
0 / 5 - 0 等级