Skip to content

Commit 509adfd

Browse files
committed
perf: use code filter when processCSSVariables is disabled
1 parent 78bbb42 commit 509adfd

2 files changed

Lines changed: 146 additions & 7 deletions

File tree

src/plugins/transform.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,12 @@ export const FontFamilyInjectionPlugin = (options: FontFamilyInjectionPluginOpti
1515
include: [IS_CSS_RE],
1616
exclude: [SKIP_RE],
1717
},
18+
code: {
19+
// Early return if no font-family is used in this CSS
20+
exclude: !options.processCSSVariables ? [/^(?!.*font-family\s*:).*$/s] : undefined,
21+
},
1822
},
1923
async handler(code, id) {
20-
// Early return if no font-family is used in this CSS
21-
if (!options.processCSSVariables && !code.includes('font-family:')) {
22-
return
23-
}
24-
2524
const s = await transformCSS(options, code, id)
2625

2726
if (s.hasChanged()) {

test/parse.test.ts

Lines changed: 142 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,146 @@ describe('parsing css', () => {
171171
})
172172
})
173173

174+
describe('filter patterns', () => {
175+
it('should not process CSS without font-family when processCSSVariables is false', async () => {
176+
const transformWithoutCSSVariables = async (css: string) => {
177+
const plugin = FontFamilyInjectionPlugin({
178+
dev: true,
179+
processCSSVariables: false,
180+
shouldPreload: () => true,
181+
fontsToPreload: new Map(),
182+
resolveFontFace: family => ({
183+
fonts: [{ src: [{ url: `/${slugify(family)}.woff2`, format: 'woff2' }] }],
184+
}),
185+
}).vite() as any
186+
187+
const result = await plugin.transform?.handler?.(css, 'some-id.css')
188+
return result?.code
189+
}
190+
191+
// CSS without font-family should not be processed (returns undefined)
192+
const cssWithoutFontFamily = `.header { color: red; background: blue; }`
193+
expect(await transformWithoutCSSVariables(cssWithoutFontFamily)).toBeUndefined()
194+
195+
// CSS with font-family should be processed
196+
const cssWithFontFamily = `.header { font-family: 'CustomFont'; color: red; }`
197+
const result = await transformWithoutCSSVariables(cssWithFontFamily)
198+
expect(result).toContain('@font-face')
199+
expect(result).toContain('CustomFont')
200+
})
201+
202+
it('should process CSS variables when processCSSVariables is true', async () => {
203+
const transformWithCSSVariables = async (css: string) => {
204+
const plugin = FontFamilyInjectionPlugin({
205+
dev: true,
206+
processCSSVariables: true,
207+
shouldPreload: () => true,
208+
fontsToPreload: new Map(),
209+
resolveFontFace: family => ({
210+
fonts: [{ src: [{ url: `/${slugify(family)}.woff2`, format: 'woff2' }] }],
211+
}),
212+
}).vite() as any
213+
214+
const result = await plugin.transform?.handler?.(css, 'some-id.css')
215+
return result?.code
216+
}
217+
218+
// CSS with font-family in variable should be processed
219+
const cssWithVariable = `:root { --font-var: 'CustomFont'; }`
220+
const result = await transformWithCSSVariables(cssWithVariable)
221+
expect(result).toContain('@font-face')
222+
expect(result).toContain('CustomFont')
223+
224+
// Even CSS without explicit font-family should be processed when processCSSVariables is true
225+
const cssWithoutFontFamily = `.header { color: red; --font-var: 'AnotherFont'; }`
226+
const result2 = await transformWithCSSVariables(cssWithoutFontFamily)
227+
expect(result2).toContain('@font-face')
228+
expect(result2).toContain('AnotherFont')
229+
})
230+
231+
it('should handle multiline CSS correctly', async () => {
232+
const transformWithoutCSSVariables = async (css: string) => {
233+
const plugin = FontFamilyInjectionPlugin({
234+
dev: true,
235+
processCSSVariables: false,
236+
shouldPreload: () => true,
237+
fontsToPreload: new Map(),
238+
resolveFontFace: family => ({
239+
fonts: [{ src: [{ url: `/${slugify(family)}.woff2`, format: 'woff2' }] }],
240+
}),
241+
}).vite() as any
242+
243+
const result = await plugin.transform?.handler?.(css, 'some-id.css')
244+
return result?.code
245+
}
246+
247+
// Multiline CSS without font-family should not be processed
248+
const multilineCssWithoutFontFamily = `
249+
.header {
250+
color: red;
251+
background: blue;
252+
margin: 10px;
253+
}
254+
`
255+
expect(await transformWithoutCSSVariables(multilineCssWithoutFontFamily)).toBeUndefined()
256+
257+
// Multiline CSS with font-family should be processed
258+
const multilineCssWithFontFamily = `
259+
.header {
260+
color: red;
261+
font-family: 'CustomFont';
262+
background: blue;
263+
}
264+
`
265+
const result = await transformWithoutCSSVariables(multilineCssWithFontFamily)
266+
expect(result).toContain('@font-face')
267+
expect(result).toContain('CustomFont')
268+
})
269+
270+
it('should detect font-family in various CSS contexts', async () => {
271+
const transformWithoutCSSVariables = async (css: string) => {
272+
const plugin = FontFamilyInjectionPlugin({
273+
dev: true,
274+
processCSSVariables: false,
275+
shouldPreload: () => true,
276+
fontsToPreload: new Map(),
277+
resolveFontFace: family => ({
278+
fonts: [{ src: [{ url: `/${slugify(family)}.woff2`, format: 'woff2' }] }],
279+
}),
280+
}).vite() as any
281+
282+
const result = await plugin.transform?.handler?.(css, 'some-id.css')
283+
return result?.code
284+
}
285+
286+
// Should process: direct font-family property
287+
const result1 = await transformWithoutCSSVariables(`.test { font-family: CustomFont; }`)
288+
expect(result1).toBeDefined()
289+
expect(result1).toContain('@font-face')
290+
291+
// Should process: font-family in nested rules
292+
const result2 = await transformWithoutCSSVariables(`.parent { .child { font-family: CustomFont; } }`)
293+
expect(result2).toBeDefined()
294+
expect(result2).toContain('@font-face')
295+
296+
// Should process: font-family in media queries
297+
const result3 = await transformWithoutCSSVariables(`@media (min-width: 768px) { .test { font-family: CustomFont; } }`)
298+
expect(result3).toBeDefined()
299+
expect(result3).toContain('@font-face')
300+
301+
// Should process: font-family with spaces
302+
const result4 = await transformWithoutCSSVariables(`.test { font-family : CustomFont ; }`)
303+
expect(result4).toBeDefined()
304+
expect(result4).toContain('@font-face')
305+
306+
// Should NOT process: no font-family at all
307+
expect(await transformWithoutCSSVariables(`.test { color: red; margin: 10px; }`)).toBeUndefined()
308+
309+
// Should NOT process: has 'font' but not 'font-family'
310+
expect(await transformWithoutCSSVariables(`.test { font-size: 14px; font-weight: bold; }`)).toBeUndefined()
311+
})
312+
})
313+
174314
describe('error handling', () => {
175315
it('handles no font details supplied', async () => {
176316
const plugin = FontFamilyInjectionPlugin({
@@ -195,8 +335,8 @@ async function transform(css: string) {
195335
fonts: [{ src: [{ url: `/${slugify(family)}.woff2`, format: 'woff2' }] }],
196336
fallbacks: options?.fallbacks ? ['Times New Roman', ...options.fallbacks] : undefined,
197337
}),
198-
}).raw({}, { framework: 'vite' }) as any
338+
}).vite() as any
199339

200-
const result = await plugin.transform?.handler?.(css, 'some-id')
340+
const result = await plugin.transform?.handler?.(css, 'some-id.css')
201341
return result?.code
202342
}

0 commit comments

Comments
 (0)