@serverless/components 代码简析
文章仅代表作者本人的认知,如有谬误,欢迎指正。 本篇文章建议配合 @serverless/components 源码 食用
前言
对于我们使用 Serverless Framework 的开发人员来说 sls 无疑是最常用的命令了
然而,当我们翻开 serverless 的源码一看,就会发现,cli 入口处实际上做了一个分支选项
const componentsV1 = require('@serverless/cli')
const componentsV2 = require('@serverless/components')
// Serverless Components v1 CLI (deprecated)
if (componentsV1.runningComponents()) return () => componentsV1.runComponents()
// Serverless Components CLI
if (componentsV2.runningComponents()) return () => componentsV2.runComponents()
@serverless/cli 作为 components v1 版本,目前已经废弃
@serverless/components 是 components v2 版本,也是 Serverless Framework 推出的最新解决方案
@serverless/components 和 @serverless/cli 相比有很多的优势:
- Components v1 版本是本地版本,组件部署后,产生的状态存储在本地,如果切换开发机,会导致状态丢失,而且使用前都需要从
npm拉到本地,依赖本地的开发环境。 - Components v2 版本是云端版本,解决了这些痛点,状态在云端,模板在云端,我们只需要选择我们的组件,调用云服务就能轻松的完成部署工作
从源码入口开始
我们先把 @serverless/components clone 到本地,(笔者为 3.9.2版本)
package.json
这个文件中,有 2 个需要注意的地方:
1.bin
"bin": {
"components": "./bin/bin"
},
这也就是说 当我们全局安装 @serverless/components 的时候,就可以直接使用components 命令了,它的本质其实就是 sls 的 v2 版本(见上面的代码块)
假设我们的项目,完全是使用 components v2 版本构建的,那么大可直接安装此包,并且使用 components 命令来取代 serverless 命令
2. 依赖
@serverless/platform-client@serverless/platform-client-china@serverless/utils@serverless/utils-china

ps: 这些包 Github 上没有,我们可以直接在
node_modules/@serverless中发现他们
platform-client 这类包实际上就是真正核心的 Sdk 了
utils 则是工具类
不过有意思的是,看上去名字长得差不多,包里面的内容却大相径庭
这里我把它分类为: 国内,国外
国外:
- 借用 online 的 web 服务来达成适配多个云厂商的功能,这块对于我们来说,就是黑箱,具体表现在:对他们
*.serverless-dev.com,*.serverless-platform.com域名的请求上,他们自己也提供了很多的特色服务.
国内:
- 从
china的包,我们可得,serverless in china就是一套@tencent-sdk/capi能力的封装,同时我们也可以在utils-china/sdk中发现很多的官方的 api 网关的地址 (地域:上海 & 广州)
Cli

通过之前的 bin/bin 这个入口,我们来到了 src/cli/index.js
值得注意的是 isChinaUser() 国内有自己的 loadTencentGlobalConfig 逻辑和我们自己的 commands-cn 命令 (笑~)
我们为了更加贴合国内的使用方式,就只看 commands-cn/index.js 部分代码
可以看到目前主要有一下代码:
run包含deployremovebind rolelogin等等一系列命令info用org/stage/app/name从服务端拉信息init模板项目初始化dev单实例调试模式registry注册模板地址,默认地址目前可以去utils-china/sdk/serverless/index.js找到,还有就是publish,unpublish最终都会转换为此命令。help使用帮助param(目前似乎没啥用components -h也没有显示此命令)credentials全局凭证,是时候抛弃扫二维码和.env了 (笑~)
我们挑选 2 个典型来讲,一个是 run 一个是 dev
run
deploy
deploy 就是我们最常用的部署命令了
从代码上看,先是做了一些验证格式化 validateAndFormat
然后用 preRunSrcHook 来处理 inputs.src 为 object/string 的各种情况
接着走 cache方法,压缩上传我们的代码包,先 fast-glob匹配一波,然后 adm-zip 压缩成 zip and axios.put 上传 cos
最终在 utils-china/library/sls/v20200205/sls_client.js 中发请求告诉服务端这些信息,完成部署
remove / bind role
和 deploy 一样,最终被转化为 library 的调用
TencentCAM.BindRole.BindRole -> forceBindQCSRole
dev
先调用是否支持调试的 doesRuntimeSupportDebug , 从代码上看,只支持 nodejs 且版本大于等于 10.15 的版本
不得不说
nodejs在这方面就是有天然优势
支持在线调试的,就 使用 tencentDebuggger.remoteDebug , 然后创建 WshubClient 进行调试
不支持就利用 ws 创建一个 WebSocket 链接,和服务端的 log 打通,输出到本地的命令行

比较值得一说的就是 startTencentRemoteLogAndDebug 了
在线调试这里也利用 socket.io-client 连接远程服务端

我猜内部应该是,单实例 nodejs 通过 inspect 把调试的 ws link 暴露在外部,通过 token 鉴权,然后通过本地的 ws client 连接上,再映射到本地的 9222 端口:
const Client = function (options) {
const {
Url,
Token,
logType = 'error',
localPort = 9222,
debugRemotePort = 9000,
logRemotePort = 3332,
timeout,
} = options;
// 日志类型,verbose或者info,测试阶段建议verbose
this.logger = createLogger(logType);
// 映射的本地端口,默认9222
this.localPort = localPort;
// 远端调试端口,默认9000
this.debugRemotePort = debugRemotePort;
// 远端日志端口,默认3222
this.logRemotePort = logRemotePort;
// 连接wshub的超时时间
this.timeout = timeout;
this.Url = Url;
this.Token = Token;
};
总结
看了这么多的代码,我们了解了这个 命令行工具 的本质
这样,我们可以利用这一点,创建出符合我们自己需求的,CLI,Web 和 Gui 客户端
附录:
代码路径参考:
platform-client-china/src/instance.js -> deploy -> run -> api.instance.run
再到 platform-client-china/src/api.js -> run
又到了 utils-china/sdk/serverless/index.js -> runComponent
再到了 utils-china/library/sls/v20200205/sls_client.js -> RunComponent
调试方法
在 vscode 中创建自己的 workspace.code-workspace , 添加 global 级别的 serverless 和 @serverless 路径
使用
npm -g bin/yarn global bin输出全局bin路径 ps: npm 和 yarn 的全局包安装位置有可能不同,取决于当时安装serverless的工具
然后使用 vscode JavaScript Debug Terminal , 直接敲命令 components dev / npm run sls:dev 等等,就可以直接命中断点
npm -g bin / yarn global bin 输出全局 bin 路径
ps: npm 和 yarn 的全局包安装位置有可能不同,取决于当时安装serverless的工具
然后使用 vscode JavaScript Debug Terminal , 直接敲命令 components dev / npm run sls:dev 等等,就可以直接命中断点