Files
Reactive-Resume/apps/server/tsdown.config.ts
T
Amruth Pillai c0bf1aebaf feat(pdf): remove react-pdf and move every consumer to forme
The web preview, downloads, template gallery, server export and public
PDF render through Forme. react-pdf, react-pdf-html, the react-pdf
hyphenation package, the Phosphor react-pdf icons and the four patches
are gone. Hyphenation now follows the page language for every language
Forme has patterns for.

Semantic CSS keeps its language; declarations Forme can't draw raise an
ENGINE_UNSUPPORTED warning in the editor. The page map rebuilds blocks
Forme leaves out of its layout when they break across pages, and a
render that misplaces a box is repeated with nested rows kept whole.

Tests move to a small shim with the react-pdf calls they were written
against; tests of react-pdf internals are dropped. Forme limits are
recorded as expected failures (RTL line order, characters above
U+FFFF).
2026-09-29 07:11:40 +02:00

86 lines
2.6 KiB
TypeScript

import type { TsdownPlugin } from "tsdown";
import { readdirSync, readFileSync } from "node:fs";
import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import { defineConfig } from "tsdown";
const rootPackageJson = JSON.parse(readFileSync(new URL("../../package.json", import.meta.url), "utf-8")) as {
version?: string;
};
// Lambda disables require(ESM) and uses stricter CJS export detection than standalone Node.
const bundledInteropPackages = new Set([
"@uiw/color-convert",
"@babel/runtime",
"sanitize-html",
"htmlparser2",
"domhandler",
"domutils",
"domelementtype",
"dom-serializer",
"entities",
"deepmerge",
"escape-string-regexp",
"is-plain-object",
"parse-srcset",
"postcss",
"nanoid",
"picocolors",
"source-map-js",
"launder",
"dayjs",
]);
const shouldExternalizeThirdParty = (id: string) => {
const packageName = id
.split("/")
.slice(0, id.startsWith("@") ? 2 : 1)
.join("/");
if (id.startsWith("@reactive-resume/") || bundledInteropPackages.has(packageName)) return false;
// Subpath imports (`#…`) are resolved by the workspace package that declares them, so they're bundled with it.
if (id.startsWith("@/") || id.startsWith("#") || id.startsWith(".") || id.startsWith("/") || id.startsWith("\0"))
return false;
return true;
};
const aiPromptsDir = resolve(dirname(fileURLToPath(import.meta.url)), "../../packages/ai/src/prompts");
const promptAssetsPlugin: TsdownPlugin = {
name: "prompt-assets",
buildStart() {
for (const filename of readdirSync(aiPromptsDir)) {
if (!filename.endsWith(".md")) continue;
this.emitFile({
type: "asset",
fileName: `prompts/${filename}`,
source: readFileSync(resolve(aiPromptsDir, filename), "utf-8"),
});
}
},
};
export default defineConfig({
entry: { index: "src/index.ts", vercel: "src/vercel.ts", "prepare-deployment": "src/prepare-deployment.ts" },
// Keep import.meta.url-based asset lookup adjacent to the entrypoints.
outputOptions: { chunkFileNames: "[name]-[hash].mjs" },
format: "esm",
platform: "node",
target: "node24",
outDir: "dist",
clean: true,
shims: true,
dts: false,
define: { __APP_VERSION__: JSON.stringify(rootPackageJson.version ?? "0.0.0") },
// The flagged dynamic imports are deliberate: they defer evaluation of env-dependent
// modules so tests can run without env vars, not to split chunks.
suppressWarnings: [/dynamic import will not move module into another chunk/],
outExtensions: () => ({ js: ".mjs" }),
deps: {
alwaysBundle: [/^@reactive-resume\//, ...bundledInteropPackages],
neverBundle: shouldExternalizeThirdParty,
},
plugins: [promptAssetsPlugin],
});