Skip to content

Commit 47728ce

Browse files
committed
feat: handle font files in css
1 parent a902dda commit 47728ce

File tree

11 files changed

+369
-66
lines changed

11 files changed

+369
-66
lines changed

package-lock.json

+198-40
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/rollup-plugin-html/package.json

+1-2
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,12 @@
4545
],
4646
"dependencies": {
4747
"@web/parse5-utils": "^2.1.0",
48-
"clean-css": "^5.3.3",
4948
"glob": "^10.0.0",
5049
"html-minifier-terser": "^7.1.0",
50+
"lightningcss": "^1.24.0",
5151
"parse5": "^6.0.1"
5252
},
5353
"devDependencies": {
54-
"@types/clean-css": "^4.2.11",
5554
"@types/html-minifier-terser": "^7.0.0",
5655
"rollup": "^4.4.0"
5756
}

packages/rollup-plugin-html/src/output/emitAssets.ts

+51-13
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { PluginContext } from 'rollup';
22
import path from 'path';
3-
import CleanCSS from 'clean-css';
3+
import { transform } from 'lightningcss';
4+
import fs from 'fs';
45

56
import { InputAsset, InputData } from '../input/InputData';
67
import { RollupPluginHTMLOptions, TransformAssetFunction } from '../RollupPluginHTMLOptions';
@@ -10,6 +11,16 @@ export interface EmittedAssets {
1011
hashed: Map<string, string>;
1112
}
1213

14+
function shouldHandleFontFile(url: string) {
15+
return (
16+
(url.endsWith('.woff2') || url.endsWith('.woff')) &&
17+
!url.startsWith('http') &&
18+
!url.startsWith('data') &&
19+
!url.startsWith('#') &&
20+
!url.startsWith('/')
21+
);
22+
}
23+
1324
export async function emitAssets(
1425
this: PluginContext,
1526
inputs: InputData[],
@@ -44,18 +55,6 @@ export async function emitAssets(
4455
const allAssets = [...hashedAssets, ...staticAssets];
4556

4657
for (const asset of allAssets) {
47-
if (asset.filePath.endsWith('.css')) {
48-
// TODO: try css bundlers like https://lightningcss.dev/bundling.html or esbuild
49-
// TODO: question: do we need to recursively analyze all assets that are referenced inside the first css file?
50-
// TODO: make a flag to enable this behavior, "false" by default
51-
const { styles } = await new CleanCSS({
52-
rebaseTo: path.dirname(asset.filePath),
53-
returnPromise: true,
54-
}).minify([asset.filePath]);
55-
console.log('emitEsset.ts styles', styles);
56-
asset.content = Buffer.from(styles, 'utf-8');
57-
}
58-
5958
const map = asset.hashed ? emittedHashedAssets : emittedStaticAssets;
6059
if (!map.has(asset.filePath)) {
6160
let source: Buffer = asset.content;
@@ -70,7 +69,46 @@ export async function emitAssets(
7069

7170
let ref: string;
7271
let basename = path.basename(asset.filePath);
72+
const emittedFonts = new Map();
7373
if (asset.hashed) {
74+
if (basename.endsWith('.css')) {
75+
let updatedCssSource = false;
76+
const { code } = await transform({
77+
filename: basename,
78+
code: asset.content,
79+
minify: false,
80+
visitor: {
81+
Url: url => {
82+
if (shouldHandleFontFile(url.url)) {
83+
// Read the font file, get the font from the source location on the FS using asset.filePath
84+
const fontLocation = path.resolve(path.dirname(asset.filePath), url.url);
85+
const fontContent = fs.readFileSync(fontLocation);
86+
87+
// Avoid duplicates
88+
if (!emittedFonts.has(fontLocation)) {
89+
const fontFileRef = this.emitFile({
90+
type: 'asset',
91+
name: path.basename(url.url),
92+
source: fontContent,
93+
});
94+
const emittedFontFilePath = path.basename(this.getFileName(fontFileRef));
95+
emittedFonts.set(fontLocation, emittedFontFilePath);
96+
// Update the URL in the original CSS file to point to the emitted font file
97+
url.url = emittedFontFilePath;
98+
} else {
99+
url.url = emittedFonts.get(fontLocation);
100+
}
101+
}
102+
updatedCssSource = true;
103+
return url;
104+
},
105+
},
106+
});
107+
if (updatedCssSource) {
108+
source = Buffer.from(code);
109+
}
110+
}
111+
74112
ref = this.emitFile({ type: 'asset', name: basename, source });
75113
} else {
76114
// ensure the output filename is unique

packages/rollup-plugin-html/test/fixtures/resolves-assets-in-styles-duplicates/fonts/font-normal.woff2

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
@font-face {
2+
font-family: 'Font';
3+
src: url('fonts/font-normal.woff2') format('woff2');
4+
font-weight: normal;
5+
font-style: normal;
6+
font-display: swap;
7+
}

0 commit comments

Comments
 (0)