@timber-js/app 0.2.0-alpha.95 → 0.2.0-alpha.96

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/LICENSE +8 -0
  2. package/dist/_chunks/{interception-DSv3A2Zn.js → interception-BsLCA9gk.js} +4 -4
  3. package/dist/_chunks/interception-BsLCA9gk.js.map +1 -0
  4. package/dist/_chunks/{ssr-data-DzuI0bIV.js → router-ref-C8OCm7g7.js} +26 -2
  5. package/dist/_chunks/router-ref-C8OCm7g7.js.map +1 -0
  6. package/dist/_chunks/{use-params-Br9YSUFV.js → use-params-IOPu7E8t.js} +3 -27
  7. package/dist/_chunks/use-params-IOPu7E8t.js.map +1 -0
  8. package/dist/client/browser-dev.d.ts +7 -0
  9. package/dist/client/browser-dev.d.ts.map +1 -1
  10. package/dist/client/error-boundary.d.ts.map +1 -1
  11. package/dist/client/error-boundary.js +16 -2
  12. package/dist/client/error-boundary.js.map +1 -1
  13. package/dist/client/index.js +2 -2
  14. package/dist/client/internal.js +2 -2
  15. package/dist/fonts/pipeline.d.ts +29 -0
  16. package/dist/fonts/pipeline.d.ts.map +1 -1
  17. package/dist/fonts/transform.d.ts +0 -8
  18. package/dist/fonts/transform.d.ts.map +1 -1
  19. package/dist/fonts/virtual-modules.d.ts +49 -5
  20. package/dist/fonts/virtual-modules.d.ts.map +1 -1
  21. package/dist/index.js +229 -89
  22. package/dist/index.js.map +1 -1
  23. package/dist/plugins/fonts.d.ts.map +1 -1
  24. package/dist/plugins/mdx.d.ts.map +1 -1
  25. package/dist/routing/index.js +1 -1
  26. package/dist/routing/link-codegen.d.ts.map +1 -1
  27. package/dist/server/internal.js +2 -2
  28. package/dist/server/internal.js.map +1 -1
  29. package/dist/server/pipeline.d.ts +10 -1
  30. package/dist/server/pipeline.d.ts.map +1 -1
  31. package/dist/server/rsc-entry/index.d.ts.map +1 -1
  32. package/package.json +6 -7
  33. package/src/cli.ts +0 -0
  34. package/src/client/browser-dev.ts +25 -0
  35. package/src/client/error-boundary.tsx +49 -4
  36. package/src/fonts/pipeline.ts +39 -0
  37. package/src/fonts/transform.ts +61 -8
  38. package/src/fonts/virtual-modules.ts +73 -5
  39. package/src/plugins/fonts.ts +49 -14
  40. package/src/plugins/mdx.ts +42 -9
  41. package/src/routing/link-codegen.ts +29 -9
  42. package/src/server/pipeline.ts +12 -3
  43. package/src/server/rsc-entry/index.ts +54 -21
  44. package/dist/_chunks/interception-DSv3A2Zn.js.map +0 -1
  45. package/dist/_chunks/ssr-data-DzuI0bIV.js.map +0 -1
  46. package/dist/_chunks/use-params-Br9YSUFV.js.map +0 -1
@@ -1,8 +1,8 @@
1
1
  import { t as bindUseQueryStates } from "../_chunks/use-query-states-BiV5GJgm.js";
2
- import { n as getSsrData, r as setSsrData, t as clearSsrData } from "../_chunks/ssr-data-DzuI0bIV.js";
2
+ import { a as getSsrData, i as clearSsrData, n as getRouterOrNull, o as setSsrData, r as setGlobalRouter, t as getRouter } from "../_chunks/router-ref-C8OCm7g7.js";
3
3
  import { TimberErrorBoundary } from "./error-boundary.js";
4
4
  import { n as useSegmentContext, t as SegmentProvider } from "../_chunks/segment-context-fHFLF1PE.js";
5
- import { a as getNavigationState, f as getRouter, i as NavigationProvider, m as setGlobalRouter, o as setNavigationState, p as getRouterOrNull, r as setHardNavigating, t as setCurrentParams } from "../_chunks/use-params-Br9YSUFV.js";
5
+ import { a as getNavigationState, i as NavigationProvider, o as setNavigationState, r as setHardNavigating, t as setCurrentParams } from "../_chunks/use-params-IOPu7E8t.js";
6
6
  import { cloneElement, isValidElement } from "react";
7
7
  //#region src/client/segment-cache.ts
8
8
  /**
@@ -27,6 +27,7 @@
27
27
  */
28
28
  import type { ExtractedFont, FontEntry, FontFaceDescriptor } from './types.js';
29
29
  import type { CachedFont } from './google.js';
30
+ import { VirtualFontCssIdMap } from './virtual-modules.js';
30
31
  /**
31
32
  * Backwards-compatible alias for the registry shape that the standalone
32
33
  * `pruneRegistryEntries` and `generateAllFontCss` helpers operate on.
@@ -48,6 +49,17 @@ export declare class FontPipeline {
48
49
  * the map contents are mutable through the methods below.
49
50
  */
50
51
  private readonly _entries;
