作者

杨苏博,偏后端的全栈开发,目前负责腾云扣钉的 Cloud Studio 产品。在团队中负责接技术架构设计与 Review、Cloud Studio 编辑器内核设计与开发、部分核心插件设计与开发;对 WebIDE 领域中的 VS Code 和 Theia IDE 有深入研究与丰富实践;多年 Serverless 领域从业经验,是 Serverless First Malagu 开源框架的作者;热爱开源,敢于创新。

前言

Next.js 是由 Vercel 团队研发的一款全栈应用开发框架。我们使用 Next.js 开发前端页面以及一些轻量级的后端 API。前端和后端都用 Javascript 技术栈,并且是前后端一体化的(在同一个项目中开发前后端)。另一个被大家所熟知的特性是它的服务端渲染能力,对 SEO 友好。

Vercel 自身是一个用户体验极佳的 Serverless 平台,支持包括 Next.js 在内的几十框开发框架一键部署到 Vercel 平台。Vercel 平台自身拥有极强的适配扩展能力,第三方框架可以按照 Vercel 平台的适配规则自主进行适配。

作为 Vercel 亲儿子的 Next.js 可以完美适配 Vercel 平台,通过 Next.js + Vercel,让开发和部署体验都能拥有极致的体验。Vercel 团队信奉着 “吃自己的狗粮” 原则,Vercel 自身很多应用都是基于自己的工具和平台开发的。

美中不足

Next.js + Vercel 看起来是如此的完美:通过 Vercel CLI 一键部署 Next.js 到 Vercel。另外,Next.js 也能很方便地运行在云主机上。但是 Vercel 作为国外的 Serverless 平台,对于国内用户,总是存在种种难以逾越的限制。如何将 Next.js 完美运行在国内的 Serverless 平台变得尤为重要。

国内 Serverless 平台官方在如何让 Next.js 运行起来各显神通。让 Next.js 在 Serverless 平台上运行不难,而要做到像 Vercel 一样的极致部署运行体验却很有挑战。

在尝试将 Next.js 部署到国内 Serverless 平台的时候,比如腾讯云函数、阿里云函数计算,可能会遇到如下一些坑:

运行适配困难

Next.js 的运行需要一个 HTTP Server,而事件函数提供的是一个简单签名函数,无法直接运行,需要将事件函数模拟成一个近似 HTTP Server 的代理服务;

代码体积过大

一个最简单的 Next.js 应用的代码体积为 245 MB 左右,打包压缩后是 54 MB 左右,而函数代码体积限制一般是在 50 MB 以内(阿里云函数计算通过 OSS 方式上传代码可以超过 50 MB 的限制,但不能超过 100 MB)。代码体积过大往往带来一系列副作用:

  • 代码上传时间长,且容易失败,部署成本变大(通过 NFS 和 Layer 解决);

  • 依赖更多云服务,如使用对象存储服务部署代码包,又或者把体积大的 node_modules 目录上传到 NFS 服务上,然后挂载到函数上。总之,让应用架构变复杂;

  • 冷启动时间变长,函数在第一次运行的时候,需要先加载远端的代码,如果代码包越大,则冷启动时间越长;

不过,通过腾讯云的 Web 函数和阿里云函数计算的 Custom Runtime,可以解决第一个问题,因为它允许我们运行一个真正的 HTTP Server。而第二个问题要困难很多,虽然其中部分问题可以通过一定手段缓解,比如冷启动,可以通过预置并发解决,但是又会让运行成本变得难以接受。所以解决问题的根本还是在代码体积上。

为什么 Next.js 项目代码体积大

为了分析这个问题,我们需要先了解 Next.js 的架构。Next.js 是一种 React 的服务端渲染框架,集成度极高,框架自身集成了 Webpack、SWC、Babel、Express 等,使得开发者仅依赖 Next、React 和 React-dom 就可以方便地构建自己的 SSR React 应用,我们甚至可以不用关心路由。Next.js 的高度集成性,易于实现代码分割、路由跳转、热更新、服务端渲染和前端渲染。

在 Next.js 项目中,不仅仅包含了运行时所需要的依赖,还包含了本地开发、构建所需要的开发时依赖,而且开发时依赖体积又大,而我们常见的解决方案是简单粗暴打包所有的依赖,从而导致 Next.js 项目代码偏大。

Vercel 官方如何打包部署 Next.js

Vercel 官方打包部署 Next.js 方案比较复杂。Vercel 平台底层基础设施是集成了 AWS Lambda,Next.js 本质是部署在 AWS Lambda 平台上。为了能让 Next.js 能在 Lambda 上运行,Vercel 官方提供了一个专门用于构建 Next.js 项目的构建器:@vercel/next。该构建器的逻辑大致是把 Next.js 中的每一个 API 和服务端渲染的页面都分别构建输出为一个函数,这一系列函数都归属与 Vercel 平台上的一个应用。所以这样就保证了每个函数的代码体积足够的小。

