Skip to content

Commit 0bebb90

Browse files
committed
refactor(core): pre-generate font assets and append via closeBundle hook
- Add scripts/generate-fonts.mjs to produce fonts.generated.css and copy woff2 files to src/assets/fonts/ from fontsource packages - Remove fonts.css; globals.css no longer imports fonts directly (avoids Vite woff2 resolution warnings during build) - Add appendFonts Vite plugin that appends fonts.generated.css to dist/app-shell.css in closeBundle hook (instant, no font generation) - Committed generated assets so CI doesn't need to re-run generation - Add generate:fonts script to package.json
1 parent f806f48 commit 0bebb90

58 files changed

Lines changed: 206 additions & 11 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

packages/core/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
"scripts": {
4545
"dev": "vite build --watch --mode development",
4646
"build": "vite build",
47+
"generate:fonts": "node scripts/generate-fonts.mjs",
4748
"lint": "oxlint -c .oxlintrc.jsonc",
4849
"test": "vitest run",
4950
"type-check": "tsc --incremental"
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/**
2+
* Generates self-contained font CSS from fontsource packages.
3+
*
4+
* - Reads @font-face declarations from @fontsource-variable/geist and inter
5+
* - Copies woff2 files to src/assets/fonts/
6+
* - Outputs src/assets/fonts.generated.css with rewritten url() paths
7+
*
8+
* Run manually: `node scripts/generate-fonts.mjs`
9+
* The output is committed to the repo so CI doesn't need to re-run this.
10+
*/
11+
import { readFileSync, writeFileSync, mkdirSync, cpSync, rmSync } from "node:fs";
12+
import { resolve, dirname } from "node:path";
13+
import { createRequire } from "node:module";
14+
15+
const require = createRequire(import.meta.url);
16+
const assetsDir = resolve(import.meta.dirname, "../src/assets");
17+
const fontsDir = resolve(assetsDir, "fonts");
18+
19+
// Clean and recreate fonts directory
20+
rmSync(fontsDir, { recursive: true, force: true });
21+
mkdirSync(fontsDir, { recursive: true });
22+
23+
const FONT_PACKAGES = ["@fontsource-variable/geist", "@fontsource-variable/inter"];
24+
25+
let css = "/* Auto-generated by scripts/generate-fonts.mjs — do not edit manually. */\n\n";
26+
27+
for (const pkg of FONT_PACKAGES) {
28+
const pkgDir = dirname(require.resolve(`${pkg}/package.json`));
29+
const pkgCss = readFileSync(resolve(pkgDir, "index.css"), "utf8");
30+
31+
// Copy woff2 files
32+
cpSync(resolve(pkgDir, "files"), fontsDir, { recursive: true });
33+
34+
// Rewrite url(./files/...) → url(./fonts/...)
35+
css += pkgCss.replace(/url\(\.\/files\//g, "url(./fonts/") + "\n";
36+
}
37+
38+
writeFileSync(resolve(assetsDir, "fonts.generated.css"), css);
39+
40+
console.log("✓ src/assets/fonts.generated.css generated");
41+
console.log(`✓ woff2 files copied to src/assets/fonts/`);

packages/core/src/assets/fonts.css

Lines changed: 0 additions & 9 deletions
This file was deleted.
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
/* Auto-generated by scripts/generate-fonts.mjs — do not edit manually. */
2+
3+
/* geist-cyrillic-ext-wght-normal */
4+
@font-face {
5+
font-family: "Geist Variable";
6+
font-style: normal;
7+
font-display: swap;
8+
font-weight: 100 900;
9+
src: url(./fonts/geist-cyrillic-ext-wght-normal.woff2) format("woff2-variations");
10+
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
11+
}
12+
13+
/* geist-cyrillic-wght-normal */
14+
@font-face {
15+
font-family: "Geist Variable";
16+
font-style: normal;
17+
font-display: swap;
18+
font-weight: 100 900;
19+
src: url(./fonts/geist-cyrillic-wght-normal.woff2) format("woff2-variations");
20+
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
21+
}
22+
23+
/* geist-vietnamese-wght-normal */
24+
@font-face {
25+
font-family: "Geist Variable";
26+
font-style: normal;
27+
font-display: swap;
28+
font-weight: 100 900;
29+
src: url(./fonts/geist-vietnamese-wght-normal.woff2) format("woff2-variations");
30+
unicode-range:
31+
U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301,
32+
U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
33+
}
34+
35+
/* geist-latin-ext-wght-normal */
36+
@font-face {
37+
font-family: "Geist Variable";
38+
font-style: normal;
39+
font-display: swap;
40+
font-weight: 100 900;
41+
src: url(./fonts/geist-latin-ext-wght-normal.woff2) format("woff2-variations");
42+
unicode-range:
43+
U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329,
44+
U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F,
45+
U+A720-A7FF;
46+
}
47+
48+
/* geist-latin-wght-normal */
49+
@font-face {
50+
font-family: "Geist Variable";
51+
font-style: normal;
52+
font-display: swap;
53+
font-weight: 100 900;
54+
src: url(./fonts/geist-latin-wght-normal.woff2) format("woff2-variations");
55+
unicode-range:
56+
U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329,
57+
U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
58+
}
59+
/* inter-cyrillic-ext-wght-normal */
60+
@font-face {
61+
font-family: "Inter Variable";
62+
font-style: normal;
63+
font-display: swap;
64+
font-weight: 100 900;
65+
src: url(./fonts/inter-cyrillic-ext-wght-normal.woff2) format("woff2-variations");
66+
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
67+
}
68+
69+
/* inter-cyrillic-wght-normal */
70+
@font-face {
71+
font-family: "Inter Variable";
72+
font-style: normal;
73+
font-display: swap;
74+
font-weight: 100 900;
75+
src: url(./fonts/inter-cyrillic-wght-normal.woff2) format("woff2-variations");
76+
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
77+
}
78+
79+
/* inter-greek-ext-wght-normal */
80+
@font-face {
81+
font-family: "Inter Variable";
82+
font-style: normal;
83+
font-display: swap;
84+
font-weight: 100 900;
85+
src: url(./fonts/inter-greek-ext-wght-normal.woff2) format("woff2-variations");
86+
unicode-range: U+1F00-1FFF;
87+
}
88+
89+
/* inter-greek-wght-normal */
90+
@font-face {
91+
font-family: "Inter Variable";
92+
font-style: normal;
93+
font-display: swap;
94+
font-weight: 100 900;
95+
src: url(./fonts/inter-greek-wght-normal.woff2) format("woff2-variations");
96+
unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
97+
}
98+
99+
/* inter-vietnamese-wght-normal */
100+
@font-face {
101+
font-family: "Inter Variable";
102+
font-style: normal;
103+
font-display: swap;
104+
font-weight: 100 900;
105+
src: url(./fonts/inter-vietnamese-wght-normal.woff2) format("woff2-variations");
106+
unicode-range:
107+
U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301,
108+
U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
109+
}
110+
111+
/* inter-latin-ext-wght-normal */
112+
@font-face {
113+
font-family: "Inter Variable";
114+
font-style: normal;
115+
font-display: swap;
116+
font-weight: 100 900;
117+
src: url(./fonts/inter-latin-ext-wght-normal.woff2) format("woff2-variations");
118+
unicode-range:
119+
U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329,
120+
U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F,
121+
U+A720-A7FF;
122+
}
123+
124+
/* inter-latin-wght-normal */
125+
@font-face {
126+
font-family: "Inter Variable";
127+
font-style: normal;
128+
font-display: swap;
129+
font-weight: 100 900;
130+
src: url(./fonts/inter-latin-wght-normal.woff2) format("woff2-variations");
131+
unicode-range:
132+
U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329,
133+
U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
134+
}
Binary file not shown.
Binary file not shown.
15.6 KB
Binary file not shown.
14.7 KB
Binary file not shown.
17.5 KB
Binary file not shown.
16.1 KB
Binary file not shown.

0 commit comments

Comments
 (0)