flake.nix only rewrote @/ aliases but left extensionless relative imports (./router) in compiled dist/. node dist/index.js (how prod runs) cannot resolve extensionless ESM specifiers -> ERR_MODULE_NOT_FOUND -> backend crashlooped (444 restarts, port 4001 dead). Extract the fixer into a shared scripts/fix-imports.mjs that appends .js to extensionless relative imports and rewrites @/ aliases, and wire it into backend + discord-gateway build phases. Verified: fresh tsc + fixer -> node dist/index.js boots; oRPC over /trpc serves both HTTP POST and WebSocket (config/dashboard/voice/moderation/ media/chatbot/analysis) end-to-end against Postgres + Redis. next build passes with the oRPC client + partysocket.
50 lines
1.9 KiB
JavaScript
50 lines
1.9 KiB
JavaScript
// Rewrite import specifiers in the compiled dist/ so the output runs under
|
|
// plain `node dist/index.js` (native ESM, no bundler / no tsx).
|
|
//
|
|
// Background: tsconfig uses moduleResolution:"bundler", so `tsc` emits BARE
|
|
// relative specifiers WITHOUT extensions (e.g. `import "./router"`) and leaves
|
|
// the `@/*` path-alias imports untouched. Node's native ESM resolver rejects
|
|
// extensionless relative specifiers and knows nothing about the `@/` alias, so
|
|
// the emitted dist/ crashes at startup (`ERR_MODULE_NOT_FOUND`). This script
|
|
// fixes both:
|
|
// 1. `@/foo` -> relative path to dist/foo.js
|
|
// 2. `./foo` / `../foo` -> `./foo.js` / `../foo.js` (append .js)
|
|
// Already-extensioned relative imports (.js/.json/.node/.mjs/.cjs) and bare
|
|
// package specifiers are left untouched (idempotent).
|
|
import { readFileSync, writeFileSync, existsSync, readdirSync } from "node:fs";
|
|
import { join, relative, dirname } from "node:path";
|
|
|
|
let count = 0;
|
|
function walk(dir) {
|
|
if (!existsSync(dir)) return;
|
|
for (const e of readdirSync(dir, { withFileTypes: true })) {
|
|
const p = join(dir, e.name);
|
|
if (e.isDirectory()) walk(p);
|
|
else if (e.name.endsWith(".js")) {
|
|
const c = readFileSync(p, "utf8");
|
|
const pat = /from\s+['"]([^'"]+)['"]/g;
|
|
const n = c.replace(pat, (m, spec) => {
|
|
if (spec.startsWith("@/")) {
|
|
const target = join("dist", spec.slice(2)) + ".js";
|
|
let rel = relative(dirname(p), target);
|
|
if (!rel.startsWith(".")) rel = "./" + rel;
|
|
return `from "${rel}"`;
|
|
}
|
|
if (
|
|
(spec.startsWith("./") || spec.startsWith("../")) &&
|
|
!/\.(js|json|node|mjs|cjs)$/.test(spec)
|
|
) {
|
|
return `from "${spec}.js"`;
|
|
}
|
|
return m;
|
|
});
|
|
if (n !== c) {
|
|
writeFileSync(p, n);
|
|
count++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
walk("dist");
|
|
console.log(`Fixed ${count} import specifiers in dist/`);
|