Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support font optimization in Google Fonts and Google Icons #80

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/providers/google.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export default defineFontProvider<ProviderOption>('google', async (_options = {}
async function getFontDetails(family: string, options: ResolveFontOptions) {
const font = googleFonts.find(font => font.family === family)!
const styles = [...new Set(options.styles.map(i => styleMap[i]))].sort()
const glyphs = options.glyphs?.join('')

const variableWeight = font.axes.find(a => a.tag === 'wght')
const weights = variableWeight
Expand Down Expand Up @@ -73,6 +74,7 @@ export default defineFontProvider<ProviderOption>('google', async (_options = {}
headers: { 'user-agent': userAgents[extension as keyof typeof userAgents] },
query: {
family: `${family}:${resolvedAxes.join(',')}@${resolvedVariants.join(';')}`,
...(glyphs && { text: glyphs }),
},
})
}
Expand Down
13 changes: 9 additions & 4 deletions src/providers/googleicons.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { hash } from 'ohash'
import type { ResolveFontOptions } from '../types'

import { hash } from 'ohash'
import { extractFontFaceData } from '../css/parse'
import { $fetch } from '../fetch'
import { defineFontProvider } from '../utils'
Expand All @@ -21,7 +22,10 @@ export default defineFontProvider('googleicons', async (_options, ctx) => {
// svg: 'Mozilla/4.0 (iPad; CPU OS 4_0_1 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/4.1 Mobile/9A405 Safari/7534.48.3',
}

async function getFontDetails(family: string) {
async function getFontDetails(family: string, options: ResolveFontOptions) {
// Google Icons require sorted icon names, or we will see a 400 error
const iconNames = options.glyphs?.sort().join(',')

let css = ''

if (family.includes('Icons')) {
Expand Down Expand Up @@ -51,6 +55,7 @@ export default defineFontProvider('googleicons', async (_options, ctx) => {
headers: { 'user-agent': userAgents[extension as keyof typeof userAgents] },
query: {
family: `${family}:` + `opsz,wght,FILL,[email protected],100..700,0..1,-50..200`,
...(iconNames && { icon_names: iconNames }),
},
})
}
Expand All @@ -60,12 +65,12 @@ export default defineFontProvider('googleicons', async (_options, ctx) => {
}

return {
async resolveFont(fontFamily, defaults) {
async resolveFont(fontFamily, options) {
if (!googleIcons.includes(fontFamily)) {
return
}

const fonts = await ctx.storage.getItem(`googleicons:${fontFamily}-${hash(defaults)}-data.json`, () => getFontDetails(fontFamily))
const fonts = await ctx.storage.getItem(`googleicons:${fontFamily}-${hash(options)}-data.json`, () => getFontDetails(fontFamily, options))
return { fonts }
},
}
Expand Down
7 changes: 7 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@ export interface ResolveFontOptions {
// TODO: improve support and support unicode range
subsets: string[]
fallbacks?: string[]
/**
* Specifies the specific characters / icons to download.
* This can reduce the size of the font file.
*
* Currently only supported by Google Fonts / Google Icons (Only available specifying the new 'Material Symbols' icons).
*/
glyphs?: string[]
}

export interface RemoteFontSource {
Expand Down
31 changes: 31 additions & 0 deletions test/providers/google.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,35 @@ describe('google', () => {
expect(resolvedStyles).toMatchObject(styles)
expect(resolvedWeights).toMatchObject(weights)
})

it('respects glyphs option and resolves optimized font', async () => {
const unifont = await createUnifont([providers.google()])

const { fonts } = await unifont.resolveFont('Poppins', {
glyphs: ['Hello', 'World'],
styles: ['normal'],
weights: ['400'],
subsets: [],
})

// Do not use sanitizeFontSource here, as we must test the url parameters
expect(fonts).toMatchInlineSnapshot(`
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the URL parameters were the only way to verify that the correctly optimized fonts were resolved, I did a snapshot test.

[
{
"src": [
{
"format": "woff2",
"url": "https://fonts.gstatic.com/l/font?kit=pxiEyp8kv8JHgFVrFJXUdVNFIvDDHy0hxgHa&skey=87759fb096548f6d&v=v22",
},
{
"format": "woff",
"url": "https://fonts.gstatic.com/l/font?kit=pxiEyp8kv8JHgFVrFJPMcBMSdJLnJzs&skey=87759fb096548f6d&v=v22",
},
],
"style": "normal",
"weight": 400,
},
]
`)
})
})
Loading
Loading