collab: replace createRequire shim with normal imports

The collab server was using createRequire() with hardcoded relative paths
(../../../packages/database/package.json, ../node_modules/@hocuspocus/server/...)
to grab `eq` from drizzle-orm and `Forbidden` from @hocuspocus/common. That
worked under tsx in dev but fell apart in the bundled prod image because
those paths don't exist there and pnpm's symlink topology in the runtime
node_modules wasn't reachable from inside the bundled dist file.

Result at runtime: Cannot find module '@hocuspocus/common' on every
collab restart, infinite crash loop.

Switch both to plain ESM imports — tsup bundles them into dist/index.mjs
directly, no runtime resolution needed. Add @hocuspocus/common and
drizzle-orm as explicit deps so they're properly tracked.

Verified locally: bundle now resolves cleanly with no createRequire calls
(actually shrinks from 304 KB to 102 KB after dead-code elimination).

Made-with: Cursor
This commit is contained in:
Randall Stillwell 2026-04-28 15:14:03 -05:00
parent 3856d11944
commit b992db5b3e
3 changed files with 11 additions and 24 deletions

View file

@ -9,10 +9,12 @@
"type-check": "tsc --noEmit"
},
"dependencies": {
"@hocuspocus/server": "^2.15.0",
"@hocuspocus/common": "^2.15.0",
"@hocuspocus/extension-database": "^2.15.0",
"@hocuspocus/extension-redis": "^2.15.0",
"@hocuspocus/server": "^2.15.0",
"@tasks/database": "workspace:*",
"drizzle-orm": "^0.38.0",
"ioredis": "^5.4.2",
"yjs": "^13.6.22",
"zod": "^3.24.0"

View file

@ -1,12 +1,11 @@
import { createRequire } from "node:module";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";
import { createHash } from "node:crypto";
import { Forbidden } from "@hocuspocus/common";
import { Database } from "@hocuspocus/extension-database";
import { Redis as HocuspocusRedis } from "@hocuspocus/extension-redis";
import { Hocuspocus, type Extension, type onAuthenticatePayload } from "@hocuspocus/server";
import { db } from "@tasks/database/client";
import { objects } from "@tasks/database/schema";
import { eq } from "drizzle-orm";
import IoRedis from "ioredis";
import { z } from "zod";
import {
@ -15,26 +14,6 @@ import {
yDocToBase64,
} from "./utils.js";
/**
* Resolve transitive deps (drizzle-orm, @hocuspocus/common) without listing them in this package.
* Uses workspace package roots so `createRequire` works under `tsx` (no `import.meta.resolve`).
*/
const __dirname = dirname(fileURLToPath(import.meta.url));
const requireFromDb = createRequire(
join(__dirname, "../../../packages/database/package.json"),
);
const requireFromServer = createRequire(
join(__dirname, "../node_modules/@hocuspocus/server/package.json"),
);
// Resolved at runtime via @tasks/database's dependency graph (see `requireFromDb` above).
const { eq } = requireFromDb("drizzle-orm") as {
eq: (...args: unknown[]) => any;
};
const { Forbidden } = requireFromServer("@hocuspocus/common") as {
Forbidden: { code: number; reason: string };
};
const contentSchema = z
.object({
yjs: z.string().optional(),

View file

@ -20,6 +20,9 @@ importers:
apps/collab-server:
dependencies:
'@hocuspocus/common':
specifier: ^2.15.0
version: 2.15.3
'@hocuspocus/extension-database':
specifier: ^2.15.0
version: 2.15.3(y-protocols@1.0.7(yjs@13.6.30))(yjs@13.6.30)
@ -32,6 +35,9 @@ importers:
'@tasks/database':
specifier: workspace:*
version: link:../../packages/database
drizzle-orm:
specifier: ^0.38.0
version: 0.38.4(@opentelemetry/api@1.9.0)(@types/react@19.2.14)(postgres@3.4.8)(react@19.2.4)
ioredis:
specifier: ^5.4.2
version: 5.10.1