mcpField
M
morphe

morphe

github.com/zenmux云与 DevOps20180 次安装7 周前更新
代码仓库

关于 morphe

morphe 是用于将 Next.js、Bigfish 或 Vite 项目打包并部署到 Morphe 的技能。它按框架生成可运行的 ZIP,支持静态 SPA 与 Vite 自定义服务器模式。

主要功能

  1. 01检测 Next.js、Bigfish 和 Vite 项目
  2. 02为 Next.js 整理独立服务器构建
  3. 03为静态项目生成零依赖服务器
  4. 04将 Vite 自定义服务器打包为单文件
  5. 05执行打包、上传校验与部署

适用场景

  1. 01部署 Next.js 独立构建
  2. 02将 Bigfish 静态站点部署到 Morphe
  3. 03部署 Vite SPA
  4. 04打包带 API 路由的 Vite 自定义服务器

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/zenmux/skills --skill morphe

安装后在 Claude Code 中输入/morphe确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
api.md
nextjs-config.md
scripts/
auth-callback.mjs
login.sh
morphe.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)会处理顶层放置、清理和打包,但只能打包安装时实际下载的二进制文件。

直接编辑配置,确保:

  1. 独立输出——output: "standalone"(否则没有 .next/standalone/ 可供打包)。

  2. 在构建主机上安装 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。
  3. (可选)进一步缩减打包内容。 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。请确保服务端:

    1. 监听 process.env.PORT || 3000 并绑定到 0.0.0.0(运行时会设置 PORT,并将请求路由到所有网络接口);
    2. 从 process.cwd() 读取静态目录(例如 path.join(process.cwd(), "dist")),因为 zip 会将构建目录与 server.js 一起放在运行时工作目录下;
    3. 仅在开发环境中使用 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(仅使用 Node http/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_session Cookie 和 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。

评论

支持 Markdown