52
+ /**
53
+ * Per-importer virtual CSS module id registry. Populated by the
54
+ * transform hook when it inlines a font function call, read by the
55
+ * plugin's `load` hook when Vite asks for the module's CSS source.
56
+ *
57
+ * Lives on the pipeline (rather than a module-level singleton) so
58
+ * multiple parallel plugin instances — e.g. in the test suite — cannot
59
+ * collide on the hash-to-importer map. Also makes `clear()` reset the
60
+ * id map alongside the font entries so test fixtures start clean.
61
+ */
62
+ readonly cssIdMap: VirtualFontCssIdMap;
51
63
  /** Number of registered fonts. */
52
64
  size(): number;
53
65
  /** Iterate every entry as a `FontEntry` (with `faces` / `cachedFiles`). */
@@ -124,6 +136,23 @@ export declare class FontPipeline {
124
136
  * or lazily in `load` for dev).
125
137
  */
126
138
  getCss(): string;
139
+ /**
140
+ * Render the combined CSS for every font registered from a specific
141
+ * importer file. This is the anchor point for the per-importer virtual
142
+ * CSS module (`virtual:timber-font-css/<hash>.css`) that the transform
143
+ * hook injects as a side-effect import.
144
+ *
145
+ * Scoping by importer means two concurrent requests rendering different
146
+ * routes cannot see each other's font CSS: each importer's virtual
147
+ * module only contains CSS for fonts that module registered. It also
148
+ * means Vite's CSS HMR can surgically reload just the affected importer
149
+ * when a single file changes, rather than rebuilding one giant blob.
150
+ *
151
+ * Returns an empty string when no fonts are registered under `importer`.
152
+ * The empty string is semantically equivalent to "no CSS" — Vite's CSS
153
+ * pipeline handles it as a valid empty CSS module.
154
+ */
155
+ getCssForSegment(importer: string): string;
127
156
  }
128
157
  /**
129
158
  * Drop every registry entry that originated from `importer` and shares
@@ -1 +1 @@
1
- {"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../src/fonts/pipeline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAC/E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAK9C;;;;;;;;;GASG;AACH,MAAM,MAAM,YAAY,GAAG,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;AAEtD,qBAAa,YAAY;IACvB;;;;;;;OAOG;IACH,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgC;IAIzD,kCAAkC;IAClC,IAAI,IAAI,MAAM;IAId,2EAA2E;IAC3E,OAAO,IAAI,gBAAgB,CAAC,SAAS,CAAC;IAItC,uEAAuE;IACvE,KAAK,IAAI,gBAAgB,CAAC,aAAa,CAAC;IAIxC,2CAA2C;IAC1C,WAAW,IAAI,gBAAgB,CAAC,SAAS,CAAC;IAM3C,kCAAkC;IAClC,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS;IAI3C;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAKjC;;;;;OAKG;IACH,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAOvC;;;;;;;;OAQG;IACH,QAAQ,CAAC,SAAS,EAAE,aAAa,GAAG,IAAI;IAOxC,oEAAoE;IACpE,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,kBAAkB,EAAE,GAAG,IAAI;IAW9D,8DAA8D;IAC9D,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,IAAI;IAW5D;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAShD,mEAAmE;IACnE,KAAK,IAAI,IAAI;IAMb;;;;;OAKG;IACF,iBAAiB,IAAI,gBAAgB,CAAC,UAAU,CAAC;IAYlD;;;;;;;OAOG;IACH,MAAM,IAAI,MAAM;CAOjB;AAoCD;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,YAAY,EACtB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GACb,IAAI,CAON"}
1
+ {"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../src/fonts/pipeline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAC/E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAI9C,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAE3D;;;;;;;;;GASG;AACH,MAAM,MAAM,YAAY,GAAG,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;AAEtD,qBAAa,YAAY;IACvB;;;;;;;OAOG;IACH,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgC;IAEzD;;;;;;;;;OASG;IACH,QAAQ,CAAC,QAAQ,sBAA6B;IAI9C,kCAAkC;IAClC,IAAI,IAAI,MAAM;IAId,2EAA2E;IAC3E,OAAO,IAAI,gBAAgB,CAAC,SAAS,CAAC;IAItC,uEAAuE;IACvE,KAAK,IAAI,gBAAgB,CAAC,aAAa,CAAC;IAIxC,2CAA2C;IAC1C,WAAW,IAAI,gBAAgB,CAAC,SAAS,CAAC;IAM3C,kCAAkC;IAClC,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS;IAI3C;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAKjC;;;;;OAKG;IACH,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAOvC;;;;;;;;OAQG;IACH,QAAQ,CAAC,SAAS,EAAE,aAAa,GAAG,IAAI;IAOxC,oEAAoE;IACpE,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,kBAAkB,EAAE,GAAG,IAAI;IAW9D,8DAA8D;IAC9D,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,IAAI;IAW5D;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAShD,mEAAmE;IACnE,KAAK,IAAI,IAAI;IAOb;;;;;OAKG;IACF,iBAAiB,IAAI,gBAAgB,CAAC,UAAU,CAAC;IAYlD;;;;;;;OAOG;IACH,MAAM,IAAI,MAAM;IAQhB;;;;;;;;;;;;;;;OAeG;IACH,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;CAQ3C;AAoCD;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,YAAY,EACtB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GACb,IAAI,CAON"}
@@ -56,14 +56,6 @@ export declare function parseGoogleFontFamilies(source: string): Map<string, str
56
56
  export declare function parseLocalFontImportName(source: string): string | null;
57
57
  /** Type for the Vite plugin's `this.error` callback. */
