@timber-js/app 0.2.0-alpha.65 → 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 CHANGED
@@ -13491,6 +13491,48 @@ async function isCacheHit(metaPath, dataPath) {
13491
13491
  return false;
13492
13492
  }
13493
13493
  }
13494
+ /**
13495
+ * Generate @font-face descriptors for cached (production) Google Fonts.
13496
+ *
13497
+ * Each CachedFont gets a FontFaceDescriptor pointing to the
13498
+ * content-hashed URL under `/_timber/fonts/`.
13499
+ */
13500
+ function generateProductionFontFaces(cachedFonts, display) {
13501
+ return cachedFonts.map((cf) => ({
13502
+ family: cf.face.family,
13503
+ src: `url('/_timber/fonts/${cf.hashedFilename}') format('woff2')`,
13504
+ weight: cf.face.weight,
13505
+ style: cf.face.style,
13506
+ display,
13507
+ unicodeRange: cf.face.unicodeRange
13508
+ }));
13509
+ }
13510
+ /**
13511
+ * Generate @font-face descriptors for dev mode (CDN-pointing).
13512
+ *
13513
+ * In dev mode, we query the Google Fonts API but use the CDN URLs
13514
+ * directly instead of downloading. This avoids the download/cache
13515
+ * step during `vite dev`.
13516
+ */
13517
+ function generateDevFontFaces(faces, display) {
13518
+ return faces.map((face) => ({
13519
+ family: face.family,
13520
+ src: `url('${face.url}') format('woff2')`,
13521
+ weight: face.weight,
13522
+ style: face.style,
13523
+ display,
13524
+ unicodeRange: face.unicodeRange
13525
+ }));
13526
+ }
13527
+ /**
13528
+ * Resolve dev-mode font faces for an extracted font.
13529
+ *
13530
+ * Fetches the CSS from Google Fonts API and returns FontFaceDescriptors
13531
+ * pointing to CDN URLs. No files are downloaded.
13532
+ */
13533
+ async function resolveDevFontFaces(font) {
13534
+ return generateDevFontFaces(filterBySubsets(await fetchGoogleFontsCss(buildGoogleFontsUrl(font)), font.subsets), font.display);
13535
+ }
13494
13536
  //#endregion
13495
13537
  //#region src/plugins/fonts.ts
13496
13538
  var VIRTUAL_GOOGLE = "@timber/fonts/google";
