잠시만요, 달이 떠오르면 글도 환해질 거예요.
wasmInit ??= readFile(
/* turbopackIgnore: true */ findPackageFile('@resvg/resvg-wasm', 'index_bg.wasm'),
)const isSharpEntry = (parent, name) =>
(parent === 'node_modules' && name === 'sharp') ||
(parent === '@img' && name.startsWith('sharp-')) ||
(parent === '.pnpm' && (name.startsWith('sharp@') || name.startsWith('@img+sharp-'))){
"rewrites": [
{ "source": "/feed.xml", "destination": "/feed" },
{ "source": "/sitemap.xml", "destination": "/sitemap" }
]
}on:
push:
branches: [main]
workflow_dispatch:
steps:
- uses: actions/checkout@v6
with: { ref: feat/edgeone-makers, fetch-depth: 0 }
- run: git fetch origin main && git merge --no-edit origin/main
- run: git submodule update --init --recursive
- run: git push origin HEAD:feat/edgeone-makers
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with: { node-version: 22, cache: pnpm }
- run: npm install -g [email protected]
- working-directory: apps/web
env:
EDGEONE_PAGES_API_TOKEN: ${{ secrets.EDGEONE_API_TOKEN }}
run: edgeone makers deploy -n yohaku-preview -e production -a overseas --json
前言
之前我一直用 Docker 自托管 Yohaku(mx-space 的 Next.js 前端)。这次想试试腾讯云 EdgeOne Makers(原 EdgeOne Pages)能不能把它跑起来 。结论是能,现在 yohaku-eo.zwh.moe 就跑在 EdgeOne 海外区。不过中间让 AI 替我踩了不少坑:函数包体积超限、平台和 Vercel 的差异,还有后端 CORS。这篇让 AI 自己按时间顺序记录下来分别踩了哪些坑,做了哪些改动。
先看限制
Yohaku 本身的情况:Next.js 16.3.7(Turbopack 构建),pnpm 12 monorepo,还依赖 yohaku-oss 子模块。
EdgeOne Makers 跟这次相关的几条:
项目
说明
Next.js 支持
13.5 到 16,App Router、SSR、ISR、RSC、`proxy.ts` 中间件都支持
Cloud Functions
免费版代码包上限 128 MiB,运行时 Node 20
next.config
`rewrites` / `redirects` 文档写着不支持,建议改用 `edgeone.json`
我用的部署方式是 CLI:edgeone makers deploy 在本地安装依赖、构建,再由 @edgeone/opennextjs-pages 适配器把产物整理成 .edgeone/ 目录上传。目录里有三部分:assets/ 是静态资源,cloud-functions/ssr-node/ 是 SSR 函数,edge-functions/ 是编译后的 proxy.ts。
第一个小坑:新项目直接用 -e preview 部署会报 Please create a production deployment first,必须先有一次 production 部署。
141 MiB:函数包超限
monorepo、pnpm 12、子模块、Next 16 这些我原本担心的地方都没出问题,构建和上传一次就通过了。卡住的是平台检查这一步:
拆开 ssr-node 看,大头是 .next/server(约 72 MB,这部分不好动)。能砍的有这几块:
内容
大小
来源
sharp + libvips
约 19 MiB
Next 的图片优化依赖,但 EdgeOne 有自己的图片处理
`src/`、`public/`
约 12.6 MB
本不该打进服务端包
sourcemap
约 3 MB
运行时用不到
坑一:动态读文件,整个项目被追踪进包
构建日志里其实给过提示:
问题出在生成 OG 图的 og-image.server.ts。它用动态路径去读 resvg 的 wasm 和兜底字体,Turbopack 推断不出会读哪个文件,就把整个项目都追踪了进去。这两个资源本来已经通过 outputFileTracingIncludes 显式包含了,所以加一行 ignore 注释就行:
这一处修改对 Docker 部署同样有用。
坑二:outputFileTracingExcludes 排除不掉 sharp
我第一反应是在 next.config.mjs 里用 outputFileTracingExcludes 排除 sharp,结果试了两种写法都没生效。翻 Next 源码才找到原因:collectBuildTraces 只在非 Turbopack 构建时运行,Turbopack 下 next-server 的依赖追踪由原生代码生成,根本不读这个配置。
最后改成构建完再删。postbuild 跑一个脚本,只在 EdgeOne 构建时生效,从 .next/standalone 里删掉 sharp、@img/sharp-* 和 *.map。适配器是在 postbuild 之后才从 standalone 目录复制文件的,所以删掉的东西不会进函数包。
坑三:158 MiB,上一次的产物被打进来了
改完再部署,体积反而涨到 158 MiB。查下来,多出来的 26 MiB 是上一次本地构建留下的 .edgeone/ 目录。pnpm 有一个 workspace 链接 @yohaku/web -> apps/web,Next 顺着这个链接把旧产物当成依赖追踪了进去,新包里又套了一份旧包。
修法是在 prebuild 里先清掉旧的 .edgeone/cloud-functions 等目录,清理脚本里也顺手删掉 standalone 中残留的 .edgeone。.edgeone/project.json 记录了项目绑定,要保留。
坑四:环境变量传不进构建
为了不影响 Docker 构建,清理脚本一开始靠环境变量 EDGEONE_BUILD 判断要不要执行。后来发现 edgeone makers deploy 执行构建时,不会把终端里设置的环境变量传下去,所以脚本一直什么都没删。
最终改成检测适配器在构建期间写入的标记文件 .edgeone/.image-loader-injected。这样不需要任何配置,Docker 构建也不受影响。
做完这四步,函数包从 141 MiB 降到约 112 MiB,部署终于通过了。
404:"The site does not exist"
中间有一段时间,访问站点所有路径都返回 EdgeOne 网关的 404,连 favicon.ico 这种静态文件也一样,自定义域名和默认域名都是这样。我先后怀疑过 DNS 和同步延迟,最后确认原因很简单:项目还没有一次成功的生产部署(前面的体积问题),域名后面没有任何内容。所以看到网关 404 先去查部署状态,DNS 不用急着怀疑。
另外,CLI 给出的预览链接带 eo_token 参数,大约一小时后会过期,不适合反复测试。绑一个自定义域名会方便得多,海外区也不需要备案。
平台差异的适配
体积问题解决后,站点基本可用。我逐个测了路由,又改了三处:
用 GitHub Actions 自动部署
我希望 EdgeOne 相关的改动单独放在 feat/edgeone-makers 分支,不污染 main,但又要跟上 main 的更新。所以 workflow 这样设计:main 每次有 push,就把 main 合并进部署分支,推回远端,再从合并结果构建部署。
几个要注意的地方:
第一次运行就成功了:依赖安装 32 秒,整个流程大约 6 分钟,SSR 包 101.4 MiB。
小结