58
58
  type EmitError = (msg: string) => never;
59
- /**
60
- * Run the timber-fonts transform pass on a single source file.
61
- *
62
- * Returns the rewritten code (with font calls inlined and the side-effect
63
- * `virtual:timber-font-css-register` import prepended) or `null` if the
64
- * file does not import from any timber-fonts virtual module and therefore
65
- * needs no transformation.
66
- */
67
59
  export declare function runFontsTransform(code: string, id: string, pipeline: FontPipeline, emitError: EmitError): {
68
60
  code: string;
69
61
  map: null;
@@ -1 +1 @@
1
- {"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../../src/fonts/transform.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAiB,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAQlE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAgClD;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,gBAAgB,GAAG,MAAM,CAM/E;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAE7E;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,IAAI,CAE5F;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAkB/D;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAqB3E;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAKtE;AASD,wDAAwD;AACxD,KAAK,SAAS,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,KAAK,CAAC;AA8IxC;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,YAAY,EACtB,SAAS,EAAE,SAAS,GACnB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,IAAI,CAAA;CAAE,GAAG,IAAI,CAkCpC"}
1
+ {"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../../src/fonts/transform.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAiB,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAQlE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AA+BlD;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,gBAAgB,GAAG,MAAM,CAM/E;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAE7E;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,IAAI,CAE5F;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAkB/D;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAqB3E;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAKtE;AASD,wDAAwD;AACxD,KAAK,SAAS,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,KAAK,CAAC;AAyLxC,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,YAAY,EACtB,SAAS,EAAE,SAAS,GACnB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,IAAI,CAAA;CAAE,GAAG,IAAI,CAqDpC"}
@@ -9,9 +9,22 @@
9
9
  * transform hook hasn't run yet, or when an unknown font is referenced
10
10
  * via the default export proxy).
11
11
  * - `@timber/fonts/local` — exports `localFont()` as a fallback default.
12
- * - `virtual:timber-font-css-register` — side-effect module that sets the
13
- * combined `@font-face` CSS on `globalThis.__timber_font_css`. The RSC
14
- * entry reads this at render time to inline a `<style>` tag.
12
+ * - `virtual:timber-font-css/<hash>.css` — per-importer CSS module that
13
+ * holds the combined `@font-face` + fallback + class CSS for every
14
+ * font registered under that importer. The transform hook injects a
15
+ * side-effect `import 'virtual:timber-font-css/<hash>.css'` into each
16
+ * file that calls a font function, so Vite's CSS pipeline picks it up
17
+ * like any other CSS asset. @vitejs/plugin-rsc's `collectCss` walks
18
+ * the RSC module graph, finds the virtual module, and injects a
19
+ * `<link rel="stylesheet" data-rsc-css-href=...>` via React Float —
20
+ * the same machinery component CSS rides on (TIM-828).
21
+ *
22
+ * The `.css` suffix is load-bearing: Vite's `isCSSRequest` regex matches
23
+ * on file extension, so keeping it in the virtual id is how we tell
24
+ * Vite's CSS pipeline (dev HMR + build asset emission) that this
25
+ * module is CSS. The old `virtual:timber-font-css-register` side-effect
26
+ * module, `globalThis.__timber_font_css` channel, and inline `<style>`
27
+ * tag in the RSC entry were all removed in TIM-828.
15
28
  *
16
29
  * Design doc: 24-fonts.md
17
30
  */
@@ -20,8 +33,39 @@ export declare const VIRTUAL_GOOGLE = "@timber/fonts/google";
20
33
  export declare const VIRTUAL_LOCAL = "@timber/fonts/local";
21
34
  export declare const RESOLVED_GOOGLE = "\0@timber/fonts/google";
22
35
  export declare const RESOLVED_LOCAL = "\0@timber/fonts/local";