@@ -13662,15 +13704,22 @@ function generateLocalVirtualModule() {
13662
13704
  /**
13663
13705
  * Generate CSS for a single extracted font.
13664
13706
  *
13665
- * Includes @font-face rules (for local fonts), fallback @font-face,
13707
+ * Includes @font-face rules (for local and Google fonts), fallback @font-face,
13666
13708
  * and the scoped class rule.
13709
+ *
13710
+ * For Google fonts, pass the resolved FontFaceDescriptor[] from either
13711
+ * `generateProductionFontFaces()` (production) or `resolveDevFontFaces()` (dev).
13667
13712
  */
13668
- function generateFontCss(font) {
13713
+ function generateFontCss(font, googleFaces) {
13669
13714
  const cssParts = [];
13670
13715
  if (font.provider === "local" && font.localSources) {
13671
13716
  const faceCss = generateFontFaces(generateLocalFontFaces(font.family, font.localSources, font.display));
13672
13717
  if (faceCss) cssParts.push(faceCss);
13673
13718
  }
13719
+ if (font.provider === "google" && googleFaces && googleFaces.length > 0) {
13720
+ const faceCss = generateFontFaces(googleFaces);
13721
+ if (faceCss) cssParts.push(faceCss);
13722
+ }
13674
13723
  const fallbackCss = generateFallbackCss(font.family);
13675
13724
  if (fallbackCss) cssParts.push(fallbackCss);
13676
13725
  if (font.variable) cssParts.push(generateVariableClass(font.className, font.variable, font.fontFamily));
@@ -13680,12 +13729,18 @@ function generateFontCss(font) {
13680
13729
  /**
13681
13730
  * Generate the CSS output for all extracted fonts.
13682
13731
  *
13683
- * Includes @font-face rules for local fonts, fallback @font-face rules,
13684
- * and scoped classes.
13732
+ * Includes @font-face rules for local and Google fonts, fallback @font-face
13733
+ * rules, and scoped classes.
13734
+ *
13735
+ * `googleFontFacesMap` provides pre-resolved FontFaceDescriptor[] for each
13736
+ * Google font ID (keyed by ExtractedFont.id).
13685
13737
  */
13686
- function generateAllFontCss(registry) {
13738
+ function generateAllFontCss(registry, googleFontFacesMap) {
13687
13739
  const cssParts = [];
13688
- for (const font of registry.values()) cssParts.push(generateFontCss(font));
13740
+ for (const font of registry.values()) {
13741
+ const googleFaces = googleFontFacesMap?.get(font.id);
13742
+ cssParts.push(generateFontCss(font, googleFaces));
13743
+ }
13689
13744
  return cssParts.join("\n\n");
13690
13745
  }
13691
13746
  /**
@@ -13736,6 +13791,11 @@ function timberFonts(ctx) {
13736
13791
  const registry = /* @__PURE__ */ new Map();
13737
13792
  /** Fonts downloaded during buildStart (production only). */
13738
13793
  let cachedFonts = [];
13794
+ /**
13795
+ * Pre-resolved @font-face descriptors for Google fonts, keyed by font ID.
13796
+ * Populated in buildStart (production) or lazily in load (dev).
13797
+ */
13798
+ const googleFontFacesMap = /* @__PURE__ */ new Map();
13739
13799
  return {
13740
13800
  name: "timber-fonts",
13741
13801
  resolveId(id) {
@@ -13750,11 +13810,22 @@ function timberFonts(ctx) {
13750
13810
  if (cleanId === VIRTUAL_FONT_CSS_REGISTER) return RESOLVED_FONT_CSS_REGISTER;
13751
13811
  return null;
13752
13812
  },
13753
- load(id) {
13813
+ async load(id) {
13754
13814
  if (id === RESOLVED_GOOGLE) return generateGoogleVirtualModule(registry);
13755
13815
  if (id === RESOLVED_LOCAL) return generateLocalVirtualModule();
13756
13816
  if (id === RESOLVED_FONT_CSS_REGISTER) {
13757
- const css = generateAllFontCss(registry);
13817
+ if (ctx.dev) {
13818
+ const googleFonts = [...registry.values()].filter((f) => f.provider === "google");
13819
+ for (const font of googleFonts) if (!googleFontFacesMap.has(font.id)) try {
13820
+ const faces = await resolveDevFontFaces(font);
13821
+ googleFontFacesMap.set(font.id, faces);
13822
+ } catch (e) {
13823
+ const msg = e instanceof Error ? e.message : String(e);
13824
+ console.warn(`[timber-fonts] Failed to resolve Google font "${font.family}": ${msg}`);
13825
+ googleFontFacesMap.set(font.id, []);
13826
+ }
13827
+ }
13828
+ const css = generateAllFontCss(registry, googleFontFacesMap);
13758
13829
  return `globalThis.__timber_font_css = ${JSON.stringify(css)};`;
13759
13830
  }
13760
13831
  return null;
@@ -13801,6 +13872,17 @@ function timberFonts(ctx) {
13801
13872
  const googleFonts = [...registry.values()].filter((f) => f.provider === "google");
13802
13873
  if (googleFonts.length === 0) return;
13803
13874
  cachedFonts = await downloadAndCacheFonts(googleFonts, ctx.root);
13875
+ const cachedByFamily = /* @__PURE__ */ new Map();
13876
+ for (const cf of cachedFonts) {
13877
+ const key = cf.face.family.toLowerCase();
13878
+ const arr = cachedByFamily.get(key) ?? [];
13879
+ arr.push(cf);
13880
+ cachedByFamily.set(key, arr);
13881
+ }
13882
+ for (const font of googleFonts) {
13883
+ const faces = generateProductionFontFaces(cachedByFamily.get(font.family.toLowerCase()) ?? [], font.display);
13884
+ googleFontFacesMap.set(font.id, faces);
13885
+ }
13804
13886
  },
13805
13887
  transform(code, id) {
13806
13888
  if (id.startsWith("\0") || id.includes("node_modules")) return null;