fix(build): copy schema.json to dist and externalize zod (#534)

Two packaging bugs:

1. The './schema.json' export pointed to dist/src/generated/schema.json
   but nothing copied it there (tsc is emitDeclarationOnly, Bun.build
   doesn't emit JSON). Consumers got ERR_MODULE_NOT_FOUND.
   Fix: cpSync after tsc runs.

2. zod is a peerDependency but was bundled into every entry point
   (~270KB each). This causes dual-instance bugs where consumer-side
   'instanceof ZodError' and schema.extend() break across boundaries.
   Fix: add zod to external list for all non-with-deps entries.

Bundle size impact:
  app.js          293952 -> 24561  (-91.6%)
  app-bridge.js   299517 -> 30112  (-89.9%)
  react/index.js  295558 -> 26153  (-91.2%)
  server/index.js 291500 -> 22135  (-92.4%)
  app-with-deps   321814 -> 321814 (unchanged, intentional)
This commit is contained in:
Olivier Chafik 2026-03-06 17:13:48 +00:00 • committed by GitHub
commit 79744afd41
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1,9 +1,15 @@
#!/usr/bin/env bun
import { $ } from "bun";
import { cpSync, mkdirSync } from "node:fs";
// Run TypeScript compiler for type declarations
await $`tsc`;
// Copy schema.json (tsc is emitDeclarationOnly, Bun.build doesn't emit JSON assets).
// Needed for the "./schema.json" package export.
mkdirSync("dist/src/generated", { recursive: true });
cpSync("src/generated/schema.json", "dist/src/generated/schema.json");
const isDevelopment = Bun.env.NODE_ENV === "development";
// Build all JavaScript/TypeScript files
@ -25,10 +31,14 @@ function buildJs(
});
}
// zod is a peerDependency — keep it external so consumers share a single
// zod instance (instanceof ZodError / schema.extend() break with duplicate copies).
const PEER_EXTERNALS = ["@modelcontextprotocol/sdk", "zod"];
await Promise.all([
buildJs("src/app.ts", {
outdir: "dist/src",
external: ["@modelcontextprotocol/sdk"],
external: PEER_EXTERNALS,
}),
buildJs("src/app.ts", {
outdir: "dist/src",
@ -36,19 +46,19 @@ await Promise.all([
}),
buildJs("src/app-bridge.ts", {
outdir: "dist/src",
external: ["@modelcontextprotocol/sdk"],
external: PEER_EXTERNALS,
}),
buildJs("src/react/index.tsx", {
outdir: "dist/src/react",
external: ["react", "react-dom", "@modelcontextprotocol/sdk"],
external: ["react", "react-dom", ...PEER_EXTERNALS],
}),
buildJs("src/react/index.tsx", {
outdir: "dist/src/react",
external: ["react", "react-dom", "@modelcontextprotocol/sdk"],
external: ["react", "react-dom", ...PEER_EXTERNALS],
naming: { entry: "react-with-deps.js" },
}),
buildJs("src/server/index.ts", {
outdir: "dist/src/server",
external: ["@modelcontextprotocol/sdk"],
external: PEER_EXTERNALS,
}),
]);