23
- export declare const VIRTUAL_FONT_CSS_REGISTER = "virtual:timber-font-css-register";
24
- export declare const RESOLVED_FONT_CSS_REGISTER = "\0virtual:timber-font-css-register";
36
+ /**
37
+ * Prefix used for the per-importer virtual CSS modules. The full id is
38
+ * `virtual:timber-font-css/<hash>.css` where `<hash>` is a short SHA-256
39
+ * digest of the importer path. We encode the hash (not the path itself)
40
+ * so the id stays filesystem-safe and opaque to downstream consumers.
41
+ */
42
+ export declare const VIRTUAL_FONT_CSS_PREFIX = "virtual:timber-font-css/";
43
+ export declare const VIRTUAL_FONT_CSS_SUFFIX = ".css";
44
+ export declare const RESOLVED_FONT_CSS_PREFIX: string;
45
+ /**
46
+ * In-memory map from the short hash used in virtual module ids back to
47
+ * the absolute importer path. Populated by `virtualFontCssIdFor()` when
48
+ * the transform hook registers an importer and read by the plugin's
49
+ * `load` hook when Vite asks for the CSS content.
50
+ *
51
+ * Scoped to a single `FontPipeline` instance to avoid cross-plugin-
52
+ * instance collisions during multi-build pipelines.
53
+ */
54
+ export declare class VirtualFontCssIdMap {
55
+ private readonly map;
56
+ /**
57
+ * Return a stable virtual module id for `importer`. Calling this twice
58
+ * with the same importer returns the same id. Registering under an
59
+ * existing hash is idempotent.
60
+ */
61
+ idFor(importer: string): string;
62
+ /** Decode the importer from a resolved (or unresolved) virtual css id. */
63
+ importerFor(id: string): string | undefined;
64
+ /** True if `id` is any form of the virtual font css module. */
65
+ matches(id: string): boolean;
66
+ /** Drop every registered mapping. Used by tests. */
67
+ clear(): void;
68
+ }
25
69
  /**
26
70
  * Generate the virtual module source for `@timber/fonts/google`.
27
71
  *
@@ -1 +1 @@
1
- {"version":3,"file":"virtual-modules.d.ts","sourceRoot":"","sources":["../../src/fonts/virtual-modules.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAKpE,eAAO,MAAM,cAAc,yBAAyB,CAAC;AACrD,eAAO,MAAM,aAAa,wBAAwB,CAAC;AACnD,eAAO,MAAM,eAAe,2BAA2B,CAAC;AACxD,eAAO,MAAM,cAAc,0BAA0B,CAAC;AAEtD,eAAO,MAAM,yBAAyB,qCAAqC,CAAC;AAC5E,eAAO,MAAM,0BAA0B,uCAAuC,CAAC;AAU/E;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,QAAQ,CAAC,aAAa,CAAC,GAAG,MAAM,CAoClF;AAED;;;;;;GAMG;AACH,wBAAgB,0BAA0B,IAAI,MAAM,CAanD;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,aAAa,EAAE,WAAW,CAAC,EAAE,kBAAkB,EAAE,GAAG,MAAM,CAwB/F;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,EACpC,kBAAkB,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,kBAAkB,EAAE,CAAC,GACrD,MAAM,CAOR"}
1
+ {"version":3,"file":"virtual-modules.d.ts","sourceRoot":"","sources":["../../src/fonts/virtual-modules.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAKpE,eAAO,MAAM,cAAc,yBAAyB,CAAC;AACrD,eAAO,MAAM,aAAa,wBAAwB,CAAC;AACnD,eAAO,MAAM,eAAe,2BAA2B,CAAC;AACxD,eAAO,MAAM,cAAc,0BAA0B,CAAC;AAEtD;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,6BAA6B,CAAC;AAClE,eAAO,MAAM,uBAAuB,SAAS,CAAC;AAC9C,eAAO,MAAM,wBAAwB,QAAiC,CAAC;AAEvE;;;;;;;;GAQG;AACH,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAA6B;IAEjD;;;;OAIG;IACH,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAM/B,0EAA0E;IAC1E,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAW3C,+DAA+D;IAC/D,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAK5B,oDAAoD;IACpD,KAAK,IAAI,IAAI;CAGd;AAUD;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,QAAQ,CAAC,aAAa,CAAC,GAAG,MAAM,CAoClF;AAED;;;;;;GAMG;AACH,wBAAgB,0BAA0B,IAAI,MAAM,CAanD;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,aAAa,EAAE,WAAW,CAAC,EAAE,kBAAkB,EAAE,GAAG,MAAM,CAwB/F;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,EACpC,kBAAkB,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,kBAAkB,EAAE,CAAC,GACrD,MAAM,CAOR"}
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { a as __toCommonJS, i as __require, n as __esmMin, o as __toESM, r as __exportAll, t as __commonJSMin } from "./_chunks/chunk-BYIpzuS7.js";
2
2
  import { n as setViteServer } from "./_chunks/dev-warnings-DpGRGoDi.js";
3
- import { i as scanRoutes, n as generateRouteMap, t as collectInterceptionRewrites } from "./_chunks/interception-DSv3A2Zn.js";
3
+ import { i as scanRoutes, n as generateRouteMap, t as collectInterceptionRewrites } from "./_chunks/interception-BsLCA9gk.js";
4
4
  import { t as formatSize } from "./_chunks/format-CYBGxKtc.js";
5
5
  import { dirname, extname, join, normalize, resolve } from "node:path";
6
6
  import { createRequire } from "node:module";
@@ -1814,15 +1814,37 @@ function shouldActivate(ctx) {
1814
1814
  return false;
1815
1815
  }
1816
1816
  /**
1817
- * Try to dynamically import a module by name. Returns the default export
1818
- * or the module itself, or undefined if the module is not installed.
1817
+ * Try to dynamically import a module by name, resolving from the user's
1818
+ * project root rather than from `@timber-js/app`'s own location.
1819
+ *
1820
+ * Why this matters: pnpm only hoists declared (peer) dependencies into a
1821
+ * package's resolution scope. The MDX integration's optional companions
1822
+ * — `remark-frontmatter`, `remark-mdx-frontmatter`, `@mdx-js/rollup` — are
1823
+ * installed as direct deps of the consumer (e.g. `packages/website`), not
1824
+ * `@timber-js/app`. A bare `import('remark-frontmatter')` from inside this
1825
+ * file resolves against `packages/timber-app/node_modules` and silently
1826
+ * fails with `ERR_MODULE_NOT_FOUND`, which made `tryImport` return
1827
+ * `undefined` and skipped frontmatter parsing entirely — leaving MDX to
1828
+ * choke on YAML as JS expressions (TIM-840).
1829
+ *
1830
+ * Resolving relative to `projectRoot` (via `createRequire`) makes the
1831
+ * lookup walk the consumer's `node_modules` tree first, which is where
1832
+ * pnpm puts the user's deps.
1833
+ *
1834
+ * Returns the default export, the module itself, or undefined if the
1835
+ * module is not installed.
1819
1836
  */
