Files
Matt Kane 18593475bb perf: hydrate taxonomy terms on collection and entry queries (#626)
* chore: bump TS target from ES2022 to ES2024

Unlocks ES2023 Array methods (toSorted, toReversed, toSpliced, findLast)
and ES2024 types (Promise.withResolvers, Object.groupBy) in type
checks. Node 22 already supports these at runtime; the old target just
made the types invisible.

* perf: hydrate taxonomy terms on collection and entry queries

Adds eager hydration of taxonomy terms on getEmDashCollection and
getEmDashEntry results via a single batched JOIN query. Each entry
now exposes data.terms keyed by taxonomy name alongside the existing
bylines hydration. Templates that previously looped and called
getEntryTerms per entry can drop the N+1.

Measured on blog-demo home page (7 posts, 2 taxonomies), warm render:
  use: 443ms -> 317ms  (-28%)
  euw: 274ms -> 178ms  (-35%)
  ape: 682ms -> 413ms  (-40%)
  aps: 1008ms -> 156ms (-85%)

The aps figure reflects the dominant cost of serial D1 round-trips
across a replica link: eliminating 6 of them dwarfs every other
homepage query put together.

New exports: getAllTermsForEntries, invalidateTermCache. A cached
hasAnyTermAssignments probe short-circuits the JOIN entirely on sites
that use no taxonomies; the cache is invalidated when term
assignments are written.

Reserved field slugs now also block terms, bylines, and byline so
new user fields cannot shadow the auto-hydrated values.

* chore(blog-demo): add account_id to wrangler.jsonc

Unblocks wrangler deploy in multi-account environments without
requiring CLOUDFLARE_ACCOUNT_ID in the shell. The EmDash CMS account
ID is non-secret.

* fix: harden hydration probes (per-DB cache, rethrow, chunk IN, cross-dialect)

Addresses review feedback on the taxonomy hydration PR. Applies the
same fixes to the pre-existing byline hydration, which had identical
shortcomings.

- Per-DB cache via WeakMap<Kysely<Database>, boolean>. The probe result
  ("does any row exist in _emdash_bylines / content_taxonomies?") used
  to live at module scope, which meant preview sessions, D1 Sessions
  API replicas, and Durable Object playground databases could see
  cached values from an unrelated DB instance.
- Rethrow non-table-missing errors from the probe. The old code
  swallowed every error and returned false, silently hiding real DB
  failures (permissions, connectivity, syntax).
- Chunk IN (...) clauses with SQL_BATCH_SIZE so large collection
  queries can't exceed D1's bound-parameter limit. Matches the
  existing getContentBylinesMany pattern.
- Cross-dialect missing-table detection via a new
  utils/db-errors.ts#isMissingTableError helper that matches SQLite,
  PostgreSQL, and MySQL phrasings. Wired into loader.ts (replacing
  three inline duplicates), query.ts hydrators, and both probes.

All 2393 core tests pass, including 7 new ones covering the helper
and the batched multi-taxonomy fetcher.
2026-04-17 12:34:00 +01:00

20 lines
426 B
JSON

{
"compilerOptions": {
"target": "ES2024",
"module": "preserve",
"lib": ["ES2024"],
"moduleResolution": "bundler",
"resolveJsonModule": true,
"allowJs": false,
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"noUncheckedIndexedAccess": true,
"noImplicitOverride": true
}
}