@timber-js/app 0.2.0-alpha.6 → 0.2.0-alpha.7
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.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -6
- package/dist/index.js.map +1 -1
- package/dist/plugins/entries.d.ts.map +1 -1
- package/dist/plugins/fonts.d.ts.map +1 -1
- package/dist/server/rsc-entry/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +2 -0
- package/src/plugins/entries.ts +1 -0
- package/src/plugins/fonts.ts +24 -17
- package/src/server/rsc-entry/index.ts +7 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entries.d.ts","sourceRoot":"","sources":["../../src/plugins/entries.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAInC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"entries.d.ts","sourceRoot":"","sources":["../../src/plugins/entries.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAInC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AA8GhD;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAUrE;AAED;;;;;;;;GAQG;AACH,wBAAgB,6BAA6B,CAAC,mBAAmB,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAwBxF;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAwExD"}
|
|
@@ -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,YAAY,CAAC;AAChD,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,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,YAAY,CAAC;AAChD,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAqBxE;;;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;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,YAAY,GAAG,MAAM,CAwBjE;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,CAuUtD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/index.ts"],"names":[],"mappings":"AAgFA;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAE/F;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/index.ts"],"names":[],"mappings":"AAgFA;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAE/F;AAgaD,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAIzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;8BApQ3C,OAAO,KAAG,OAAO,CAAC,QAAQ,CAAC;AAsQhD,wBAAiE"}
|
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.7",
|
|
4
4
|
"description": "Vite-native React framework for Cloudflare Workers — correct HTTP semantics, real status codes, pages that work without JavaScript",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cloudflare-workers",
|
package/src/index.ts
CHANGED
|
@@ -223,6 +223,8 @@ export interface PluginContext {
|
|
|
223
223
|
buildManifest: BuildManifest | null;
|
|
224
224
|
/** Startup timer for profiling cold start phases (active in dev, no-op in prod) */
|
|
225
225
|
timer: StartupTimer;
|
|
226
|
+
/** URL path to font CSS file, set by timber-fonts when fonts are registered */
|
|
227
|
+
fontCssUrl?: string;
|
|
226
228
|
}
|
|
227
229
|
|
|
228
230
|
/**
|
package/src/plugins/entries.ts
CHANGED
package/src/plugins/fonts.ts
CHANGED
|
@@ -33,10 +33,11 @@ import {
|
|
|
33
33
|
|
|
34
34
|
const VIRTUAL_GOOGLE = '@timber/fonts/google';
|
|
35
35
|
const VIRTUAL_LOCAL = '@timber/fonts/local';
|
|
36
|
-
const VIRTUAL_FONT_CSS = 'virtual:timber-fonts.css';
|
|
37
36
|
const RESOLVED_GOOGLE = '\0@timber/fonts/google';
|
|
38
37
|
const RESOLVED_LOCAL = '\0@timber/fonts/local';
|
|
39
|
-
|
|
38
|
+
|
|
39
|
+
/** URL path where font CSS is served (dev middleware and prod asset). */
|
|
40
|
+
const FONT_CSS_PATH = '/_timber/fonts/fonts.css';
|
|
40
41
|
|
|
41
42
|
/**
|
|
42
43
|
* Registry of fonts extracted during transform.
|
|
@@ -371,34 +372,32 @@ export function timberFonts(ctx: PluginContext): Plugin {
|
|
|
371
372
|
name: 'timber-fonts',
|
|
372
373
|
|
|
373
374
|
/**
|
|
374
|
-
* Resolve `@timber/fonts/google
|
|
375
|
-
* virtual font CSS module to internal IDs.
|
|
375
|
+
* Resolve `@timber/fonts/google` and `@timber/fonts/local` to virtual modules.
|
|
376
376
|
*/
|
|
377
377
|
resolveId(id: string) {
|
|
378
378
|
if (id === VIRTUAL_GOOGLE) return RESOLVED_GOOGLE;
|
|
379
379
|
if (id === VIRTUAL_LOCAL) return RESOLVED_LOCAL;
|
|
380
|
-
if (id === VIRTUAL_FONT_CSS) return RESOLVED_FONT_CSS;
|
|
381
380
|
return null;
|
|
382
381
|
},
|
|
383
382
|
|
|
384
383
|
/**
|
|
385
384
|
* Return generated source for font virtual modules.
|
|
386
|
-
*
|
|
387
|
-
* The font CSS virtual module returns the combined @font-face rules,
|
|
388
|
-
* fallback CSS, and scoped classes for all registered fonts.
|
|
389
385
|
*/
|
|
390
386
|
load(id: string) {
|
|
391
387
|
if (id === RESOLVED_GOOGLE) return generateGoogleVirtualModule(registry);
|
|
392
388
|
if (id === RESOLVED_LOCAL) return generateLocalVirtualModule();
|
|
393
|
-
if (id === RESOLVED_FONT_CSS) return generateAllFontCss(registry);
|
|
394
389
|
return null;
|
|
395
390
|
},
|
|
396
391
|
|
|
397
392
|
/**
|
|
398
|
-
* Serve local font files in dev mode under `/_timber/fonts/`.
|
|
393
|
+
* Serve local font files and font CSS in dev mode under `/_timber/fonts/`.
|
|
399
394
|
*
|
|
400
|
-
*
|
|
401
|
-
*
|
|
395
|
+
* Serves:
|
|
396
|
+
* - `/_timber/fonts/fonts.css` — combined @font-face + scoped class CSS
|
|
397
|
+
* - `/_timber/fonts/<filename>` — individual font files from the registry
|
|
398
|
+
*
|
|
399
|
+
* Only files registered in the font registry are served.
|
|
400
|
+
* Paths are validated to prevent directory traversal.
|
|
402
401
|
*/
|
|
403
402
|
configureServer(server: ViteDevServer) {
|
|
404
403
|
server.middlewares.use((req, res, next) => {
|
|
@@ -413,6 +412,15 @@ export function timberFonts(ctx: PluginContext): Plugin {
|
|
|
413
412
|
return;
|
|
414
413
|
}
|
|
415
414
|
|
|
415
|
+
// Serve generated font CSS
|
|
416
|
+
if (requestedFilename === 'fonts.css') {
|
|
417
|
+
const css = generateAllFontCss(registry);
|
|
418
|
+
res.setHeader('Content-Type', 'text/css');
|
|
419
|
+
res.setHeader('Cache-Control', 'no-cache');
|
|
420
|
+
res.end(css);
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
|
|
416
424
|
// Find the matching font file in the registry
|
|
417
425
|
for (const font of registry.values()) {
|
|
418
426
|
if (font.provider !== 'local' || !font.localSources) continue;
|
|
@@ -420,7 +428,6 @@ export function timberFonts(ctx: PluginContext): Plugin {
|
|
|
420
428
|
const basename = src.path.split('/').pop() ?? '';
|
|
421
429
|
if (basename === requestedFilename) {
|
|
422
430
|
const absolutePath = normalize(resolve(src.path));
|
|
423
|
-
// Verify the resolved path hasn't escaped (extra safety)
|
|
424
431
|
if (!existsSync(absolutePath)) {
|
|
425
432
|
res.statusCode = 404;
|
|
426
433
|
res.end('Not found');
|
|
@@ -571,10 +578,10 @@ export function timberFonts(ctx: PluginContext): Plugin {
|
|
|
571
578
|
}
|
|
572
579
|
|
|
573
580
|
if (transformedCode !== code) {
|
|
574
|
-
//
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
581
|
+
// Mark that fonts are in use so the RSC entry injects a <link> tag.
|
|
582
|
+
if (registry.size > 0 && !ctx.fontCssUrl) {
|
|
583
|
+
ctx.fontCssUrl = FONT_CSS_PATH;
|
|
584
|
+
}
|
|
578
585
|
return { code: transformedCode, map: null };
|
|
579
586
|
}
|
|
580
587
|
|
|
@@ -385,6 +385,13 @@ async function renderRoute(
|
|
|
385
385
|
headHtml += buildCssLinkTags(cssUrls);
|
|
386
386
|
}
|
|
387
387
|
|
|
388
|
+
// Inject font CSS stylesheet — pure CSS, no JS needed.
|
|
389
|
+
// The URL is set by the timber-fonts plugin when fonts are registered.
|
|
390
|
+
const fontCssUrl = (config as { fontCssUrl?: string | null }).fontCssUrl;
|
|
391
|
+
if (fontCssUrl) {
|
|
392
|
+
headHtml += `<link rel="stylesheet" href="${fontCssUrl}">`;
|
|
393
|
+
}
|
|
394
|
+
|
|
388
395
|
const fontEntries = collectRouteFonts(segments, typedManifest);
|
|
389
396
|
if (fontEntries.length > 0) {
|
|
390
397
|
headHtml += buildFontPreloadTags(fontEntries);
|