@timber-js/app 0.2.0-alpha.64 → 0.2.0-alpha.66
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.
- package/dist/index.js +94 -9
- package/dist/index.js.map +1 -1
- package/dist/plugins/dev-browser-logs.d.ts.map +1 -1
- package/dist/plugins/fonts.d.ts +12 -5
- package/dist/plugins/fonts.d.ts.map +1 -1
- package/dist/shims/font-google.js +42 -0
- package/dist/shims/font-google.js.map +1 -0
- package/dist/shims/font-local.js +20 -0
- package/dist/shims/font-local.js.map +1 -0
- package/package.json +7 -6
- package/src/cli.ts +0 -0
- package/src/plugins/dev-browser-logs.ts +5 -1
- package/src/plugins/fonts.ts +71 -9
- package/LICENSE +0 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev-browser-logs.d.ts","sourceRoot":"","sources":["../../src/plugins/dev-browser-logs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAiB,MAAM,MAAM,CAAC;AAClD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAIjD,6CAA6C;AAC7C,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;AAExD,kEAAkE;AAClE,MAAM,MAAM,oBAAoB,GAAG,eAAe,GAAG,MAAM,GAAG,SAAS,CAAC;AAExE;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,eAAe,CAAC;IACvB,iCAAiC;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,6DAA6D;IAC7D,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,gDAAgD;IAChD,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,qDAAqD;IACrD,SAAS,EAAE,MAAM,CAAC;CACnB;AA6BD;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,iBAAiB,GAAG,MAAM,CAsBnE;AAID;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,eAAe,EACtB,SAAS,EAAE,eAAe,GAAG,MAAM,GAClC,OAAO,CAGT;AAID;;;GAGG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAMzE;AAID;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,eAAe,GAAG,MAAM,GAAG,MAAM,CAgEhF;AAID;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"dev-browser-logs.d.ts","sourceRoot":"","sources":["../../src/plugins/dev-browser-logs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAiB,MAAM,MAAM,CAAC;AAClD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAIjD,6CAA6C;AAC7C,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;AAExD,kEAAkE;AAClE,MAAM,MAAM,oBAAoB,GAAG,eAAe,GAAG,MAAM,GAAG,SAAS,CAAC;AAExE;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,eAAe,CAAC;IACvB,iCAAiC;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,6DAA6D;IAC7D,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,gDAAgD;IAChD,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,qDAAqD;IACrD,SAAS,EAAE,MAAM,CAAC;CACnB;AA6BD;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,iBAAiB,GAAG,MAAM,CAsBnE;AAID;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,eAAe,EACtB,SAAS,EAAE,eAAe,GAAG,MAAM,GAClC,OAAO,CAGT;AAID;;;GAGG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAMzE;AAID;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,eAAe,GAAG,MAAM,GAAG,MAAM,CAgEhF;AAID;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CA6D/D"}
|
package/dist/plugins/fonts.d.ts
CHANGED
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
import type { Plugin } from 'vite';
|
|
17
17
|
import type { PluginContext } from '../index.js';
|
|
18
18
|
import type { ExtractedFont, GoogleFontConfig } from '../fonts/types.js';
|
|
19
|
+
import type { FontFaceDescriptor } from '../fonts/types.js';
|
|
19
20
|
/**
|
|
20
21
|
* Registry of fonts extracted during transform.
|
|
21
22
|
* Keyed by a unique font ID derived from family + config.
|
|
@@ -59,17 +60,23 @@ export declare function parseGoogleFontFamilies(source: string): Map<string, str
|
|
|
59
60
|
/**
|
|
60
61
|
* Generate CSS for a single extracted font.
|
|
61
62
|
*
|
|
62
|
-
* Includes @font-face rules (for local fonts), fallback @font-face,
|
|
63
|
+
* Includes @font-face rules (for local and Google fonts), fallback @font-face,
|
|
63
64
|
* and the scoped class rule.
|
|
65
|
+
*
|
|
66
|
+
* For Google fonts, pass the resolved FontFaceDescriptor[] from either
|
|
67
|
+
* `generateProductionFontFaces()` (production) or `resolveDevFontFaces()` (dev).
|
|
64
68
|
*/
|
|
65
|
-
export declare function generateFontCss(font: ExtractedFont): string;
|
|
69
|
+
export declare function generateFontCss(font: ExtractedFont, googleFaces?: FontFaceDescriptor[]): string;
|
|
66
70
|
/**
|
|
67
71
|
* Generate the CSS output for all extracted fonts.
|
|
68
72
|
*
|
|
69
|
-
* Includes @font-face rules for local fonts, fallback @font-face
|
|
70
|
-
* and scoped classes.
|
|
73
|
+
* Includes @font-face rules for local and Google fonts, fallback @font-face
|
|
74
|
+
* rules, and scoped classes.
|
|
75
|
+
*
|
|
76
|
+
* `googleFontFacesMap` provides pre-resolved FontFaceDescriptor[] for each
|
|
77
|
+
* Google font ID (keyed by ExtractedFont.id).
|
|
71
78
|
*/
|
|
72
|
-
export declare function generateAllFontCss(registry: FontRegistry): string;
|
|
79
|
+
export declare function generateAllFontCss(registry: FontRegistry, googleFontFacesMap?: Map<string, FontFaceDescriptor[]>): string;
|
|
73
80
|
/**
|
|
74
81
|
* Parse the local name used for the default import of `@timber/fonts/local`.
|
|
75
82
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fonts.d.ts","sourceRoot":"","sources":["../../src/plugins/fonts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAiB,MAAM,MAAM,CAAC;AAGlD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"fonts.d.ts","sourceRoot":"","sources":["../../src/plugins/fonts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAiB,MAAM,MAAM,CAAC;AAGlD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAYzE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AA6B5D;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;AA4CtD;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAE7E;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,IAAI,CAE5F;AAUD;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAkB/D;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAqB3E;AAwED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,aAAa,EAAE,WAAW,CAAC,EAAE,kBAAkB,EAAE,GAAG,MAAM,CAwB/F;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,YAAY,EACtB,kBAAkB,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,kBAAkB,EAAE,CAAC,GACrD,MAAM,CAOR;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAKtE;AAqED;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAqYtD"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
//#region src/shims/font-google.ts
|
|
2
|
+
/**
|
|
3
|
+
* Create a stub FontResult with empty values.
|
|
4
|
+
*
|
|
5
|
+
* The timber-fonts plugin replaces these calls at build time with real
|
|
6
|
+
* class names and font stacks. This stub ensures code that imports
|
|
7
|
+
* font functions outside of the build pipeline (tests, type-checking)
|
|
8
|
+
* gets a valid FontResult shape without runtime errors.
|
|
9
|
+
*/
|
|
10
|
+
function createStubFontResult(config) {
|
|
11
|
+
return {
|
|
12
|
+
className: "",
|
|
13
|
+
style: { fontFamily: "" },
|
|
14
|
+
variable: config?.variable
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Generic font loader — accepts any font name, returns a stub FontResult.
|
|
19
|
+
*
|
|
20
|
+
* Named exports like `Inter`, `Roboto`, etc. are generated dynamically
|
|
21
|
+
* by the virtual module at build time. This function provides a catch-all
|
|
22
|
+
* for non-Vite contexts.
|
|
23
|
+
*/
|
|
24
|
+
function createFont(_family, config) {
|
|
25
|
+
return createStubFontResult(config);
|
|
26
|
+
}
|
|
27
|
+
var Inter = (config) => createStubFontResult(config);
|
|
28
|
+
var Roboto = (config) => createStubFontResult(config);
|
|
29
|
+
var Open_Sans = (config) => createStubFontResult(config);
|
|
30
|
+
var Lato = (config) => createStubFontResult(config);
|
|
31
|
+
var Montserrat = (config) => createStubFontResult(config);
|
|
32
|
+
var Poppins = (config) => createStubFontResult(config);
|
|
33
|
+
var Geist = (config) => createStubFontResult(config);
|
|
34
|
+
var Geist_Mono = (config) => createStubFontResult(config);
|
|
35
|
+
var JetBrains_Mono = (config) => createStubFontResult(config);
|
|
36
|
+
var Source_Code_Pro = (config) => createStubFontResult(config);
|
|
37
|
+
var Playfair_Display = (config) => createStubFontResult(config);
|
|
38
|
+
var Merriweather = (config) => createStubFontResult(config);
|
|
39
|
+
//#endregion
|
|
40
|
+
export { Geist, Geist_Mono, Inter, JetBrains_Mono, Lato, Merriweather, Montserrat, Open_Sans, Playfair_Display, Poppins, Roboto, Source_Code_Pro, createFont };
|
|
41
|
+
|
|
42
|
+
//# sourceMappingURL=font-google.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"font-google.js","names":[],"sources":["../../src/shims/font-google.ts"],"sourcesContent":["/**\n * Fallback shim for `next/font/google` → `@timber/fonts/google`.\n *\n * At build time, the timber-fonts plugin's transform hook replaces font\n * function calls with static FontResult objects containing real class names\n * and font stacks. This file serves two purposes:\n *\n * 1. **TypeScript resolution** — provides types for IDEs and `tsc` outside\n * of Vite's module graph (where the virtual module handles it).\n * 2. **Runtime fallback** — returns empty className/fontFamily values when\n * the plugin hasn't processed a call (e.g. in tests or non-Vite environments).\n *\n * The shim resolution path (`next/font/google` → `\\0@timber/fonts/google`)\n * is unchanged — this file is NOT on that resolution path. It exists as a\n * physical module for direct imports and type re-exports.\n *\n * Design doc: 24-fonts.md, \"Next.js Font Compatibility\"\n */\n\nimport type { GoogleFontConfig, FontResult } from '../fonts/types.js';\n\nexport type { GoogleFontConfig, FontResult };\n\n/**\n * Create a stub FontResult with empty values.\n *\n * The timber-fonts plugin replaces these calls at build time with real\n * class names and font stacks. This stub ensures code that imports\n * font functions outside of the build pipeline (tests, type-checking)\n * gets a valid FontResult shape without runtime errors.\n */\nfunction createStubFontResult(config?: GoogleFontConfig): FontResult {\n return {\n className: '',\n style: { fontFamily: '' },\n variable: config?.variable,\n };\n}\n\n/**\n * Generic font loader — accepts any font name, returns a stub FontResult.\n *\n * Named exports like `Inter`, `Roboto`, etc. are generated dynamically\n * by the virtual module at build time. This function provides a catch-all\n * for non-Vite contexts.\n */\nexport function createFont(_family: string, config?: GoogleFontConfig): FontResult {\n return createStubFontResult(config);\n}\n\n// Common Google Font exports for TypeScript autocomplete.\n// These are stubs — the virtual module and transform hook provide real values.\nexport const Inter = (config?: GoogleFontConfig): FontResult => createStubFontResult(config);\nexport const Roboto = (config?: GoogleFontConfig): FontResult => createStubFontResult(config);\nexport const Open_Sans = (config?: GoogleFontConfig): FontResult => createStubFontResult(config);\nexport const Lato = (config?: GoogleFontConfig): FontResult => createStubFontResult(config);\nexport const Montserrat = (config?: GoogleFontConfig): FontResult => createStubFontResult(config);\nexport const Poppins = (config?: GoogleFontConfig): FontResult => createStubFontResult(config);\nexport const Geist = (config?: GoogleFontConfig): FontResult => createStubFontResult(config);\nexport const Geist_Mono = (config?: GoogleFontConfig): FontResult => createStubFontResult(config);\nexport const JetBrains_Mono = (config?: GoogleFontConfig): FontResult =>\n createStubFontResult(config);\nexport const Source_Code_Pro = (config?: GoogleFontConfig): FontResult =>\n createStubFontResult(config);\nexport const Playfair_Display = (config?: GoogleFontConfig): FontResult =>\n createStubFontResult(config);\nexport const Merriweather = (config?: GoogleFontConfig): FontResult => createStubFontResult(config);\n"],"mappings":";;;;;;;;;AA+BA,SAAS,qBAAqB,QAAuC;AACnE,QAAO;EACL,WAAW;EACX,OAAO,EAAE,YAAY,IAAI;EACzB,UAAU,QAAQ;EACnB;;;;;;;;;AAUH,SAAgB,WAAW,SAAiB,QAAuC;AACjF,QAAO,qBAAqB,OAAO;;AAKrC,IAAa,SAAS,WAA0C,qBAAqB,OAAO;AAC5F,IAAa,UAAU,WAA0C,qBAAqB,OAAO;AAC7F,IAAa,aAAa,WAA0C,qBAAqB,OAAO;AAChG,IAAa,QAAQ,WAA0C,qBAAqB,OAAO;AAC3F,IAAa,cAAc,WAA0C,qBAAqB,OAAO;AACjG,IAAa,WAAW,WAA0C,qBAAqB,OAAO;AAC9F,IAAa,SAAS,WAA0C,qBAAqB,OAAO;AAC5F,IAAa,cAAc,WAA0C,qBAAqB,OAAO;AACjG,IAAa,kBAAkB,WAC7B,qBAAqB,OAAO;AAC9B,IAAa,mBAAmB,WAC9B,qBAAqB,OAAO;AAC9B,IAAa,oBAAoB,WAC/B,qBAAqB,OAAO;AAC9B,IAAa,gBAAgB,WAA0C,qBAAqB,OAAO"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
//#region src/shims/font-local.ts
|
|
2
|
+
/**
|
|
3
|
+
* Create a local font.
|
|
4
|
+
*
|
|
5
|
+
* The timber-fonts plugin replaces these calls at build time with real
|
|
6
|
+
* class names and font stacks. This stub ensures code that imports
|
|
7
|
+
* `localFont` outside of the build pipeline (tests, type-checking)
|
|
8
|
+
* gets a valid FontResult shape without runtime errors.
|
|
9
|
+
*/
|
|
10
|
+
function localFont(config) {
|
|
11
|
+
return {
|
|
12
|
+
className: "",
|
|
13
|
+
style: { fontFamily: "" },
|
|
14
|
+
variable: config?.variable
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
//#endregion
|
|
18
|
+
export { localFont as default };
|
|
19
|
+
|
|
20
|
+
//# sourceMappingURL=font-local.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"font-local.js","names":[],"sources":["../../src/shims/font-local.ts"],"sourcesContent":["/**\n * Fallback shim for `next/font/local` → `@timber/fonts/local`.\n *\n * At build time, the timber-fonts plugin's transform hook replaces\n * `localFont()` calls with static FontResult objects containing real\n * class names and font stacks. This file serves two purposes:\n *\n * 1. **TypeScript resolution** — provides types for IDEs and `tsc` outside\n * of Vite's module graph (where the virtual module handles it).\n * 2. **Runtime fallback** — returns empty className/fontFamily values when\n * the plugin hasn't processed a call (e.g. in tests or non-Vite environments).\n *\n * Design doc: 24-fonts.md, \"Next.js Font Compatibility\"\n */\n\nimport type { LocalFontConfig, FontResult } from '../fonts/types.js';\n\nexport type { LocalFontConfig, FontResult };\n\n/**\n * Create a local font.\n *\n * The timber-fonts plugin replaces these calls at build time with real\n * class names and font stacks. This stub ensures code that imports\n * `localFont` outside of the build pipeline (tests, type-checking)\n * gets a valid FontResult shape without runtime errors.\n */\nexport default function localFont(config?: LocalFontConfig): FontResult {\n return {\n className: '',\n style: { fontFamily: '' },\n variable: config?.variable,\n };\n}\n"],"mappings":";;;;;;;;;AA2BA,SAAwB,UAAU,QAAsC;AACtE,QAAO;EACL,WAAW;EACX,OAAO,EAAE,YAAY,IAAI;EACzB,UAAU,QAAQ;EACnB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@timber-js/app",
|
|
3
|
-
"version": "0.2.0-alpha.
|
|
3
|
+
"version": "0.2.0-alpha.66",
|
|
4
4
|
"description": "Vite-native React framework built for Servers and Serverless Platforms — correct HTTP semantics, real status codes, pages that work without JavaScript",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cloudflare-workers",
|
|
@@ -88,6 +88,11 @@
|
|
|
88
88
|
"publishConfig": {
|
|
89
89
|
"access": "public"
|
|
90
90
|
},
|
|
91
|
+
"scripts": {
|
|
92
|
+
"build": "vite build --config vite.lib.config.ts && tsc --emitDeclarationOnly --project tsconfig.json --outDir dist",
|
|
93
|
+
"typecheck": "tsgo --noEmit",
|
|
94
|
+
"prepublishOnly": "pnpm run build"
|
|
95
|
+
},
|
|
91
96
|
"dependencies": {
|
|
92
97
|
"@opentelemetry/api": "^1.9.1",
|
|
93
98
|
"@opentelemetry/context-async-hooks": "^2.6.1",
|
|
@@ -126,9 +131,5 @@
|
|
|
126
131
|
},
|
|
127
132
|
"engines": {
|
|
128
133
|
"node": ">=22.12.0"
|
|
129
|
-
},
|
|
130
|
-
"scripts": {
|
|
131
|
-
"build": "vite build --config vite.lib.config.ts && tsc --emitDeclarationOnly --project tsconfig.json --outDir dist",
|
|
132
|
-
"typecheck": "tsgo --noEmit"
|
|
133
134
|
}
|
|
134
|
-
}
|
|
135
|
+
}
|
package/src/cli.ts
CHANGED
|
File without changes
|
|
@@ -231,7 +231,11 @@ export function timberDevBrowserLogs(ctx: PluginContext): Plugin {
|
|
|
231
231
|
|
|
232
232
|
configureServer(server: ViteDevServer) {
|
|
233
233
|
const threshold = ctx.config.devBrowserLogs ?? 'warn';
|
|
234
|
-
if (threshold === 'none')
|
|
234
|
+
if (threshold === 'none') {
|
|
235
|
+
// Clear any stale script from a prior server instance (e.g. HMR reconfigure)
|
|
236
|
+
delete (globalThis as Record<string, unknown>).__timber_dev_browser_log_script;
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
235
239
|
|
|
236
240
|
// Register the client injection script on globalThis so the RSC entry
|
|
237
241
|
// can include it in headHtml for all Timber route responses.
|
package/src/plugins/fonts.ts
CHANGED
|
@@ -24,7 +24,13 @@ import { generateVariableClass, generateFontFamilyClass, generateFontFaces } fro
|
|
|
24
24
|
import { generateFallbackCss, buildFontStack } from '../fonts/fallbacks.js';
|
|
25
25
|
import { processLocalFont, generateLocalFontFaces } from '../fonts/local.js';
|
|
26
26
|
import { inferFontFormat } from '../fonts/local.js';
|
|
27
|
-
import {
|
|
27
|
+
import {
|
|
28
|
+
downloadAndCacheFonts,
|
|
29
|
+
generateProductionFontFaces,
|
|
30
|
+
resolveDevFontFaces,
|
|
31
|
+
type CachedFont,
|
|
32
|
+
} from '../fonts/google.js';
|
|
33
|
+
import type { FontFaceDescriptor } from '../fonts/types.js';
|
|
28
34
|
import {
|
|
29
35
|
extractFontConfigAst,
|
|
30
36
|
extractLocalFontConfigAst,
|
|
@@ -264,10 +270,13 @@ function generateLocalVirtualModule(): string {
|
|
|
264
270
|
/**
|
|
265
271
|
* Generate CSS for a single extracted font.
|
|
266
272
|
*
|
|
267
|
-
* Includes @font-face rules (for local fonts), fallback @font-face,
|
|
273
|
+
* Includes @font-face rules (for local and Google fonts), fallback @font-face,
|
|
268
274
|
* and the scoped class rule.
|
|
275
|
+
*
|
|
276
|
+
* For Google fonts, pass the resolved FontFaceDescriptor[] from either
|
|
277
|
+
* `generateProductionFontFaces()` (production) or `resolveDevFontFaces()` (dev).
|
|
269
278
|
*/
|
|
270
|
-
export function generateFontCss(font: ExtractedFont): string {
|
|
279
|
+
export function generateFontCss(font: ExtractedFont, googleFaces?: FontFaceDescriptor[]): string {
|
|
271
280
|
const cssParts: string[] = [];
|
|
272
281
|
|
|
273
282
|
if (font.provider === 'local' && font.localSources) {
|
|
@@ -276,6 +285,11 @@ export function generateFontCss(font: ExtractedFont): string {
|
|
|
276
285
|
if (faceCss) cssParts.push(faceCss);
|
|
277
286
|
}
|
|
278
287
|
|
|
288
|
+
if (font.provider === 'google' && googleFaces && googleFaces.length > 0) {
|
|
289
|
+
const faceCss = generateFontFaces(googleFaces);
|
|
290
|
+
if (faceCss) cssParts.push(faceCss);
|
|
291
|
+
}
|
|
292
|
+
|
|
279
293
|
const fallbackCss = generateFallbackCss(font.family);
|
|
280
294
|
if (fallbackCss) cssParts.push(fallbackCss);
|
|
281
295
|
|
|
@@ -291,13 +305,20 @@ export function generateFontCss(font: ExtractedFont): string {
|
|
|
291
305
|
/**
|
|
292
306
|
* Generate the CSS output for all extracted fonts.
|
|
293
307
|
*
|
|
294
|
-
* Includes @font-face rules for local fonts, fallback @font-face
|
|
295
|
-
* and scoped classes.
|
|
308
|
+
* Includes @font-face rules for local and Google fonts, fallback @font-face
|
|
309
|
+
* rules, and scoped classes.
|
|
310
|
+
*
|
|
311
|
+
* `googleFontFacesMap` provides pre-resolved FontFaceDescriptor[] for each
|
|
312
|
+
* Google font ID (keyed by ExtractedFont.id).
|
|
296
313
|
*/
|
|
297
|
-
export function generateAllFontCss(
|
|
314
|
+
export function generateAllFontCss(
|
|
315
|
+
registry: FontRegistry,
|
|
316
|
+
googleFontFacesMap?: Map<string, FontFaceDescriptor[]>
|
|
317
|
+
): string {
|
|
298
318
|
const cssParts: string[] = [];
|
|
299
319
|
for (const font of registry.values()) {
|
|
300
|
-
|
|
320
|
+
const googleFaces = googleFontFacesMap?.get(font.id);
|
|
321
|
+
cssParts.push(generateFontCss(font, googleFaces));
|
|
301
322
|
}
|
|
302
323
|
return cssParts.join('\n\n');
|
|
303
324
|
}
|
|
@@ -390,6 +411,11 @@ export function timberFonts(ctx: PluginContext): Plugin {
|
|
|
390
411
|
const registry: FontRegistry = new Map();
|
|
391
412
|
/** Fonts downloaded during buildStart (production only). */
|
|
392
413
|
let cachedFonts: CachedFont[] = [];
|
|
414
|
+
/**
|
|
415
|
+
* Pre-resolved @font-face descriptors for Google fonts, keyed by font ID.
|
|
416
|
+
* Populated in buildStart (production) or lazily in load (dev).
|
|
417
|
+
*/
|
|
418
|
+
const googleFontFacesMap = new Map<string, FontFaceDescriptor[]>();
|
|
393
419
|
|
|
394
420
|
return {
|
|
395
421
|
name: 'timber-fonts',
|
|
@@ -429,12 +455,32 @@ export function timberFonts(ctx: PluginContext): Plugin {
|
|
|
429
455
|
* Because this is loaded lazily (on first request), the font
|
|
430
456
|
* registry is always populated by the time it's needed.
|
|
431
457
|
*/
|
|
432
|
-
load(id: string) {
|
|
458
|
+
async load(id: string) {
|
|
433
459
|
if (id === RESOLVED_GOOGLE) return generateGoogleVirtualModule(registry);
|
|
434
460
|
if (id === RESOLVED_LOCAL) return generateLocalVirtualModule();
|
|
435
461
|
|
|
436
462
|
if (id === RESOLVED_FONT_CSS_REGISTER) {
|
|
437
|
-
|
|
463
|
+
// In dev mode, resolve Google font faces from CDN on demand.
|
|
464
|
+
if (ctx.dev) {
|
|
465
|
+
const googleFonts = [...registry.values()].filter((f) => f.provider === 'google');
|
|
466
|
+
for (const font of googleFonts) {
|
|
467
|
+
if (!googleFontFacesMap.has(font.id)) {
|
|
468
|
+
try {
|
|
469
|
+
const faces = await resolveDevFontFaces(font);
|
|
470
|
+
googleFontFacesMap.set(font.id, faces);
|
|
471
|
+
} catch (e) {
|
|
472
|
+
// In dev mode, fail gracefully — fonts fall back to system fonts.
|
|
473
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
474
|
+
console.warn(
|
|
475
|
+
`[timber-fonts] Failed to resolve Google font "${font.family}": ${msg}`
|
|
476
|
+
);
|
|
477
|
+
googleFontFacesMap.set(font.id, []);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
const css = generateAllFontCss(registry, googleFontFacesMap);
|
|
438
484
|
// Side-effect module: sets font CSS on globalThis for the RSC entry to read.
|
|
439
485
|
return `globalThis.__timber_font_css = ${JSON.stringify(css)};`;
|
|
440
486
|
}
|
|
@@ -515,6 +561,22 @@ export function timberFonts(ctx: PluginContext): Plugin {
|
|
|
515
561
|
if (googleFonts.length === 0) return;
|
|
516
562
|
|
|
517
563
|
cachedFonts = await downloadAndCacheFonts(googleFonts, ctx.root);
|
|
564
|
+
|
|
565
|
+
// Build a family→CachedFont[] lookup, then generate production @font-face
|
|
566
|
+
// descriptors for each registered Google font.
|
|
567
|
+
const cachedByFamily = new Map<string, CachedFont[]>();
|
|
568
|
+
for (const cf of cachedFonts) {
|
|
569
|
+
const key = cf.face.family.toLowerCase();
|
|
570
|
+
const arr = cachedByFamily.get(key) ?? [];
|
|
571
|
+
arr.push(cf);
|
|
572
|
+
cachedByFamily.set(key, arr);
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
for (const font of googleFonts) {
|
|
576
|
+
const familyCached = cachedByFamily.get(font.family.toLowerCase()) ?? [];
|
|
577
|
+
const faces = generateProductionFontFaces(familyCached, font.display);
|
|
578
|
+
googleFontFacesMap.set(font.id, faces);
|
|
579
|
+
}
|
|
518
580
|
},
|
|
519
581
|
|
|
520
582
|
/**
|
package/LICENSE
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
DONTFUCKINGUSE LICENSE
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2025 Daniel Saewitz
|
|
4
|
-
|
|
5
|
-
This software may not be used, copied, modified, merged, published,
|
|
6
|
-
distributed, sublicensed, or sold by anyone other than the copyright holder.
|
|
7
|
-
|
|
8
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND.
|