Next.js 打包部署到国内 Serverless 平台最佳实践

解决函数适配困难:我们可以通过 Web 函数或者 Custom Runtime 来解决,不推荐使用自定义镜像方式,因为自定义镜像冷启动很严重。并在其中运行一个 HTTP Server,且简单适配 Next.js。Next.js 官方有示例。

解决代码包体积过大问题:剔除掉运行时不需要的可选依赖和开发依赖,剔除方式如下:

npm install --omit optional --omit dev
# 或者
yarn install --ignore-optional --prod

说明:因为 swc 构建工具是通过可选依赖安装的,在运行时不需要,所以我们需要把可选依赖也剔除。

通过以上方式构来的代码体积由原来的 54 MB 减小到了 18 MB。另外,值得一提的是阿里云函数计算 Custom Runtime 内置的 Node.js 版本为 v10.16.2,而 Next.js 最新版本要求必须是 Node.js 12.22.0+。所有直接部署在函数计算的 Custom Runtime 上的 Next.js 应用无法运行,此时我们就需要自行将 Node.js 的二进制下载到我们自己的代码中(也可以通过 Layer 实现),然后指定新的 PATH 环境变量。

如果每次部需要做上面的操作是不是很繁琐,而且还需要自己写适配入口代码,以及 Web 函数和 Custom Runtime 所必须的 bootstrap 文件,且该文件必须拥有可执行权限,额外安装新版 Node.js 运行时。其实,这些能力在 Cloud Studio 云开发平台中已经内置提供了。一个原生的 Next.js 应用,使用 Cloud Studio 云开发平台可以一键部署到腾讯云函数或者阿里函数计算,对业务代码零侵入,零门槛。只需如下几步:

1.登录进入 Cloud Studio 的 Dashboard 页面

2.选择 Next.js 模板,并创建一个工作空间

3.切换到 Cloud Studio 云部署套件视图

4.选择腾讯云部署选项,并微信扫描登录

5.点击【开始部署】按钮,一键部署 Next.js 应用

6.点击【访问】按钮,即刻预览部署后的效果

说明:同样的 Next.js 应用,无需做任何修改,采用上述一样的步骤,一键部署到阿里云函数计算。

Cloud Studio 是基于浏览器的集成式开发环境(IDE),为开发者提供了一个永不间断的云端工作站。其包含代码高亮、自动补全、Git 集成、终端等 IDE 的基础功能,同时支持实时调试、插件扩展等,可以帮助开发者快速完成各种应用的开发、编译与部署工作。用户在使用 Cloud Studio 时无需安装,随时随地打开浏览器就能使用。

目前 Cloud Studio 支持部署到腾讯云函数和阿里云函数计算。并且支持 15+ 前后端框架的一键部署。

写在最后

开始胡乱打包,到后面的精致打包,让代码体积变小,从而避免了一些列的坑。至于我们为什么不采用像 Vercel 那样的极致方案,原因有三点:实现成本太高、对 Next.js API 深度依赖,维护成本高和构建成多个函数管理成本极大(我们不可能想 Vercel 一样提供一个高阶平台)。通过 Cloud Studio 云开发平台,我们可以一键部署 Next.js 等流行框架,对框架零改造。

关于我们

更多关于云原生的案例和知识,可关注同名【腾讯云原生】公众号~

福利:

①公众号后台回复【手册】,可获得《腾讯云原生路线图手册》&《腾讯云原生最佳实践》~

②公众号后台回复【系列】,可获得《15个系列100+篇超实用云原生原创干货合集》,包含Kubernetes 降本增效、K8s 性能优化实践、最佳实践等系列。

③公众号后台回复【白皮书】,可获得《腾讯云容器安全白皮书》&《降本之源-云原生成本管理白皮书v1.0》

④公众号后台回复【光速入门】,可获得腾讯云专家5万字精华教程,光速入门Prometheus和Grafana。

【腾讯云原生】云说新品、云研新术、云游新活、云赏资讯,扫码关注同名公众号,及时获取更多干货!!

