@timber-js/app 0.2.0-alpha.149 → 0.2.0-alpha.150
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.map +1 -1
- package/dist/index.js +23 -23
- package/dist/index.js.map +1 -1
- package/dist/plugins/fonts.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +9 -3
- package/src/plugins/fonts.ts +28 -48
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fonts.d.ts","sourceRoot":"","sources":["../../src/plugins/fonts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAiC,MAAM,MAAM,CAAC;AAClE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AA2B1D,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,qBAAqB,EACrB,sBAAsB,EACtB,uBAAuB,EACvB,wBAAwB,GACzB,MAAM,uBAAuB,CAAC;AAE/B;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"fonts.d.ts","sourceRoot":"","sources":["../../src/plugins/fonts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAiC,MAAM,MAAM,CAAC;AAClE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AA2B1D,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,qBAAqB,EACrB,sBAAsB,EACtB,uBAAuB,EACvB,wBAAwB,GACzB,MAAM,uBAAuB,CAAC;AAE/B;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAkLtD"}
|
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.150",
|
|
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",
|
package/src/index.ts
CHANGED
|
@@ -325,14 +325,20 @@ export function timber(config?: TimberUserConfig): PluginOption[] {
|
|
|
325
325
|
envPort: process.env.PORT,
|
|
326
326
|
listen: (p) => holdingRef.listen(p),
|
|
327
327
|
});
|
|
328
|
-
resolvedDevPort = result.port;
|
|
329
|
-
resolvedDevPortExplicit = result.explicit;
|
|
330
328
|
if (!result.bound) {
|
|
331
329
|
// Holding server failed to bind. Drop the reference so the
|
|
332
330
|
// dev-server plugin doesn't try to close a server that was
|
|
333
|
-
// never listening
|
|
331
|
+
// never listening.
|
|
334
332
|
ctx.holdingServer = null;
|
|
335
333
|
}
|
|
334
|
+
if (result.bound || result.explicit) {
|
|
335
|
+
// When bound, use the probed port with strictPort so Vite
|
|
336
|
+
// doesn't re-bump. When unbound but explicit, still forward
|
|
337
|
+
// the port so Vite surfaces the conflict via strictPort.
|
|
338
|
+
// When unbound and implicit, skip — let Vite auto-bump.
|
|
339
|
+
resolvedDevPort = result.port;
|
|
340
|
+
resolvedDevPortExplicit = result.explicit;
|
|
341
|
+
}
|
|
336
342
|
} else if (command === 'serve' && isPreview) {
|
|
337
343
|
// Preview mode: resolve the starting port from config/env/
|
|
338
344
|
// default but do NOT probe. Vite's preview server handles the
|
package/src/plugins/fonts.ts
CHANGED
|
@@ -143,8 +143,11 @@ export function timberFonts(ctx: PluginContext): Plugin {
|
|
|
143
143
|
* emitted as a real CSS asset and @vitejs/plugin-rsc's `collectCss`
|
|
144
144
|
* walks the RSC module graph to find it.
|
|
145
145
|
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
146
|
+
* Google `@font-face` descriptors are resolved lazily here (both
|
|
147
|
+
* dev and production) because `load` runs after `transform` has
|
|
148
|
+
* registered the font. `buildStart` runs before any transforms,
|
|
149
|
+
* so fonts aren't in the pipeline yet when it fires for the first
|
|
150
|
+
* environment.
|
|
148
151
|
*/
|
|
149
152
|
async load(id: string) {
|
|
150
153
|
if (id === RESOLVED_GOOGLE) return generateGoogleVirtualModule(pipeline.fonts());
|
|
@@ -153,31 +156,32 @@ export function timberFonts(ctx: PluginContext): Plugin {
|
|
|
153
156
|
if (pipeline.cssIdMap.matches(id)) {
|
|
154
157
|
const importer = pipeline.cssIdMap.importerFor(id);
|
|
155
158
|
if (!importer) {
|
|
156
|
-
// Hash is valid but no importer is registered — return an empty
|
|
157
|
-
// CSS module rather than `null`. This can happen if Vite's
|
|
158
|
-
// module graph invalidates the virtual module between the
|
|
159
|
-
// transform that registered the hash and the load that asks
|
|
160
|
-
// for it (e.g. after an HMR edit that removes every font from
|
|
161
|
-
// the file). An empty stylesheet is a valid, safe no-op.
|
|
162
159
|
return '';
|
|
163
160
|
}
|
|
164
161
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
162
|
+
for (const font of pipeline.googleFonts()) {
|
|
163
|
+
if (font.importer !== importer) continue;
|
|
164
|
+
if (pipeline.hasFaces(font.id)) continue;
|
|
165
|
+
try {
|
|
166
|
+
if (ctx.dev) {
|
|
170
167
|
const faces = await resolveDevFontFaces(font);
|
|
171
168
|
pipeline.attachFaces(font.id, faces);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
169
|
+
} else {
|
|
170
|
+
const cached = await downloadAndCacheFonts([font], ctx.root);
|
|
171
|
+
const byFamily = groupCachedFontsByFamily(cached);
|
|
172
|
+
const familyCached = byFamily.get(font.family.toLowerCase()) ?? [];
|
|
173
|
+
pipeline.attachCachedFiles(font.id, familyCached);
|
|
174
|
+
pipeline.attachFaces(
|
|
175
|
+
font.id,
|
|
176
|
+
generateProductionFontFaces(familyCached, font.display, fontUrlPrefix(resolvedBase))
|
|
179
177
|
);
|
|
180
178
|
}
|
|
179
|
+
} catch (e) {
|
|
180
|
+
if (!ctx.dev) throw e;
|
|
181
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
182
|
+
console.warn(
|
|
183
|
+
`[timber-fonts] Failed to resolve Google font "${font.family}": ${msg}. Will retry on next request.`
|
|
184
|
+
);
|
|
181
185
|
}
|
|
182
186
|
}
|
|
183
187
|
|
|
@@ -196,39 +200,15 @@ export function timberFonts(ctx: PluginContext): Plugin {
|
|
|
196
200
|
},
|
|
197
201
|
|
|
198
202
|
/**
|
|
199
|
-
*
|
|
200
|
-
*
|
|
201
|
-
*
|
|
202
|
-
* resolved lazily inside `load()` when the side-effect module runs.
|
|
203
|
+
* No-op. Font downloading and face attachment happen lazily in `load()`
|
|
204
|
+
* because `buildStart` runs before `transform` — fonts aren't registered
|
|
205
|
+
* in the pipeline yet when this fires for the first environment.
|
|
203
206
|
*
|
|
204
207
|
* Local font hashing is handled at registration time by the pipeline
|
|
205
208
|
* (when `hashOnRegister` is set) so hashed filenames are available
|
|
206
209
|
* before the virtual CSS `load()` hook runs.
|
|
207
210
|
*/
|
|
208
|
-
|
|
209
|
-
if (ctx.dev) return;
|
|
210
|
-
|
|
211
|
-
const googleFonts = [...pipeline.googleFonts()];
|
|
212
|
-
if (googleFonts.length === 0) return;
|
|
213
|
-
|
|
214
|
-
const cachedFonts = await downloadAndCacheFonts(googleFonts, ctx.root);
|
|
215
|
-
|
|
216
|
-
// Build a family→CachedFont[] lookup, then attach the cached files
|
|
217
|
-
// and resolved @font-face descriptors to each registered Google
|
|
218
|
-
// font. Multiple fonts that share a family hold references to the
|
|
219
|
-
// same `CachedFont` objects; the bundle emitter dedupes by
|
|
220
|
-
// `hashedFilename` so each binary is written to disk exactly once.
|
|
221
|
-
const cachedByFamily = groupCachedFontsByFamily(cachedFonts);
|
|
222
|
-
const urlPrefix = fontUrlPrefix(resolvedBase);
|
|
223
|
-
for (const font of googleFonts) {
|
|
224
|
-
const familyCached = cachedByFamily.get(font.family.toLowerCase()) ?? [];
|
|
225
|
-
pipeline.attachCachedFiles(font.id, familyCached);
|
|
226
|
-
pipeline.attachFaces(
|
|
227
|
-
font.id,
|
|
228
|
-
generateProductionFontFaces(familyCached, font.display, urlPrefix)
|
|
229
|
-
);
|
|
230
|
-
}
|
|
231
|
-
},
|
|
211
|
+
buildStart() {},
|
|
232
212
|
|
|
233
213
|
/**
|
|
234
214
|
* Scan source files for font function calls and extract static config.
|