Browser model dependencies and SSR packaging
2026-09-25 — Cause and scope
A local Netlify upload returned HTTP 400: “The function exceeds the maximum size of 250 MB.” The Tier 1 text encoder is browser-only, but its dynamic imports of Transformers and ONNX remained in compiled server output. Local Netlify dependency tracing included Transformers' native Node runtime: macOS, Windows and Linux ONNX binaries, plus Sharp. Lazy browser loading does not itself exclude a dependency from a serverless package.
The fix adds a build-time import.meta.env.SSR guard before the encoder's imports.
Vite removes the unreachable server dependency graph. Browser loading is unchanged.
pnpm build now checks compiled server import/export/require statements for
browser-model dependencies; checker regressions run in CI. Missing or empty
server artifacts fail the check rather than silently passing.
Equivalent local comparison
Isolated worktrees used Node 24.10.0, the manifest-pinned pnpm 10.33.0, Netlify CLI
26.0.2 on macOS arm64, identical pinned submodules and frozen dependency installs.
Each ran netlify build --context branch-deploy against the same staging site.
| Source | ZIP bytes | Unpacked bytes | ONNX native bytes |
|---|---|---|---|
Production base dd2f72b6 | 111,399,011 | 285,838,807 | 217,912,684 |
History change 152d8e5e | 111,402,418 | 285,851,749 | 217,912,684 |
| SSR guard | 11,548,700 | 35,337,155 | 0 |
The two failing artifacts both contained 1,016 files. Large entries included
onnxruntime-node/bin/napi-v3/darwin/x64/libonnxruntime.1.21.0.dylib, its arm64
variant, Linux libonnxruntime.so.1 and .so.1.21.0 copies, Windows DLLs and
@img/sharp-libvips-darwin-arm64. The identical native payload on the production
base establishes that this was not introduced by the Notes animation change.
Hosted Netlify function metadata reported 12,137,528 bytes for production base and 12,140,705 for the history staging build. The hosted path did not exhibit corresponding growth. Local and hosted packaging paths differ; these observations do not establish a regression across every operating system or bundler version.
Validation and deployment evidence
TypeScript and 2,398 component/unit tests passed (five skipped). Two checker tests cover static, dynamic and CommonJS imports, ignored comments/string labels, nested files, and absent/empty artifacts. The check rejects the actual prior SSR output and accepts the fixed build.
The corrected macOS artifact uploaded successfully as Netlify draft
6ab6d0978a010d55c7a15c39 at
the SSR verification preview.
Requests to /, /geyang/notes, /geyang/artifacts and /products/search returned
HTTP 200. The artifact route exercises the separately preserved DreamDB runtime
and WASM dependency. This is upload/SSR evidence, not authenticated Notes acceptance.
The shared staging deployment containing unrelated breadcrumb work was preserved.
App PR 450 tracks CI, merge and production promotion separately.
Separate browser loading policy
Dataset semantic search starts its dedicated worker only after the user enables
it. The worker's static Transformers import is already behind that worker boundary.
The search landing page instead invokes warmTier1 after mount, skipping Save-Data
and slow connections. Its requestIdleCallback timeout of 15,000 ms is a maximum
wait, not a minimum delay; the fallback is 200 ms. It loads vector chunks before
the encoder and caches model bytes in IndexedDB.
A production browser observation without a click recorded the Tier 1 manifest
request at 364.7 ms after navigation (HTTP 200, cached). The runtime attempted ONNX
session creation automatically. No cold-model download timing is claimed because
model data was already cached. An existing SimplifiedLayerNormFusion model/runtime
compatibility warning was observed and reported separately; this packaging change
does not change prewarming policy or model compatibility.
2026-09-25 — Production release
PR #450 merged at
b3211944676d6859dd22e234e19f88e94442a942 after all CI checks passed.
The combined history/activity/packaging tree (368dbe65) passed 2,402 local tests,
TypeScript, build and the SSR boundary check, and matched the hosted staging tree.
Netlify production deploy 6ab6d54a2ecf420008bff7a0 is ready with an 11,828,565-byte
SSR function. Homepage, Notes, artifacts and search routes returned HTTP 200.
The verified local package measured 35,337,155 bytes unpacked and 11,548,700 bytes
compressed. Local upload, hosted build and production checks are separate evidence;
none changes the browser model-loading policy described above.