关于 morphe
morphe 是用于将 Next.js、Bigfish 或 Vite 项目打包并部署到 Morphe 的技能。它按框架生成可运行的 ZIP,支持静态 SPA 与 Vite 自定义服务器模式。
主要功能
- 01检测 Next.js、Bigfish 和 Vite 项目
- 02为 Next.js 整理独立服务器构建
- 03为静态项目生成零依赖服务器
- 04将 Vite 自定义服务器打包为单文件
- 05执行打包、上传校验与部署
适用场景
- 01部署 Next.js 独立构建
- 02将 Bigfish 静态站点部署到 Morphe
- 03部署 Vite SPA
- 04打包带 API 路由的 Vite 自定义服务器
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ zenmux/ skills --skill morphe安装后在 Claude Code 中输入/morphe确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/api.mdnextjs-config.mdscripts/auth-callback.mjslogin.shmorphe.py详细介绍
Morphe 部署
概述
将 Next.js、Bigfish(@alipay/bigfish)或 Vite 项目部署到
Morphe(运行时 custom.debian11,linux-x64-gnu)。运行时始终通过
node server.js 启动函数,因此每种框架最终都会打包成一个根目录包含 server.js 的 zip 文件:
- Next.js → 独立服务器(
.next/standalone/server.js)及其 跟踪到的node_modules。打包时会剔除平台不匹配的原生绑定,并修复 pnpm 不完整的软件包。 - Bigfish → 静态 / SPA 构建(
dist/)。打包时会生成一个零依赖静态server.js(仅使用 Node 内置模块——无需安装任何内容),用于提供构建目录,并在 SPA 模式下回退到index.html。 - Vite → 两种模式。纯 SPA(
vite build→dist/,无服务器) 会复用与 Bigfish 相同的零依赖静态封装器。自定义服务器 应用(包含用于提供dist/和后端 API 路由的server.ts/server.js,例如 Express)会通过 esbuild 打包为位于 zip 根目录的独立server.js,构建目录则与其并列。
易出错且需要确定性处理的 API 操作(身份验证、预签名、上传、CRC64、.morphe.json、
部署)位于 scripts/morphe.py 中。构建和配置的判断步骤由你负责。
所有 scripts/morphe.py 命令都要在项目根目录下运行。将下方的 SKILL_DIR 替换为此技能所在的目录(即包含此文件的文件夹)。
工作流
按顺序执行以下步骤。任何步骤失败时,立即停止并报告。
1. 确认已登录
通过浏览器登录——绝不要向用户索要用户名或密码:
bash SKILL_DIR/scripts/login.sh
这与 gh auth login / vercel login 类似:用户只需在浏览器中点击,无需复制粘贴令牌。
- 如果
~/.morphe/auth.json中已存在有效的accessToken,脚本会复用它并跳过浏览器(立即输出AUTH_OK=1)。 - 否则,脚本会启动本地回调服务器,在浏览器中打开
morphe.zenmux.app/cli-auth(输出OPEN_AUTH=<url>——如果浏览器无法自动打开,请将其展示给用户),并等待。用户登录(使用密码或 Google 登录)后,点击**「授权并返回终端」**;浏览器会将令牌 POST 回来,脚本再将令牌写入~/.morphe/auth.json。 - 成功后,脚本会输出
AUTH_OK=1。如需强制重新登录(例如切换账号),请运行bash SKILL_DIR/scripts/login.sh --force。 - 如果脚本报错或超时(未输出
AUTH_OK=1),请报告错误并停止。
2. 检测框架
python3 SKILL_DIR/scripts/morphe.py detect-framework --project-root .
输出 nextjs、bigfish、vite 或 unknown(退出码为 1)。检测顺序如下(匹配第一个即停止):
- bigfish —
package.json依赖中包含@alipay/bigfish,或存在config/config.ts(优先检查;Bigfish 项目也使用类似 next 的构建脚本和 vite 风格工具)。 - nextjs — 依赖中包含
next,或存在next.config.{js,mjs,ts}。 - vite — 依赖中包含
vite,或存在vite.config.{js,mjs,ts,mts,cjs}(最后检查;其匹配范围最广)。
如果输出 unknown,请告知用户“暂不支持该项目类型(仅支持 Next.js、Bigfish 与 Vite)”
并停止。否则记住检测到的框架——它决定后续的构建和打包路径。
3. 确定函数名称
询问用户要部署的函数名称。告知他们:如果不知道填什么,
可以留空,会自动生成一个 user-xxxxxxxx 格式的随机函数名。
- 如果
.morphe.json中已有function_name,请说明这是当前默认值,并让用户选择保留(直接按回车)或覆盖。 - 保存该选择(输入为空 → 保留现有名称或生成新名称):
# user provided a name:
python3 SKILL_DIR/scripts/morphe.py set-function-name --name "NAME" --project-root .
# user left it blank:
python3 SKILL_DIR/scripts/morphe.py set-function-name --project-root .
该命令会输出最终函数名称并将其写入 .morphe.json。
每次重新部署都会复用此名称,因此会更新同一个函数。
4. 验证并修复构建配置
步骤 4–6 因框架而异。 根据步骤 2 检测到的框架,遵循相应分支。
4a. Next.js
目标:每个原生依赖的运行时目标(linux-x64-gnu)二进制文件都必须在构建前安装到磁盘上,这样 Next 的追踪器才能找到它。morphe.py package 步骤(步骤 6)会处理顶层放置、清理和打包,但只能打包安装时实际下载的二进制文件。
直接编辑配置,确保:
-
独立输出——
output: "standalone"(否则没有.next/standalone/可供打包)。 -
在构建主机上安装 Linux 二进制文件。 原生扩展以各平台的可选依赖形式发布;在 macOS 上安装只会获取 darwin 版本。
- pnpm(
pnpm-workspace.yaml)——添加supportedArchitectures,以便同时获取 linux-x64-gnu 二进制文件。这是最重要的修复;完成后,追踪器会自动包含绑定,通常完全不需要outputFileTracingIncludes:
然后重新运行supportedArchitectures: os: [current, linux] cpu: [current, x64] libc: [current, glibc]pnpm install。 - npm/yarn——安装目标平台所需的特定绑定,例如:
npm i --no-save @resvg/resvg-js-linux-x64-gnu --force --os=linux --cpu=x64 --libc=glibc。
- pnpm(
-
(可选)进一步缩减打包内容。
morphe.py package已会清理所有非 linux-x64-gnu 原生二进制文件,因此不需要为它们设置outputFileTracingExcludes。仅为运行时不需要的项目数据添加排除项(大型测试夹具、原始数据集、文档)。保留运行时通过process.cwd()读取的内容(字体、路由读取的 JSON)。
详情、各软件包的绑定名称,以及如何确认 Linux 二进制文件已在磁盘上,请参阅 references/nextjs-config.md。
4b. Bigfish
无需处理原生绑定——Bigfish 会构建静态 / SPA 包,morphe.py package 会生成零依赖的 server.js(仅使用 Node 内置模块)。Linux 目标无需安装任何内容,通常也无需修改配置。
- 确认应用构建为静态包。默认的 Bigfish
site构建会生成dist/(包含index.html和带哈希的 JS/CSS),生成的静态服务会提供这些文件。此静态封装不支持deployMode: 'render'(SSR)——如果应用确实需要在运行时进行服务端渲染,请停止操作并告知用户,静态方案无法提供其 SSR 路由。 - 如果构建输出目录不是
dist/(Bigfish 允许覆盖该目录),请记下目录名称;步骤 6 中会通过--static-dir传入。
4c. Vite
Vite 有两种模式;morphe.py package(步骤 6)会通过探测服务端入口(server.{ts,js,mjs,cjs},也包括 src/ 下的入口)自动检测模式。
-
纯 SPA(没有服务端入口)——无需安装或修改,与 Bigfish 完全相同。
vite build会生成dist/(index.html+ 哈希资源),生成的零依赖静态server.js会提供这些文件,并支持 SPA 回退。如果输出目录不是dist/,请在步骤 6 中为--static-dir指定该目录。 -
自定义服务端(用于提供
dist/和 API 路由的server.ts/server.js)——package会将该入口通过 esbuild 打包为自包含的server.js。请确保服务端:- 监听
process.env.PORT || 3000并绑定到0.0.0.0(运行时会设置PORT,并将请求路由到所有网络接口); - 从
process.cwd()读取静态目录(例如path.join(process.cwd(), "dist")),因为 zip 会将构建目录与server.js一起放在运行时工作目录下; - 仅在开发环境中使用
vite导入。vite始终会从打包产物中外置(它体积庞大,还会引入无法打包且会导致构建失败的原生.node插件——esbuild/ lightningcss/fsevents)。生产服务端不得加载它。请将任何 dev-middleware 的 vite 用法放在延迟执行的非生产分支中,例如:if (process.env.NODE_ENV !== "production") { const { createServer } = await import("vite"); // 延迟加载:绝不会被打包 // ... dev middleware }
运行时密钥(API 密钥等)应放在函数环境中,而不是 zip 中——构建过程绝不会打包你的
.env。- 如果服务端需要将额外的软件包保留在打包产物之外(例如 esbuild 无法内联的原生
.node插件),请在步骤 6 中通过--external NAME传入该软件包——但该软件包必须在运行时可访问(这是边缘情况;大多数纯 JavaScript 依赖都能顺利打包)。
- 监听
5. 构建
npm run build # or: pnpm build / yarn build (Bigfish: also `bigfish build`)
请勿手动复制资源或手动打包 zip——步骤 6 会完成所有组装。(Vite:此处只运行前端构建以生成 dist/。对于自定义服务端应用,无需自行打包服务端——package 会在步骤 6 中为你运行 esbuild。如果你的 build 脚本已通过 esbuild 打包服务端,也没有问题;package 无论如何都会将其重新打包到暂存的 zip 中。)
6. 组装最小部署 zip
python3 SKILL_DIR/scripts/morphe.py package --project-root .
package 会自动检测框架(使用 --framework nextjs|bigfish|vite 覆盖)。此操作具有幂等性(可安全地重复运行,但如果代码有更改,请先重新运行构建)。
Next.js — 将 .next/standalone 组装成可运行的 zip:
- 将
.next/static和public/复制到打包文件中(构建不会跟踪这些目录); - 修复 pnpm 不完整的软件包——顶层
node_modules/<pkg>目录中只有package.json,而实际文件位于.pnpm中(这种遮蔽会导致node server.js崩溃,例如报错 Cannot find module@swc/helpers/cjs/_interop_require_default.cjs); - 删除所有非
linux-x64-gnu的原生绑定(darwin/musl/arm64,通常超过 100M),并将保留的 Linux 绑定符号链接到顶层 node_modules,以便运行时通过裸模块路径require("<pkg>-linux-x64-gnu")解析。缺少此步骤时,SVG 类代码路径可以正常工作,但任何调用原生扩展的路径都会报 500,并显示 Cannot find module…-linux-x64-gnu; - **使用保留符号链接的方式(
zip -y)**将文件压缩到.next/standalone目录外的./code.zip(这样就不会把上一次生成的code.zip嵌套进去)。运行时会保留符号链接,而 pnpm 的目录布局大多是指向.pnpm的符号链接,因此 zip 体积大约能减半。
Bigfish — 组装静态服务端 zip:
- 定位构建输出目录(自动探测包含
index.html的dist、build、out目录;使用--static-dir DIR覆盖); - 生成零依赖的
server.js(仅使用 Nodehttp/fs/path),用于提供构建目录的内容,并为客户端路由回退到index.html; - 暂存
server.js和构建目录并压缩,使server.js位于 zip 根目录,构建目录与其并列。没有node_modules,因此 zip 体积很小。
Vite — 两种模式,通过探测服务端入口自动选择:
- SPA(未找到服务端入口)——与上述 Bigfish 流程相同:生成零依赖静态
server.js和构建目录。 - 自定义服务端(自动探测
server.{ts,js,mjs,cjs}入口;使用--server-entry PATH强制选择或覆盖)——使用 esbuild 打包入口(--bundle --platform=node --format=cjs,始终将vite设为外部依赖,还可指定任意--external NAME),生成独立的server.js,然后将其与构建目录暂存(自动探测dist/build/out;使用--static-dir覆盖)并压缩,使server.js位于 zip 根目录。依赖会内联,因此不会打包node_modules。
完成后会打印最终路径、大小和框架,例如:
packaged: …/code.zip (25M)、packaged: …/code.zip (0.2M, framework=bigfish)
或 packaged: …/code.zip (0.7M, framework=vite, mode=server, entry=server.ts)。
7–11. 上传、校验和部署
一条命令即可依次完成预签名 → 使用 curl PUT 上传 → CRC64 校验和 →
更新 .morphe.json(写入 checksum;使用第 3 步解析出的 function_name,仅在该字段仍缺失时才生成)→ 调用 /api/deploy:
python3 SKILL_DIR/scripts/morphe.py deploy --zip code.zip --project-root .
成功后会打印部署结果 JSON(包括 action、functionName,以及在可用时的 triggerUrl),随后删除本地 code.zip(它已上传到 OSS,而且体积较大、无需保留)。传入 --keep-zip 可保留文件以供检查。失败时会保留 zip,以便重试部署。请向用户报告结果;如果有 triggerUrl,请提供给他们。如果输出 not-logged-in 或 HTTP 错误,请返回第 1 步(令牌可能已过期)或报告失败。
备注
- Morphe API 声明使用 Cookie 进行身份验证,但登录会返回
accessToken; 脚本会同时将它作为morphe_sessionCookie 和 Bearer 请求头发送。 .morphe.json中的function_name只会生成一次,并在每次重新部署时重复使用, 这样更新的是同一个函数,而不是创建重复函数。请勿手动编辑或重新生成它。- 所有框架都使用默认的
command="node server.js"和port=3000进行部署,不使用针对特定框架的部署标志。Bigfish / Vite-SPA 静态 服务会遵循process.env.PORT(默认为 3000),因此保持一致;Vite 自定义服务也 必须如此(步骤 4c)。 - (Next.js)缩小
code.zip体积大多可通过morphe.py package自动完成(清理绑定 + 保留符号链接的压缩)。剩余的大文件通常是 项目数据:构建时被追踪进来的原始数据集、测试夹具、生成的输出文件(位于服务端组件调用readdir的目录下)。可在 Next 配置中通过outputFileTracingExcludes排除这些文件,但切勿排除通过process.cwd()在运行时读取的文件(字体、路由解析的 JSON)。 (Bigfish 压缩包仅包含静态构建产物,体积本来就小,也不含node_modules。) - (Next.js)如果原生扩展在运行时仍返回 500 错误,并显示 Cannot find module
<pkg>-linux-x64-gnu:表示构建主机上没有安装该二进制文件。修复安装配置(步骤 4a:pnpm 使用supportedArchitectures,或执行npm i --os=linux --cpu=x64 --libc=glibc …),然后重新安装、构建并打包。预期的 Linux 绑定缺失时,package会发出警告。 - (Bigfish)客户端路由显示空白页或返回 404,意味着 SPA 回退没有指向
index.html,或者构建目录不是dist/。确认构建目录中存在index.html;如果目录不是dist/build/out之一,请传入--static-dir。生成的静态服务适用于静态构建;SSR(deployMode: 'render')应用需要真正的服务入口,而不是这个包装器。 - (Vite)
package的 esbuild 步骤失败(例如出现 No loader is configured for ".node" files,或vite/lightningcss/fsevents导致 glob/require.resolve错误):服务入口在顶层导入了vite(或其他原生扩展依赖)。请将该导入设为仅供开发使用或延迟加载(步骤 4c),以便将其外置;或者通过--external NAME传入该依赖。 - (Vite)SPA 空白页 / 客户端路由返回 404——与 Bigfish 的情况相同:确认构建目录中存在
index.html;如果目录不是dist/build/out,请传入--static-dir。自定义服务路由返回 500通常意味着某个依赖被外置了,但运行时实际需要它;或者服务从process.cwd()以外的路径读取静态目录。请按照步骤 4c 修复。 - (Vite)后端路由在运行时返回 500,但本地正常,通常是缺少运行时密钥——请在函数环境中设置 API 密钥等(它们不会从你的
.env打包进压缩包)。 - 完整 API 参考:
references/api.md。