作者

杨苏博,偏后端的全栈开发,目前负责腾云扣钉的 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. Redis Set Type

    集合中的元素个数最多为2的32次方-1个,集合中的元素师没有顺序的. Redis集合的操作命令和对应的api如下: smembers [set] JedisAPI:public Set<Stri ...

  2. 学习Python(一)

    一.Python的基础 1.Python是怎样的语言? 2.Python的安装 Linux安装(python3) yum install -y make zlib zlib-devel gcc-c++ ...

  3. java集合类框架的基本接口有哪些

    集合类接口指定了一组叫做元素的对象.集合类接口的每一种具体的实现类都可以以他自己的方式对元素进行保存和排序.有的集合允许重复的键,有些不允许. java集合类里面最基本 的接口: Collection ...

  4. 详解Mysql事务隔离级别与锁机制

    一.概述 我们的数据库一般都会并发执行多个事务,多个事务可能会并发的对相同的一批数据进行增删改查操作,可能 就会导致我们说的脏写. 胀读和不可重复读.幻读这些问题. 这些问题的本质都是数据库的多事务并 ...

  5. MiL → SiL → PiL → HiL 是什么?

    基于模型的快速原型开发通常分为四个过程:MiL → SiL → PiL → HiL 1. MiL(Model in Loop)模型在环  在PC上基于模型的测试,它的输出是经过验证的控制算法模型.验证 ...

  6. Python模块导入方式

    import导入方式 from...import导入方式  from...import... 导入模块相当于在此文件中写了所导入函数名(对比c/c++中的.h文件来理解),所以在之后使用导入的函数直接 ...

  7. C++:Abstract class : invalid abstract return type for member function ‘virtual...’

    #include <iostream> #include <cmath> #include <sstream> using namespace std; class ...

  8. 人机交互BS

    B/S结构用户界面设计       [实验编号] 10003809548j Web界面设计 [实验学时] 8学时 [实验环境] l  所需硬件环境为微机: l  所需软件环境为dreamweaver ...

  9. linux vim编辑器使用

    小i 在光标所在行位置停止不动开始写入内容 大I 在光标所在行行首开始写入内容 小a 在光标所在行当前字符后开始写入内容 大A 在光标所在行行尾开始写入内容 小o 在光标所在行下一行开始写入内容 大O ...

  10. 搭建 LNMP 环境

    搭建 LNMP 环境 搭建 Nginx 静态服务器 安装 Nginx 使用 yum 安装 Nginx: yum install nginx -y 修改 /etc/nginx/conf.d/defaul ...