ed96d36b54
Validate e-invoices / mustang (push) Successful in 23s
fonts.ts resolved the vendored Liberation Sans .ttf files via
`new URL('./assets/fonts/...', import.meta.url).pathname` — Next.js's
Turbopack/webpack bundler statically rewrites exactly that expression
into its own hashed static-asset system. Harmless in the frontend's own
build, but the Payload backend is also a Next.js app consuming this
package as a node_modules git dependency, where the hash referenced in
the compiled server code didn't match what was actually emitted to disk
— every invoice/correction-invoice admin download failed with
ENOENT: .../LiberationSans-Regular.<hash>.ttf. Not a cache issue,
reproduced identically after a from-scratch --no-cache rebuild. Fixed by
resolving the path via fileURLToPath(import.meta.url) + path.join
instead, which Turbopack does not special-case.
41 lines
2.2 KiB
TypeScript
41 lines
2.2 KiB
TypeScript
import { Font } from "@react-pdf/renderer";
|
|
import { fileURLToPath } from "node:url";
|
|
import { dirname, join } from "node:path";
|
|
|
|
// Registered once here (not inline in invoicePdf.tsx/correctionInvoicePdf.tsx)
|
|
// and imported by both for its side effect — avoids double-registering the
|
|
// same family when renderEInvoice.ts imports both PDF modules in the same
|
|
// process.
|
|
//
|
|
// Liberation Sans, not built-in Helvetica: PDF/A-3 (required by the
|
|
// Factur-X/ZUGFeRD pipeline in src/einvoice/) has no exemption for the
|
|
// standard/base-14 fonts react-pdf ships — every font actually used must be
|
|
// embedded, and react-pdf only embeds fonts it has real font-file bytes for
|
|
// via Font.register. Liberation Sans is metrically identical to Helvetica/
|
|
// Arial (SIL Open Font License, see src/assets/fonts/LICENSE-OFL.txt), so
|
|
// embedding it doesn't shift any existing layout.
|
|
//
|
|
// Path built via fileURLToPath+join, NOT `new URL('./file', import.meta.url)`
|
|
// — that literal pattern is exactly what Next.js's Turbopack/webpack bundler
|
|
// statically detects and rewrites into its own hashed static-asset system
|
|
// (`.next/server/assets/<hash>.ttf`). When this package is consumed as a
|
|
// node_modules git dependency inside a Next.js/Payload server build, that
|
|
// rewritten hash ended up not matching the file Turbopack actually emitted,
|
|
// so every PDF render at runtime failed with `ENOENT: .../LiberationSans-
|
|
// Regular.<hash>.ttf` — reproduced even with a from-scratch `--no-cache`
|
|
// rebuild, so it wasn't a stale-cache issue, the asset-hashing itself was
|
|
// wrong for this consumption path. This file only runs server-side (a PDF
|
|
// renderer has no reason to ever reach a client bundle) and Turbopack does
|
|
// not apply the same special-cased URL rewriting to a plain
|
|
// fileURLToPath/path.join construction, so this sidesteps the bug entirely
|
|
// while still resolving to the correct absolute path at runtime.
|
|
const fontsDir = join(dirname(fileURLToPath(import.meta.url)), "assets/fonts");
|
|
|
|
Font.register({
|
|
family: "Liberation Sans",
|
|
fonts: [
|
|
{ src: join(fontsDir, "LiberationSans-Regular.ttf"), fontWeight: "normal" },
|
|
{ src: join(fontsDir, "LiberationSans-Bold.ttf"), fontWeight: "bold" },
|
|
],
|
|
});
|