@ base44/ 函数编译器
Base44后端功能的生产编译器. 函数源为
数据并返回单一的 Cloudflare 工人模块——生成的工人
条目、 Deno shim、 运行时间和私有数据源模块以及 npm/jsr
依赖性分辨率通过 @deno/loader + 建设.
两个消费者共享这个引擎:
- 页:1 基数44 CLI,用于本地编译(并在平台的建筑内) sandbox),路径中没有网络服务;
- 阿普尔的
base44-userapp-bundlerHTTP 服务,它保持自己的功能 端点、认证、工人池和周围遥测.
状况和范围
内部至基地44——已出版 公开 所以apper的捆绑服务可以安装 它,但它不是一个支持的公众 API:CLI捆绑在建设时间 终端用户从不安装它,它不会给任何人带来兼容的承诺 此回转外. 汇编是其全部工作,现在包括: 源组装,硬度规划,大小测量和分出. 艺术 写作,版本创建,上传和部署在其上方的活性.
软件包没有证书,也没有自己的配置。 这个
命名生成的工人在
运行时间( o)BASE44_*, (中文(简体) ), X-Base44-*)但是没有他们的价值观和代码
船是已经编入所有部署的用户工的代码.
硬块和整件应用建筑
此软件包将一个应用程序的整个后端功能集变为可部署 Cloudflare
工人:它把每个函数的源头组装起来,将它们组成碎片,编译
每个硬的,用它来测量云浮的天花板, 将任何坚硬的
模块超过一个. compileFunctionShards 是切入点,而且与
bundleApp 它拒绝部分结果 —— 一个模块缺少一个处理器是损坏的
应用,不是一个较小的成功.
每一块都来自Apper, 而出处值得保存:
| 块 | 从哪里来 | 给 |
|---|---|---|
| 源装配 | function_bundle.py —— 说 cfw_bundle_input, (中文(简体) ), collect_reachable_backend_files | src/assembly.ts |
| 新的硬计划 | shard_planning.py —— 说 full_repartition, (中文(简体) ), target_shard_count | src/shards/plan.ts |
| 大小测量 | cloudflare_wfp_runtime.py —— 说 measure_bundle_bytes, (中文(简体) ), judge_bundle_size | src/shards/size.ts |
| 溢出时分拆 | cloudflare_wfp_runtime.py —— 说 _build_shard_with_split | src/shards/build.ts |
| 全面建设验证 | 最高公关号23460 | src/shards/build.ts |
政策数字——硬度大小,硬度计数,压缩盖等——作为投入而来.
软件包未读取设置和特征旗, 以及两个包装旗
(单位:千美元)postResponseTelemetry, (中文(简体) ), runtimeSecrets)是交给它的,因为两个变化
所释放的字节,只有平台知道其对应用程序的价值.
故意不在此地: Deno 部署目标、现有工人再利用、供应商 上传、装订分辨率、秘密交货和再利用 版本是从零开始构建的,所以这里没有任何东西能记住之前的部署. 这个 引擎保持其对仍然使用它的后遗症服务的演员支持.
一捆东西说自己什么
一个被编译的硬体的第一行是它自己的表:
//!b44:1 {"functions":["cleanupForgottenDepartures","health","sendReminder"],"telemetry":false,"runtimeSecrets":false,"compiler":"0.1.0"}
//!b44:<format> 是一个固定的哨兵,所以 head -1 脚本
Cloudflare回答“这里面是什么?” 不执行或分析任何东西,和
有效载荷是JSON,所以一个工具 描述它在一个呼叫。 只有应用路径发出它.
传统的单一职能 bundle() 保持无横幅: 它编译一个函数,
因此,“哪些功能在内部”已经得到了答案。 apper的捆绑服务
现在运行此软件包( 它不再保留自己的引擎), 没有比对
该车道的输出字节 对于字节跨引擎.
functions 被排序 任何的顺序 硬的构建. telemetry 财务报告和审定财务报表
runtimeSecrets 因为他们改变 释放的字节,部署
把秘密交给他们. compiler 是此软件包的版本; 它
也告诉一个消费者 包装器的特征 建筑承载,例如
_b44_error 记录(见“处理过的5xx记录错误”).
无法添加任何挥发性:一个时间戳或构建 id 会重新闪烁一个版本 对于不变的代码, app id 将使相同的函数编译不同 每个应用程序, 和shard的地位 将使两个相同的shards不同.
复制是合同,不是好东西
一个版本的身份是 编译的文物从没有 来源。 任何改变所释放的字节的事物 都会使新版本的 代码没有改变,所有这些都做了:
- 此软件包的版本和深度
node_modules这是建造的 反之- 建造 将每个小贩的相对路径写入小块 输出,所以构建一个目录更浅会改变每个用户Worker的字节; - 调用者将功能交接到其中, 用于一个硬度: 该路径
以呼叫者顺序构建,而多硬性计划则按名称排序. 两个分支机构
他们像apper有
shard-build.e2e.test.ts标出差异; - 或包装旗 (
postResponseTelemetry, (中文(简体) ),runtimeSecrets) (中文(简体) ). 这个_b44_error录音机不是一面旗帜:每个建筑都带着它,所以它会移动 仅在此软件包的版本完成时才有字节 .
两种行为与Apper的Python故意不同,两者都经过了测试:
- 出无相源. apper 自己看每个文件, 所以一个文件 无法解析集合其余部分仍然组装时的边缘. esbuild的行走是整个图上的一栋建筑,所以里面任何无法分割的东西 拒绝 —— 倒置是平面单文件提交, 然后是编译器 报告错误.
- 压缩大小. 节点的gzip读取比Python重约0.7% 相同输入:43,057字节对42,765个正版122,324字节模块. 这个 方向是安全的,因为这条车道拒绝的时间略早于 服务会.
用这个
import { bundle, bundleApp } from "@base44/functions-compiler";
const result = await bundle({
entry: "main.ts",
files: { "main.ts": "export default { fetch: () => new Response('hi') }" },
});
if (result.ok) console.log(result.module);
bundleApp 将若干功能汇编成一个综合模块和报告
每个函数状态; 成功的响应仍然可以包含失败的函数,
因此,一个需要整体建设的呼叫者必须拒绝他们自己.
原始地图
sourceMap: true 在两个请求返回时 source_map 旁边 module页:1
外部源图,其源代码为用户所写文件的名称 。 这是关闭的
默认时, 公共 CLI 永远不会设置它, 而用它关闭输出不变 .
有了它,模块就不同了,只有后行
//# sourceMappingURL=_bundled.mjs.map 注释; 保存并上传地图
旁边那个名字下的模块.
是什么被重新塑造, 由谁:
- 一个未发现的例外 {\fn黑体\fs20\shad2\2aH82\3aH20\4aH33\fscx95\3cH592001\be1} - 尾部工人的堆栈 {\fn黑体\fs20\shad2\2aH82\3aH20\4aH33\fscx95\3cH592001\be1} - The stack in a Tail Worker's
exceptions。 。 。 . Cloudflare 用上传的地图重新描绘它 引用之后和外部 工人们. - 工人日志本身的堆栈保持精密化,因为地图不是
运行时可用。 包括每个应用程序的条目
console.error(e)重新删除之前, 以及任何错误用户代码日志 。 一个消费者读这些 线条用同版本的source_map。 。 。 .
当地工人没有重新绘图。 所以这里的测试 映射出一个 Tail 例外 通过手动绘制的图框,显示运行时间报告的位置 与地图一起排列。 Cloudflare自己的重新绘图需要部署的检查.
地图上没有 sourcesContent 没有 sourceRoot。 。 sources 为:
重写 :
- 请求文件保留其路径; 在每个应用程序中捆绑
fn_<index>/前缀 剥离,并对照该函数自己的文件检查路径; - 函数的条目成为其
entryPath,当请求发出一个- 提交为main.ts· ; - 其他一切(shim、生成的条目和包装、虚拟)
运行时间模块、npm和远程模块)留在列表中,因为
将索引映射到其中, 并带有前缀
base44-internal:。 。 。 .
每个函数探测器编译 bundleApp 运行到属性错误跳过
地图,因为它们跳过遥测; 演员条目和 compileFunctionShards 永远
问一. 每个应用程序中有两个功能
捆绑可以同时列出 a main.ts所以消费者需要知道
函数框架属于从日志行读取,而不是从地图读取.
处理的 5xx 错误记录
一个能够捕捉到自己错误并返回500叶 Cloudflare 的函数 没有记录. 每个建筑 带入一个小记录器 条目(单功能和每个应用程序;不是演员),没有构建选项。 那个 包括公共CLI的自建, 所以一个应用程序已经准备好了, 没有重建。 它在一个模块中增加了大约3个KB(约1.2个KB gziped).
关闭开关是请求,而不是构建:记录器不做任何事情,除非
请求包含 x-b44-feed-context后端只为
(b) 启动
关闭每捆记录,无论它建造。 没有
记录器头需要每个请求一个头检查和一个上下文查看
百分比 console.* 电话.
当信头出现, 处理器返回一个 Response 有状态
500,同样的反应一次又一次:从未重建,从未被拖延,没有
头套. 在克隆人体内 ctx.waitUntil,录音机:
- 选择信件, 按此顺序 : 在请求中记录错误, 其错误
消息 JSON 机构重复( 这是最近8个错误中的最新错误 )
记录,因此后来不相关的警告不能隐藏它;否则尸体(JSON of J
最多2 048个字节在 50 ms 内读取; 第一个非空
error, (中文(简体) ),message, (中文(简体) ),detail, (中文(简体) ),details或者说error.message,跳过error当它 没错"Internal server error"财务报告和审定财务报表details; 否则是最后一个 在请求中记录错误 . 无信息即无记录; - 只从提供消息的已登录错误中取出堆栈 。 没错
错误为原始
stack,在工人内部读取,所以它是 已修改数字 : Cloudflare只重新描绘它捕捉到的例外,从没有被记录的字符串. A 类 消费者用同一个版本的source_map(见原始地图); - 用
[redacted]时间最长,在切东西之前 包括字符串 以 JSON 值为单位的嵌入( 允许在白空间前), 例如 私人数据来源清单; - 盖子
name在64个字符,message以500 UTF-8 字节( 成型良好, 切) )和stack4 KB(切入一行端); - 日志完全为一行,与
console.error({ _b44_error: record })。 。 。 .
呼叫通过控制台补丁,所以 对象不是什么 消费者看. 尾巴工人会得到这样的记录
| 外地 | 数值 |
|---|---|
尾端项目日志 level | "log"。补丁会通过原件写入每个关卡 console.log |
日志 message | 以 一个 参数: 补丁的包装对象 |
| 包装键 | _b44_env, (中文(简体) ), _b44_function (只应用捆绑), level, (中文(简体) ), message |
包装 level | "error" |
包装 message | 页:1 JSON 字符串 联 合 国 { "_b44_error": { v: 1, kind: "response", status, name?, message, stack? } } |
所以消费者会保存包装的日志 level 实值 "error",然后读取
JSON.parse(wrapper.message)._b44_error. apper 错误尾巴
(单位:千美元)workers/base44-log-tail/src/error-tail.ts是消费者,和
error-records.e2e.test.ts 为两个条目标出此形状。 记录是
登录在内 waitUntil在回击后,它永远不会降落
输入 X-B44-Invocation-Logs 头曰. 这还是一条普通的纹章,所以
在被盖章的工人日志行上所建视图显示为错误行.
任何失败都写不出来,也从未达到要求. 一个未触碰的投球是 未出:入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出入入入入入入入入入入入入入入入出出出出出出出出出出出入出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出.
进程隔离
installFetchGuard() 块出局 fetch 除抚养人以外
解析器本身执行。 在工人或儿童身上安装
进程,运行一个编译——而不是一个后来需要网络的过程.
诊断
编译者无追蹤器和服役证书. 需要跨度的主机 或结构化日志在运行编译的线程中注册自己的:
import { setCompilerTracer, setLogSink } from "@base44/functions-compiler";
setCompilerTracer({ withSpan, setSpanTags }); // e.g. a dd-trace adapter
setLogSink((level, event, fields) => myLogger[level](event, fields));
没有水槽, logEvent 写出它一直以来的Datadog形状的JSON行.
静态进取 TCP 运行时间
编译函数曝光 staticEgress 从 base44:runtime数字 :
import { staticEgress } from "base44:runtime";
const socket = await staticEgress.connect({ hostname: "sftp.example.com", port: 2222 });
API 读取当前信任的工人环境, 只调用
STATIC_EGRESS.connect,并拒绝工作空间门或绑定时
无. 它永远不会回到直接TCP。 可选的第二个论点
仅支持 { secureTransport: "off" }; SSH提供自己的加密.
TLS/STARTLS 和未知选项拒绝 。 呼叫者拥有认证 超时,
流锁和套接字清理。 公共套接字暴露出溪流, opened, (中文(简体) ),
closed,以及 close()。 。 。 .
src/static-egress-tcp-core.mjs 与 apper 相匹配
backend/app/static_egress/tcp.mjs,它的捆绑器和满层上传器
共享 。 保持源和合同测试的对齐,直到内部检索编译器
已经退休了. build:shim 将这个核心嵌入运行时shim; 这不是运行时
文件系统依赖。 内部清单的进口商许可证包括:
精确的注入运行时间 shim 这样激活的 PDS 排除是
在不使显示的用户可进口的情况下执行.
在撞出 Apper 的编译针前释放此包. 现有汇编 工人需要重建;工作空间切换没有安装新代码.
Npm 客户端的工人兼容性
工人打破常见的节点目标 npm 包的两个缺口, Stagehand 中 ,而编译器会同时关闭每个函数和演员:
ws。 。 。 . 它的出口地图发送browser条件到一个扔出 在使用时.src/esbuild/ws-native-virtual.ts解析为赤色ws财务报告和审定财务报表npm:ws[@version]改为ws- 字形客户端比工人的本地WebSocket (单位:千美元)on编号 :once编号 :off, (中文(简体) ),send, (中文(简体) ),close, (中文(简体) ),terminate, (中文(简体) ),readyState) (中文(简体) ). 它覆盖 舞台手用什么,不是整个wsAPI (英语). 当选项带有信头时 外加User-Agent(Stagehand'scdpHeaders,以fetch升级后,它们可以到达服务器 函数的 Egress 路由。 其他连接选项被忽略,以及WebSocketServer抛出:一个函数可以打开套接字而不能听 .AsyncLocalStorage.enterWith()。 。 。 . 工人的版本抛出。 德诺之声 取而代之的是"禁",所以店从不播种. 适合图书馆 并重新进入其中run()编辑 shim首先探测,并保持有效的本地执行.
版式
| 路径 | 这是什么 |
|---|---|
src/bundler.ts | 单函数和合并应用程序汇编、错误归属 |
src/deno-bundle.ts, (中文(简体) ), src/esbuild/ | 重建执行和解析器/虚拟模块插件 |
src/worker-entry.ts, (中文(简体) ), src/actor-compat.ts | 生成的工人条目和演员包装 |
src/shim/, (中文(简体) ), src/static-egress.ts | Shim 来源——为 build:shim,从未导入 |
src/runtime/, (中文(简体) ), src/runtime-context.ts, (中文(简体) ), src/private-data-sources/ | 编译时间资产读作 文本 并注入用户捆绑 |
编译时间资产必须保留类型Script:虚拟插件加载
与建设的 ts 加载器. scripts/build-shim.ts 嵌入他们,与三个
把它建起来,像弦一样 src/generated/assets.ts,所有读取
他们通过 src/assets.ts。编译器没有读取自己的文件,因为
路径相对 import.meta.url 消费者一旦有文件就停止命名
把它捆起来 未执行生成的模块 : prepare 写在
安装, 何为根 package.json 允许通过 trustedDependencies —— 说
bun默认会阻断依赖的生命周期脚本, CLI 依赖于
这个工作空间.
esbuild 财务报告和审定财务报表 @deno/loader 首次使用时进口(src/lazy-deps.ts(没有)
与调用它们的模块。 一个将编译器捆绑的消费者
外部的, 和捆绑者举起 外部的无害环境管理进口到它的顶端
输出——在消费者启动时加载本地二进制和WASM模块
无论它是否编译.
不要重塑资产. 他们的文字输入用户的捆绑,所以
白空间是被排放的工人字节的一部分——运行在 Biome 上
src/shim/, (中文(简体) ), src/private-data-sources/, (中文(简体) ), src/runtime/, (中文(简体) ), runtime-context.ts, (中文(简体) ),
static-egress.ts, (中文(简体) ), static-egress-tcp.ts, (中文(简体) ), static-egress-tcp-core.mjs
或者说 static-egress-marker.ts 更改每个编译的内容
函数散列. biome.json 因此,排除这些路径。 这个
test/ 目录同样与 apper 复制的字节相同,直到
副本被删除; 它坐落在 repo 之外 packages/*/src 闪闪发光.
图标
bun run build:shim # regenerate src/generated/assets.ts (shims + text assets)
bun run test # vitest (regenerates the assets first)
bun run typecheck # tsc --noEmit over src/, test/, scripts/
bun run build # assets + tsc -> lib/; what gets published
exports 只有点数 lib/唯一的一件事是柏油球飞船 有一个
故意不解析源导出条件: 第二个解析路径
因为软件包意味着"哪个代码运行"的两个答案. 国家领导才能没有
通过 exports 它将软件包映射到 src/index.ts 它本身
tsconfig并捆绑源代码 lib/ 编译的,所以它的捆绑是
回答CLI,它不需要 bun run build 先来.
释放
运行 手动函数编译器出版 工作流程
(单位:千美元).github/workflows/functions-compiler-publish.yml) 从动作标签。 这个
单击版本,同步 COMPILER_VERSION 字元, 构建 lib/, (中文(简体) ),
发布到 npm, 并推动 a functions-compiler-v<version> 标签外加
释放承诺.
一个版本生活在两个文件中—— package.json 和字数
src/version.ts 进入每一个编译的Shard的旗帜。 手打脚打
表示运行 bun run scripts/sync-version.ts 编辑后 package.json· ;
version.test.ts 如果两者分开,则会失败。 国家领导学院自己的
释放列车是一个独立的工作流程,有自己的 v<version> 标记; 两者
永远不移动在一起.
认证为 npm 值得信赖的出版 (OIDC)——在回购中没有符号. 这个
在 repo 上信任的出版商的注册密钥 和工作流程文件名这样
@base44/functions-compiler 在 npmjs.com 上需要自己的条目
functions-compiler-publish.yml; 条目 manual-publish.yml 别
盖住它.
工作流程只构建和发布. 证明柏油球有效的东西
scripts/verify-package.ts把它装入一个抛出物
目录和汇编一个真实的函数——运行于 functions-compiler.yml
在每次推动 main在Wix封锁网关后面 从犯罪中公布
绿色的.