Skip to content

Commit

Permalink
fix(transform): skip adding existing @font-face declarations
Browse files Browse the repository at this point in the history
  • Loading branch information
danielroe committed Feb 20, 2024
1 parent 0cb114b commit 79f9c58
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 12 deletions.
23 changes: 18 additions & 5 deletions src/plugins/transform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,29 @@ export const FontFamilyInjectionPlugin = (options: FontFamilyInjectionPluginOpti
}
}

// TODO: handle these edge cases
// 1. existing font-family in this scope
// 2. handle CSS custom properties
walk(parse(code), {
const ast = parse(code)

// Collect existing `@font-face` declarations (to skip adding them)
const existingFontFamilies = new Set<string>()
walk(ast, {
visit: 'Declaration',
enter (node) {
if (this.atrule?.name === 'font-face' && node.property === 'font-family') {
for (const family of extractFontFamilies(node)) {
existingFontFamilies.add(family)
}
}
}
})

// TODO: handle CSS custom properties
walk(ast, {
visit: 'Declaration',
enter (node) {
if (node.property !== 'font-family' || this.atrule?.name === 'font-face') { return }

for (const fontFamily of extractFontFamilies(node)) {
if (processedFontFamilies.has(fontFamily)) continue
if (processedFontFamilies.has(fontFamily) || existingFontFamilies.has(fontFamily)) continue
processedFontFamilies.add(fontFamily)
promises.push(addFontFaceDeclaration(fontFamily))
}
Expand Down
33 changes: 26 additions & 7 deletions test/parse.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,47 @@ import { describe, expect, it } from 'vitest'
import { FontFamilyInjectionPlugin } from '../src/plugins/transform'

describe('parsing', () => {
it('should declarations within `@font-face`', async () => {
it('should add declarations for `font-family`', async () => {
expect(await transform(`:root { font-family: 'CustomFont' }`))
.toMatchInlineSnapshot(`
"@font-face {
font-family: 'CustomFont';
src: url("/customfont.woff2") format(woff2);
font-display: swap;
}
:root { font-family: 'CustomFont' }"
`)
})

it('should skip processing declarations within `@font-face`', async () => {
expect(await transform(`@font-face { font-family: 'CustomFont' }`))
.toMatchInlineSnapshot(`undefined`)
})

it('should add declarations for `font-family`', async () => {
expect(await transform(`:root { font-family: 'CustomFont' }`))
it('should ignore any @font-face already in scope', async () => {
expect(await transform([
`@font-face { font-family: 'ScopedFont'; src: local("ScopedFont") }`,
`:root { font-family: 'ScopedFont' }`,
`:root { font-family: 'CustomFont' }`,
].join('\n')))
.toMatchInlineSnapshot(`
"@font-face {
font-family: 'CustomFont';
src: url("/font.woff2") format(woff2);
src: url("/customfont.woff2") format(woff2);
font-display: swap;
}
@font-face { font-family: 'ScopedFont'; src: local("ScopedFont") }
:root { font-family: 'ScopedFont' }
:root { font-family: 'CustomFont' }"
`)
})
})


const slugify = (str: string) => str.toLowerCase().replace(/[^\d\w]/g, '-')
async function transform (css: string) {
const plugin = FontFamilyInjectionPlugin({ resolveFontFace: () => ({ src: '/font.woff2' }) })
.raw({}, { framework: 'vite' }) as any
const plugin = FontFamilyInjectionPlugin({
resolveFontFace: (family) => ({ src: `/${slugify(family)}.woff2` })
}).raw({}, { framework: 'vite' }) as any

const result = await plugin.transform(css)
return result?.code
Expand Down

0 comments on commit 79f9c58

Please sign in to comment.