Serverless 部署 Deno 应用有那么难吗 ???
牛年大吉
Serverless 部署 Deno 应用有那么难吗 ???
❝Deno 是一个简单、现代且安全的 JavaScript 和 TypeScript 运行时环境,其基于 V8 引擎并采用 Rust 编程语言构建。Deno 自打出生就不乏话题:“Node.js 的替代品,将来可能就不需要 Node.js 了”、"Deno 并不是下一代 Node.js"、“Deno 已经死了吗?”……而对于 Copy 攻城狮 来说,有趣就行!目前 CloudBase Framework 支持一键部署 Deno 应用,而我却踩了不少坑,谨以此文纪念逝去的那些一文不值的时光!
❞
CloudBase Framework
❝🏆 腾讯云开发 ☁️ 云原生一体化部署工具 🚀 CloudBase Framework:一键部署,不限框架语言,云端一体化开发,基于 Serverless 架构。
❞
「云开发 CloudBase 是腾讯云的热门产品,云开发应用可以是运行在云开发环境的应用,例如一个包含前后端、数据库等能力的服务,可以通过一键部署,直接部署在云开发环境中,使用云开发底层的各项 Serverless 资源,享受弹性免运维的优势。」 什么是云开发?什么是 Serverless?Copy 攻城狮心中满是疑问,还能不能愉快地切图!上一次了解到云开发还是看到“小程序·云开发”,印象比较深刻的是云开发提供一个云函数环境,提供云数据库、鉴权服务等,无需自备服务器搭建后端服务。听过一些老师的课,得益于云开发,前端开发尤其是小程序开发者,一个人就能前后端甚至运维也全干,快速上线一款弹性伸缩企业级应用;而 「Serverles」 是「功能即服务」(Function-as-a-Service,缩写为 FaaS) 和 「平台即服务」(platform as a service,缩写:PaaS 的组合,是当前主流的技术实现;不过,Copy 攻城狮只会跑跑 Hello World 。在 Serverless 技术体系中,我们熟知的 Node.js 扮演着举足轻重的一环,比如 Serverless Framework、Vercel等 Serverless 优秀产品都离不开 Node.js 完善的生态。CloudBase Framework也是如此,因此我们能够轻而易举的想到 CloudBase Framework 的安装和使用方式。
安装 CLI 工具
npm install -g @cloudbase/cli@latest
❝
如遇到权限问题,请使用
❞sudo
, MacOS 上好像容易出现。help
指令cloudbase -h
❝
盲猜应遵循了国际惯例, help help help!,当然,惊喜发现 cloudbase 还能简写为
❞tcb
。Tip: cloudbase 命令可以简写为 tcb
CloudBase CLI 1.5.0
CloudBase Framework 1.6.18-+
命令
login [options] 登录腾讯云账号
logout 登出腾讯云账号
env [cmd] 环境管理操作
fn [cmd] 操作函数
framework [cmd] 云开发 Serverless 应用框架操作
hosting [cmd] 静态托管资源管理操作
new [appName] [template] 创建新的云开发应用
open [link] 在浏览器中打开云开发相关连接
storage [cmd] 云存储资源管理操作
service [cmd] HTTP 访问服务管理操作
选项
--verbose 打印出内部运行信息
-r, --region指定环境地域
--mode指定加载 env 文件的环境
--config-file指定配置文件路径
-v, --version 输出当前版本
-h, --help 查看命令帮助信息
Tips:
– 登录
$ tcb login
– 创建新的云开发应用
$ tcb new appName
– 部署云函数
$ tcb fn deploy
– 查看命令使用介绍
$ tcb fn -h登录
看到有登录的命令,先尝试一下,由于我之前已经登录过了,通过 logout 登出,再 login 。
huqi@Mac-mini deno % tcb login
CloudBase CLI 1.5.0
CloudBase Framework 1.6.18
✔ 您已登录,无需再次登录!
huqi@Mac-mini deno % tcb logout
CloudBase CLI 1.5.0
CloudBase Framework 1.6.18
✔ 注销登录成功!
huqi@Mac-mini deno % tcb login
CloudBase CLI 1.5.0
CloudBase Framework 1.6.18
⠋ 获取授权中...此时,会通过默认浏览器打开一个 CLI 授权的页面,这让我想起 Huawei DevEcho Studio 在登录时也会调用网页来进行授权。登录逻辑实现的代码,我们可以「给 github 加 1s」 来打开在线 VSCode 来查看:https://github1s.com/TencentCloudBase/cloudbase-cli/blob/HEAD/src/commands/account/login.ts,感兴趣的小伙伴可以尝试通读源码。
授权成功之后,它还会征求我的意见收集我的使用数据,为了更好的体验 Cloudbase ,我愿意!我愿意奉献我的使用数据!
async function askForCollectDataConfirm() {
const agree = await usageStore.get('agreeCollect')
if (agree) return
// 询问
const { confirm } = await inquirer.prompt({
type: 'confirm',
name: 'confirm',
message: '是否同意 Cloudbase CLI 收集您的使用数据以改进产品?',
default: true
})
if (confirm) {
await usageStore.set('agreeCollect', true)
}
await collectAgree(confirm)
}初始化项目及部署
既然前边已经提到可以使用简写
tcb
来代替那串冗长的字母,那肯定使用tcb
来创建初始化项目。tcb new deno_hello deno # 以 deno 为模板创建项目
cd deno_hello
tcb # 部署项目非常简单明了的命令就实现了一个 Deno 应用的 Serverless 部署。当然,也正是三行命令,让我踩了一个又一个的坑,为此还花费了我好几毛钱的”巨款”,钱不钱倒是无所谓,主要是磨洋工都快把我耐心耗尽了!
先来看看
tcb new deno_hello deno
干了啥,大胆猜测是创建了deno_hello
文件夹,并通过调用https://tcli.service.tcloudbase.com/download
传入 os、uin、macMd5、templateId、templateName、version 等参数,获取到 deno 模板并写入到deno_hello
项目中。Cloudbase deno 模板源码依旧可通过「给 github 加 1s」 来查看:https://github1s.com/TencentCloudBase/cloudbase-templates/tree/master/deno。如果您碰巧留意到
cloudbaserc.json
,您可能会想为啥 deno 版本是 1.6.3 呢?:{
"version": "2.0",
"envId": "{{envId}}",
"$schema": "https://framework-1258016615.tcloudbaseapp.com/schema/latest.json",
"framework": {
"name": "deno-app",
"plugins": {
"deno": {
"use": "@cloudbase/framework-plugin-deno",
"inputs": {
"dockerImage": "debian:latest",
"runtime": "1.6.3"
}
}
}
}
}对,这里便是我踩的坑!目前来看,在执行
tcb
之前,去掉"runtime": "1.6.3"
这行使用 deno 最新的版本能避坑!
Deno 镜像之“锅”
很荣幸能遇到 Deno 生态建设崎岖之路的“bug”,云里雾里,这究竟是怎样一个故事?请听 Copy 攻城狮娓娓道来。
大概半个月之前,我尝试使用 Cloudbase 部署 deno 的 HelloWorld 应用,拉的 Cloudbase 官方的模板直接部署,怎么都不成功,部署失败的关键日志提示如下:
CloudBase CLI 1.2.7
CloudBase Framework 1.6.11
……
step 4/14 : RUN curl -fsSL https://x.deno.js.cn/install.sh | sh
---> Running in df11b9868b9a
�[91m#=#=#
curl: (22) The requested URL returned error: 403
�[0mThe command '/bin/sh -c curl -fsSL https://x.deno.js.cn/install.sh | sh' returned a non-zero code: 22
当时看到https://x.deno.js.cn/install.sh
就想到了 justjavac 大大的 Deno 镜像,不过没想到的居然是「jsdelivr CDN 单文件最大只支持 20M」导致了 Deno 1.7.0 版本在当时的镜像无法正常使用,因为 1.7.0 版本的 zip 包刚好超过了 20M,参见https://github.com/justjavac/dvm/issues/42:
这间接导致了 Cloudbase 中 Deno 模板使用最新的版本时,通过镜像无法下载;也造就了我这个注定是巧合的坑!
好在 justjavac 大大及时修复了这个“bug”:
fn compose_url_to_exec(version: &Version) -> String {
if version.major >= 1 && version.minor >= 7 {
format!("https://dl.deno.land/release/v{}/{}", version, ARCHIVE_NAME)
} else {
format!(
"https://cdn.jsdelivr.net/gh/justjavac/deno_releases/{}/{}",
version, ARCHIVE_NAME
)
}
}
当然,社区也有大佬折腾出了"自给自足"的方法--向 Deno 学习优秀的脚本管理,果真是自己动手丰衣足食。
这就结束了?非也非也,Deno 的生态目前还不够强大,同样是版本升级带来的问题,这回轮到了 denon!
Denon 兼容之“锅”
Denon 之于 Deno 如同 Nodemon 之于 Node.js ;Denon 可以监视您的 Deno 应用程序中的所有更改并自动重新启动,避免了每修改一处代码就要手动重启的繁琐;此外,对于 Deno 应用来说,还提供了体验非常棒的配置。
在我们通过tcb new deno_hello deno
拉取的模板中,也能看到 Denon 的身影,denon.yml
:
scripts:
lint: deno fmt --check .
build:
cmd: mkdir dist && deno bundle --no-check src/entry.ts dist/entry.js
watch: false
start:
cmd: deno run --no-check dist/entry.js
env:
PATHNAME: "/deno-app"
allow:
- net
- env
- read
dev:
cmd: deno run --no-check src/entry.ts
env:
PORT: "3000"
allow:
- net
- env
- read
上边这个配置文件将我们可以做的一些事安排得明明白白:代码检查、打包构建、本地调试等。
那 Denon 带来了什么困扰呢?“罪魁祸首”还是因为 Deno 版本升级。当时,Deno 刚升到 1.7.0 ,使用 Denon 就会报错permission error
,参见:fix: permission error on latest deno:
TS2339 [ERROR]: Property 'url' does not exist on type 'NetPermissionDescriptor'.
? `--allow-${pd.name}=${pd.url}`
~~~
at https://deno.land/std@0.83.0/permissions/mod.ts:18:44
当时普遍认为 Deno 1.6.3 是比较稳定的版本,至少也不会导致 Denon 无法正常使用,我猜大概也是因为这个原因,我们在上文中提到 Cloudbase 中 deno 模板目前也是使用的 1.6.3。
出现类似的“锅”,如果您依旧想使用最新版本,那就只能等等兼容问题被处理,或者您亲自动手处理兼容问题。再回过头来看看这个兼容问题是如何处理的?看上去只是改了一个版本号,但究竟为何要这样改,估计只能深入 Deno 源码学习才能一探究竟了。
牛刀小试
既然所有的问题都如愿以偿地被社区大佬们解决了,那接下来,我还是想试试 Cloudbase 和 Deno 这两把“牛刀”,完成我琢磨了很久的一个 Hello World,姑且称为「一条热搜」。主要是不想浪费之前通过 Deno 获取的每日热搜数据,加上想体验一下 Cloudbase 的一键部署功能,难得 Cloudbase 支持 Deno 插件。
按照剧情,上文中初始化 Deno 项目之后,直接输出 tcb
这三个字母就能进行部署,「请尽量本地调试好应用再部署,每次部署都会」,当然,截止文章发布前,建议去到指定 Deno 版本的这行配置:
- "runtime": "1.6.3"
简单修改了一下 HelloWorld 的代码,让它变成一个我想要的「一条热搜」,数据基于「trending-in-one」,我粗暴地在 controller 中获取热搜数据:
const response = await fetch(`https://cdn.jsdelivr.net/gh/hu-qi/trending-in-one/raw/toutiao-search/${formatTime(new Date(),{template:'{{YYYY}}-{{MM}}-{{DD}}'})}.json`)
const responseJson = await response.json()
const index = Math.floor(Math.random() * responseJson.length);
const pathname = Deno.env.get("PATHNAME") || '';
ctx.response.body = await renderFile(`${Deno.cwd()}/views/home.ejs`, {
title: '一条热搜',
text: responseJson[index],
pathname,
});
来看看部署之后惨不忍睹的效果:
在线预览地址:http://deno-demo-3ghgaf7pa8d97b90-1253880795.ap-shanghai.app.tcloudbase.com/(PS:如果无法访问,那一定是我欠下巨款跑路了,您可以自行一键部署)
一键部署:
最后唠嗑一下 Cloudbase 的一键部署,「一键部署按钮可以让公开的 Git 项目一键部署到云开发 CloudBase 上,大大简化用户部署的门槛,便用户快速使用和体验应用。一键部署功能支持 Github,Gitlab,Coding,Gitee 等 Git 仓库地址。」 简直是 Copy 攻城狮的福音,复制粘贴都不用了,一键部署!(PS: 其实还是需要手动进行配置)
一键部署按钮的生成可以访问:https://docs.cloudbase.net/framework/deploy-button.html,只需填入仓库地址、目录和分支,这点和 Vercel 部署也有些类同:
总体体验还是不错的,不过最后还是遇到了一个访问地址的坑,还没来得及填,不过影响不大。大概是一键部署成功之后,访问地址*.ap-shanghai.app.tcloudbase.com/deno-app
在浏览器中打开时变成了文件下载,而实际服务的地址是没有deno-app
这个服务名称路径的,大概率是我的配置有点偏差,弃坑弃坑!
小结
总得来说,随着 Deno 生态的不断完善,Serverless 部署 Deno 应用变得越来越简单。借助云开发 Cloudbase,您无需关注 Deno 的安装实现、服务的运维等等,还能以最低的成本运行 Deno 应用。希望我的踩坑能够给您启发,请多多指教,感谢!