1820
- async function tryImport(name) {
1837
+ async function tryImport(name, projectRoot) {
1821
1838
  try {
1822
- const mod = await import(name);
1839
+ const mod = await import(pathToFileURL(createRequire(join(projectRoot, "package.json")).resolve(name)).href);
1823
1840
  return mod.default ?? mod;
1824
1841
  } catch {
1825
- return;
1842
+ try {
1843
+ const mod = await import(name);
1844
+ return mod.default ?? mod;
1845
+ } catch {
1846
+ return;
1847
+ }
1826
1848
  }
1827
1849
  }
1828
1850
  /**
@@ -1837,7 +1859,7 @@ function timberMdx(ctx) {
1837
1859
  let innerPlugin = null;
1838
1860
  async function activate() {
1839
1861
  if (innerPlugin !== null || !shouldActivate(ctx)) return;
1840
- const createMdxPlugin = await tryImport("@mdx-js/rollup");
1862
+ const createMdxPlugin = await tryImport("@mdx-js/rollup", ctx.root);
1841
1863
  if (!createMdxPlugin) throw new Error([
1842
1864
  "[timber] MDX is enabled but @mdx-js/rollup is not installed.",
1843
1865
  "",
@@ -1848,8 +1870,8 @@ function timberMdx(ctx) {
1848
1870
  ].join("\n"));
1849
1871
  const mdxConfig = ctx.config.mdx ?? {};
1850
1872
  const remarkPlugins = [];
1851
- const remarkFrontmatter = await tryImport("remark-frontmatter");
1852
- const remarkMdxFrontmatter = await tryImport("remark-mdx-frontmatter");
1873
+ const remarkFrontmatter = await tryImport("remark-frontmatter", ctx.root);
1874
+ const remarkMdxFrontmatter = await tryImport("remark-mdx-frontmatter", ctx.root);
1853
1875
  if (remarkFrontmatter) remarkPlugins.push(remarkFrontmatter);
1854
1876
  if (remarkMdxFrontmatter) remarkPlugins.push(remarkMdxFrontmatter);
1855
1877
  if (mdxConfig.remarkPlugins) remarkPlugins.push(...mdxConfig.remarkPlugins);
@@ -14446,6 +14468,124 @@ function processLocalFont(config, importerPath) {
14446
14468
  fontFamily: fontStack
14447
14469
  };
14448
14470
  }
14471
+ var RESOLVED_GOOGLE = "\0@timber/fonts/google";
14472
+ var RESOLVED_LOCAL = "\0@timber/fonts/local";
14473
+ /**
14474
+ * Prefix used for the per-importer virtual CSS modules. The full id is
14475
+ * `virtual:timber-font-css/<hash>.css` where `<hash>` is a short SHA-256
14476
+ * digest of the importer path. We encode the hash (not the path itself)
14477
+ * so the id stays filesystem-safe and opaque to downstream consumers.
14478
+ */
14479
+ var VIRTUAL_FONT_CSS_PREFIX = "virtual:timber-font-css/";
14480
+ var VIRTUAL_FONT_CSS_SUFFIX = ".css";
14481
+ "" + VIRTUAL_FONT_CSS_PREFIX;
14482
+ /**
14483
+ * In-memory map from the short hash used in virtual module ids back to
14484
+ * the absolute importer path. Populated by `virtualFontCssIdFor()` when
14485
+ * the transform hook registers an importer and read by the plugin's
14486
+ * `load` hook when Vite asks for the CSS content.
14487
+ *
14488
+ * Scoped to a single `FontPipeline` instance to avoid cross-plugin-
14489
+ * instance collisions during multi-build pipelines.
14490
+ */
14491
+ var VirtualFontCssIdMap = class {
14492
+ map = /* @__PURE__ */ new Map();
14493
+ /**
14494
+ * Return a stable virtual module id for `importer`. Calling this twice
14495
+ * with the same importer returns the same id. Registering under an
14496
+ * existing hash is idempotent.
14497
+ */
14498
+ idFor(importer) {
14499
+ const hash = createHash("sha256").update(importer).digest("hex").slice(0, 16);
14500
+ this.map.set(hash, importer);
14501
+ return `${VIRTUAL_FONT_CSS_PREFIX}${hash}${VIRTUAL_FONT_CSS_SUFFIX}`;
14502
+ }
14503
+ /** Decode the importer from a resolved (or unresolved) virtual css id. */
14504
+ importerFor(id) {
14505
+ const body = id.startsWith("\0") ? id.slice(1) : id;
14506
+ if (!body.startsWith("virtual:timber-font-css/")) return void 0;
14507
+ if (!body.endsWith(".css")) return void 0;
14508
+ const hash = body.slice(24, body.length - 4);
14509
+ return this.map.get(hash);
14510
+ }
14511
+ /** True if `id` is any form of the virtual font css module. */
14512
+ matches(id) {
14513
+ const body = id.startsWith("\0") ? id.slice(1) : id;
14514
+ return body.startsWith("virtual:timber-font-css/") && body.endsWith(".css");
14515
+ }
14516
+ /** Drop every registered mapping. Used by tests. */
14517
+ clear() {
14518
+ this.map.clear();
14519
+ }
14520
+ };
14521
+ /**
14522
+ * Convert a font family name to a PascalCase export name.
14523
+ * e.g. "JetBrains Mono" → "JetBrains_Mono"
14524
+ */
14525
+ function familyToExportName(family) {
14526
+ return family.replace(/\s+/g, "_");
14527
+ }
14528
+ /**
14529
+ * Generate the virtual module source for `@timber/fonts/google`.
14530
+ *
14531
+ * The transform hook replaces real call sites at build time, so this
14532
+ * module only matters as a runtime fallback. We export a Proxy default
14533
+ * that handles any font name plus named exports for known families
14534
+ * (for tree-shaking).
14535
+ */
14536
+ function generateGoogleVirtualModule(fonts) {
14537
+ const families = /* @__PURE__ */ new Set();
14538
+ for (const font of fonts) if (font.provider === "google") families.add(font.family);
14539
+ const lines = [
14540
+ "// Auto-generated virtual module: @timber/fonts/google",
14541
+ "// Each export is a font loader function that returns a FontResult.",
14542
+ "",
14543
+ "function createFontResult(family, config) {",
14544
+ " return {",
14545
+ " className: `timber-font-${family.toLowerCase().replace(/\\s+/g, \"-\")}`,",
14546
+ " style: { fontFamily: family },",
14547
+ " variable: config?.variable,",
14548
+ " };",
14549
+ "}",
14550
+ "",
14551
+ "export default new Proxy({}, {",
14552
+ " get(_, prop) {",
14553
+ " if (typeof prop === \"string\") {",
14554
+ " return (config) => createFontResult(prop.replace(/_/g, \" \"), config);",
14555
+ " }",
14556
+ " }",
14557
+ "});"
14558
+ ];
14559
+ for (const family of families) {
14560
+ const exportName = familyToExportName(family);
14561
+ lines.push("");
14562
+ lines.push(`export function ${exportName}(config) {`);
14563
+ lines.push(` return createFontResult('${family}', config);`);
14564
+ lines.push("}");
14565
+ }
14566
+ return lines.join("\n");
14567
+ }
14568
+ /**
14569
+ * Generate the virtual module source for `@timber/fonts/local`.
14570
+ *
14571
+ * Like the google virtual module, this is a runtime fallback. The
14572
+ * transform hook normally replaces `localFont(...)` calls with static
14573
+ * `FontResult` objects at build time.
14574
+ */
14575
+ function generateLocalVirtualModule() {
14576
+ return [
14577
+ "// Auto-generated virtual module: @timber/fonts/local",
14578
+ "",
14579
+ "export default function localFont(config) {",
14580
+ " const family = config?.family || \"Local Font\";",
14581
+ " return {",
14582
+ " className: `timber-font-${family.toLowerCase().replace(/\\s+/g, \"-\")}`,",
14583
+ " style: { fontFamily: family },",
14584
+ " variable: config?.variable,",
14585
+ " };",
14586
+ "}"
14587
+ ].join("\n");
14588
+ }
14449
14589
  //#endregion
14450
14590
  //#region src/fonts/pipeline.ts
14451
14591
  var FontPipeline = class {
@@ -14458,6 +14598,17 @@ var FontPipeline = class {
14458
14598
  * the map contents are mutable through the methods below.
14459
14599
  */
14460
14600
  _entries = /* @__PURE__ */ new Map();
14601
+ /**
14602
+ * Per-importer virtual CSS module id registry. Populated by the
14603
+ * transform hook when it inlines a font function call, read by the
14604
+ * plugin's `load` hook when Vite asks for the module's CSS source.
14605
+ *
14606
+ * Lives on the pipeline (rather than a module-level singleton) so
14607
+ * multiple parallel plugin instances — e.g. in the test suite — cannot
14608
+ * collide on the hash-to-importer map. Also makes `clear()` reset the
14609
+ * id map alongside the font entries so test fixtures start clean.
14610
+ */
14611
+ cssIdMap = new VirtualFontCssIdMap();
14461
14612
  /** Number of registered fonts. */
14462
14613
  size() {
14463
14614
  return this._entries.size;
@@ -14546,6 +14697,7 @@ var FontPipeline = class {
14546
14697
  /** Drop every registered font. Used by tests and rebuild flows. */
14547
14698
  clear() {
14548
14699
  this._entries.clear();
14700
+ this.cssIdMap.clear();
14549
14701
  }
14550
14702
  /**
14551
14703
  * Iterate every cached Google Font binary across all registered entries,
@@ -14577,6 +14729,30 @@ var FontPipeline = class {
14577
14729
  for (const entry of this._entries.values()) cssParts.push(renderEntryCss(entry));
14578
14730
  return cssParts.join("\n\n");
14579
14731
  }
14732
+ /**
14733
+ * Render the combined CSS for every font registered from a specific
14734
+ * importer file. This is the anchor point for the per-importer virtual
14735
+ * CSS module (`virtual:timber-font-css/<hash>.css`) that the transform
14736
+ * hook injects as a side-effect import.
14737
+ *
14738
+ * Scoping by importer means two concurrent requests rendering different
14739
+ * routes cannot see each other's font CSS: each importer's virtual
14740
+ * module only contains CSS for fonts that module registered. It also
14741
+ * means Vite's CSS HMR can surgically reload just the affected importer
14742
+ * when a single file changes, rather than rebuilding one giant blob.
14743
+ *
14744
+ * Returns an empty string when no fonts are registered under `importer`.
14745
+ * The empty string is semantically equivalent to "no CSS" — Vite's CSS
14746
+ * pipeline handles it as a valid empty CSS module.
14747
+ */
14748
+ getCssForSegment(importer) {
14749
+ const cssParts = [];
14750
+ for (const entry of this._entries.values()) {
14751
+ if (entry.importer !== importer) continue;
14752
+ cssParts.push(renderEntryCss(entry));
14753
+ }
14754
+ return cssParts.join("\n\n");
14755
+ }
14580
14756
  };
14581
14757
  /**
14582
14758
  * Render the combined CSS for a single font entry.
@@ -14602,78 +14778,6 @@ function renderEntryCss(entry) {
14602
14778
  else cssParts.push(generateFontFamilyClass(entry.className, entry.fontFamily));
14603
14779
  return cssParts.join("\n\n");
14604
14780
  }
14605
- var RESOLVED_GOOGLE = "\0@timber/fonts/google";
14606
- var RESOLVED_LOCAL = "\0@timber/fonts/local";
14607
- var VIRTUAL_FONT_CSS_REGISTER = "virtual:timber-font-css-register";
14608
- var RESOLVED_FONT_CSS_REGISTER = "\0virtual:timber-font-css-register";
14609
- /**
14610
- * Convert a font family name to a PascalCase export name.
14611
- * e.g. "JetBrains Mono" → "JetBrains_Mono"
14612
- */
14613
- function familyToExportName(family) {
14614
- return family.replace(/\s+/g, "_");
14615
- }
14616
- /**
14617
- * Generate the virtual module source for `@timber/fonts/google`.
14618
- *
14619
- * The transform hook replaces real call sites at build time, so this
14620
- * module only matters as a runtime fallback. We export a Proxy default
14621
- * that handles any font name plus named exports for known families
14622
- * (for tree-shaking).
14623
- */
14624
- function generateGoogleVirtualModule(fonts) {
14625
- const families = /* @__PURE__ */ new Set();
14626
- for (const font of fonts) if (font.provider === "google") families.add(font.family);
14627
- const lines = [
14628
- "// Auto-generated virtual module: @timber/fonts/google",
14629
- "// Each export is a font loader function that returns a FontResult.",
14630
- "",
14631
- "function createFontResult(family, config) {",
14632
- " return {",
14633
- " className: `timber-font-${family.toLowerCase().replace(/\\s+/g, \"-\")}`,",
14634
- " style: { fontFamily: family },",
14635
- " variable: config?.variable,",
14636
- " };",
14637
- "}",
14638
- "",
14639
- "export default new Proxy({}, {",
14640
- " get(_, prop) {",
14641
- " if (typeof prop === \"string\") {",
14642
- " return (config) => createFontResult(prop.replace(/_/g, \" \"), config);",
14643
- " }",
14644
- " }",
14645
- "});"
14646
- ];
14647
- for (const family of families) {
14648
- const exportName = familyToExportName(family);
14649
- lines.push("");
14650
- lines.push(`export function ${exportName}(config) {`);
14651
- lines.push(` return createFontResult('${family}', config);`);
14652
- lines.push("}");
14653
- }
14654
- return lines.join("\n");
14655
- }
14656
- /**
14657
- * Generate the virtual module source for `@timber/fonts/local`.
14658
- *
14659
- * Like the google virtual module, this is a runtime fallback. The
14660
- * transform hook normally replaces `localFont(...)` calls with static
14661
- * `FontResult` objects at build time.
14662
- */
14663
- function generateLocalVirtualModule() {
14664
- return [
14665
- "// Auto-generated virtual module: @timber/fonts/local",
14666
- "",
14667
- "export default function localFont(config) {",
14668
- " const family = config?.family || \"Local Font\";",
14669
- " return {",
14670
- " className: `timber-font-${family.toLowerCase().replace(/\\s+/g, \"-\")}`,",
14671
- " style: { fontFamily: family },",
14672
- " variable: config?.variable,",
14673
- " };",
14674
- "}"
14675
- ].join("\n");
14676
- }
14677
14781
  //#endregion
14678
14782
  //#region src/fonts/transform.ts
14679
14783
  /**
@@ -14842,13 +14946,45 @@ function transformLocalFonts(transformedCode, originalCode, importerId, pipeline
14842
14946
  /**
14843
14947
  * Run the timber-fonts transform pass on a single source file.
14844
14948
  *
14845
- * Returns the rewritten code (with font calls inlined and the side-effect
14846
- * `virtual:timber-font-css-register` import prepended) or `null` if the
14847
- * file does not import from any timber-fonts virtual module and therefore
14848
- * needs no transformation.
14949
+ * Returns the rewritten code (with font calls inlined and a side-effect
14950
+ * `import 'virtual:timber-font-css/<hash>.css'` prepended so Vite's CSS
14951
+ * pipeline owns the font CSS) or `null` if the file does not import from
14952
+ * any timber-fonts virtual module and therefore needs no transformation.
14849
14953
  */
14954
+ /**
14955
+ * File extensions that may contain real font imports. Only JS/TS module
14956
+ * variants are scanned. Excluding non-JS extensions (.mdx, .md, .css,
14957
+ * .json, etc.) prevents false-positive matches on text that mentions a
14958
+ * font specifier inside documentation, code fences, or asset metadata.
14959
+ *
14960
+ * Why this matters: the heuristic below is a substring check (`code.includes`),
14961
+ * not an AST parse. An MDX file documenting Next.js font compatibility
14962
+ * (e.g. a code fence containing `import { Inter } from 'next/font/google'`)
14963
+ * would trigger the same match as a real import. The transform then prepends
14964
+ * `import 'virtual:timber-font-css/<hash>.css';` to the file, which breaks
14965
+ * downstream parsers that require the file to start with their own delimiter
14966
+ * — most notably MDX frontmatter, which must start at line 1 col 1 for
14967
+ * `remark-frontmatter` to recognise it. See TIM-840.
14968
+ */
14969
+ var FONT_IMPORT_SCANNABLE_EXTENSIONS = new Set([
14970
+ ".js",
14971
+ ".jsx",
14972
+ ".ts",
14973
+ ".tsx",
14974
+ ".mjs",
14975
+ ".cjs",
14976
+ ".mts",
14977
+ ".cts"
14978
+ ]);
14979
+ function hasScannableExtension(id) {
14980
+ const path = id.split("?", 1)[0];
14981
+ const dot = path.lastIndexOf(".");
14982
+ if (dot === -1) return false;
14983
+ return FONT_IMPORT_SCANNABLE_EXTENSIONS.has(path.slice(dot).toLowerCase());
14984
+ }
14850
14985
  function runFontsTransform(code, id, pipeline, emitError) {
14851
14986
  if (id.startsWith("\0") || id.includes("node_modules")) return null;
14987
+ if (!hasScannableExtension(id)) return null;
14852
14988
  const hasGoogleImport = code.includes("@timber/fonts/google") || code.includes("@timber-js/app/fonts/google") || code.includes("next/font/google");
14853
14989
  const hasLocalImport = code.includes("@timber/fonts/local") || code.includes("@timber-js/app/fonts/local") || code.includes("next/font/local");
14854
14990
  if (!hasGoogleImport && !hasLocalImport) return null;
@@ -14856,7 +14992,7 @@ function runFontsTransform(code, id, pipeline, emitError) {
14856
14992
  if (hasGoogleImport) transformedCode = transformGoogleFonts(transformedCode, code, id, pipeline, emitError);
14857
14993
  if (hasLocalImport) transformedCode = transformLocalFonts(transformedCode, code, id, pipeline, emitError);
14858
14994
  if (transformedCode !== code) {
14859
- if (pipeline.size() > 0) transformedCode = `import '${VIRTUAL_FONT_CSS_REGISTER}';\n` + transformedCode;
14995
+ if (pipeline.size() > 0) transformedCode = `import '${pipeline.cssIdMap.idFor(id)}';\n` + transformedCode;
14860
14996
  return {
14861
14997
  code: transformedCode,
14862
14998
  map: null
@@ -15010,6 +15146,7 @@ function timberFonts(ctx) {
15010
15146
  const pipeline = new FontPipeline();
15011
15147
  return {
15012
15148
  name: "timber-fonts",
15149
+ enforce: "pre",
15013
15150
  resolveId(id) {
15014
15151
  let cleanId = id.startsWith("\0") ? id.slice(1) : id;
15015
15152
  if (cleanId.startsWith(ctx.root)) {
@@ -15019,14 +15156,17 @@ function timberFonts(ctx) {
15019
15156
  }
15020
15157
  if (cleanId === "@timber/fonts/google") return RESOLVED_GOOGLE;
15021
15158
  if (cleanId === "@timber/fonts/local") return RESOLVED_LOCAL;
15022
- if (cleanId === "virtual:timber-font-css-register") return RESOLVED_FONT_CSS_REGISTER;
15159
+ if (pipeline.cssIdMap.matches(cleanId)) return "\0" + cleanId;
15023
15160
  return null;
15024
15161
  },
15025
15162
  async load(id) {
15026
15163
  if (id === "\0@timber/fonts/google") return generateGoogleVirtualModule(pipeline.fonts());
15027
15164
  if (id === "\0@timber/fonts/local") return generateLocalVirtualModule();
15028
- if (id === "\0virtual:timber-font-css-register") {
15165
+ if (pipeline.cssIdMap.matches(id)) {
15166
+ const importer = pipeline.cssIdMap.importerFor(id);
15167
+ if (!importer) return "";
15029
15168
  if (ctx.dev) for (const font of pipeline.googleFonts()) {
15169
+ if (font.importer !== importer) continue;
15030
15170
  if (pipeline.hasFaces(font.id)) continue;
15031
15171
  try {
15032
15172
  const faces = await resolveDevFontFaces(font);
@@ -15036,7 +15176,7 @@ function timberFonts(ctx) {
15036
15176
  console.warn(`[timber-fonts] Failed to resolve Google font "${font.family}": ${msg}. Will retry on next request.`);
15037
15177
  }
15038
15178
  }
15039
- return `globalThis.__timber_font_css = ${JSON.stringify(pipeline.getCss())};`;
15179
+ return pipeline.getCssForSegment(importer);
15040
15180
  }
15041
15181
  return null;
15042
15182
  },