Next.js 在 Serverless 中从踩坑到破茧重生的更多相关文章

  1. 对称加密算法在C#中的踩坑日常

    前言 有幸接触了一下传说中的对称加密算法3DES 感觉这些加密算法与我的工作是想去甚远的,一般没什么机会接触这些东西 今次了解了一下3DES这个对称算法 原理算不上明白,算是踩了C#中的一些坑吧 C# ...

  2. 避坑手册 | JAVA编码中容易踩坑的十大陷阱

    JAVA编码中存在一些容易被人忽视的陷阱,稍不留神可能就会跌落其中,给项目的稳定运行埋下隐患.此外,这些陷阱也是面试的时候面试官比较喜欢问的问题. 本文对这些陷阱进行了统一的整理,让你知道应该如何避免 ...

  3. 前端坑多:使用js模拟按键输入的踩坑记录

    坑 一开始在Google搜索了一番,找到了用jQuery的方案,代码量很少,看起来很美好很不错,结果,根本没用-- 我反复试了这几个版本: var e = $.Event('keyup') e.key ...

  4. python学习过程中的踩坑记录<若干,随时更新>

    问题1:python中print的连串输出与java不一样? 输入print(code +"+++"); --在代码中写入,界面未报错,但是告诉你不行 会报错,如图: 解决办法: ...

  5. Vue中axios踩坑之路-POST传参

    https://blog.csdn.net/call_me_fly/article/details/79012581

  6. router路由去掉#!的踩坑记

    项目中在研究去掉router#!的过程中的踩坑过程.

  7. vue.js 踩坑第一步 利用vue-cli vue-router搭建一个带有底部导航栏移动前端项目

    vue.js学习 踩坑第一步 1.首先安装vue-cli脚手架 不多赘述,主要参考WiseWrong 的 Vue 爬坑之路(一)-- 使用 vue-cli 搭建项目 2.项目呈现效果 项目呈现网址:w ...

  8. 『vue踩坑日常』 在index.html中引入静态文件不生效

    Vue日常踩坑日常 -- 在index.html中引入静态文件不生效问题 本文针对的是Vue小白,不喜勿喷,谢谢 出现该问题的标志如下 控制台warning(Resource interpreted ...

  9. 微信小程序使用pako.js的踩坑笔记

    问题 今天组长跟我们讨论了个问题,说是文章存储占用有点大,消耗宽带流量费,让我看看能不能找个方法解决一下(文章存储的是html字符串).第一反应是没什么头绪,能想到的就是将相同的字符串替换成一个标识之 ...

随机推荐

  1. Java 中堆和栈有什么区别?

    JVM 中堆和栈属于不同的内存区域,使用目的也不同.栈常用于保存方法帧和局 部变量,而对象总是在堆上分配.栈通常都比堆小,也不会在多个线程之间共享, 而堆被整个 JVM 的所有线程共享.

  2. Flask-Migrate使用教程

    功能:flask-migrate是flask的一个扩展模块,主要是扩展数据库表结构的. 项目准备:一个干净的Flask项目,下载连接地址: https://pan.baidu.com/s/1WqdIN ...

  3. Redis++:Redis做分布式锁真的靠谱吗

    Redis做分布式锁真的靠谱吗 Redis的分布式锁可以通过Lua进行实现,通过setnx和expire命令连用的方式 || 也可以使用高版本的方法同时设置失效时间,但是假如在以下情况下,就会造成无锁 ...

  4. 数据结构:DHUOJ 删除链表的顺数及倒数第N个节点

    删除链表的顺数及倒数第N个节点 作者: turbo时间限制: 1S章节: DS:数组和链表 题目描述: 可使用以下代码,完成其中的removeNth函数,其中形参head指向无头结点单链表,n为要删除 ...

  5. 创建TypeScript代码模板(NVS+Yarn+ESLint+Prettier+Husky)

    创建TypeScript代码模板(NVS+Yarn+ESLint+Prettier+Husky) Cui, Richard Chikun 本文笔者将带你在Github代码仓库创建TypeScript代 ...

  6. AWS 6R

    "The 6 R's": 6 Application Migration Strategies "The 6 R's": 6 Application Migra ...

  7. Polymer API开发指南 (二)(翻译)

    公开 property 当你公开一个 Polymer 元素的 property 名字时,就等于把这个 property 设置为公开API了.公开 property 会有如下的特性: 支持声明数据双向绑 ...

  8. Content Security Policy减少劫持

    Content Security Policy减少劫持 什么是CSP? CSP是由单词 Content Security Policy 的首单词组成,是HTML5带给我们的一套全新主动防御的体系,旨在 ...

  9. 实用的 CSS — 贝塞尔曲线(cubic-bezier)

    欢迎移步我的博客阅读:<实用的 CSS - 贝塞尔曲线(cubic-bezier)> 前言 在了解 cubic-bezier 之前,你需要对 CSS3 中的动画效果有所认识,它是 anim ...

  10. 体验javascript之美6:如果你觉得什么都会了或者不知道js学什么了看这里-面向对象编程

    概述 当大家已经把js的语言基础理解了,然后能够写出一些简单的例子了,这个时候基本上达到了一年工作经验的水平,而自己能够独立的写一些小功能,完成一些小效果,或者临摹修改一些比较复杂的插件的时候差不多就 ...