Skip to content

Commit

Permalink
refactor(google): use native google apis
Browse files Browse the repository at this point in the history
  • Loading branch information
danielroe committed Feb 21, 2024
1 parent 70fc384 commit 8399b32
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 66 deletions.
94 changes: 44 additions & 50 deletions src/providers/google.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { $fetch } from 'ofetch'

import type { FontProvider } from '../types'
import type { FontProvider, ResolveFontFacesOptions } from '../types'
import { extractFontFaceData, addLocalFallbacks } from '../css/parse'

export default {
async setup () {
Expand All @@ -9,78 +10,71 @@ export default {
async resolveFontFaces (fontFamily, defaults) {
if (!isGoogleFont(fontFamily)) { return }

const details = await getFontDetails(fontFamily, defaults.subsets)

return {
fonts: details.variants.map(variant => ({
style: variant.fontStyle,
weight: variant.fontWeight,
// TODO: handle subset unicode ranges
src: [
...variant.local?.map(name => ({ name })) || [fontFamily],
...variant.woff2 ? [{ url: variant.woff2, format: 'woff2' }] : [],
...variant.woff ? [{ url: variant.woff, format: 'woff' }] : [],
...variant.ttf ? [{ url: variant.ttf, format: 'truetype' }] : [],
...variant.eot ? [{ url: variant.eot, format: 'embedded-opentype' }] : [],
...variant.svg ? [{ url: variant.svg, format: 'svg' }] : [],
]
}))
fonts: await getFontDetails(fontFamily, defaults)
}
},
} satisfies FontProvider

// https://github.com/majodev/google-webfonts-helper

interface FontIndexMeta {
category: string
defSubset: string
defVariant: string
family: string
id: string
lastModified: string
popularity: number
subsets: string[]
variants: string[]
version: string
}

interface FontDetail extends Omit<FontIndexMeta, 'variants'> {
variants: Array<{
id: string
fontFamily: string
fontStyle: string
fontWeight: string
eot: string
woff: string
ttf: string
svg: string
woff2: string
local: string[]
fonts: Record<string, {
thickness: number | null
slant: number | null
width: number | null
lineHeight: number | null
}>
subsetMap: Record<string, boolean>
storeID: string
}

const fontAPI = $fetch.create({
baseURL: 'https://gwfh.mranftl.com/api/fonts'
})

let fonts: FontIndexMeta[]

// TODO: Fetch and cache possible Google fonts
async function initialiseFontMeta () {
fonts = await fontAPI<FontIndexMeta[]>('/')
const { familyMetadataList } = await $fetch<{ familyMetadataList: FontIndexMeta[] }>('/metadata/fonts', {
baseURL: 'https://fonts.google.com'
})
fonts = familyMetadataList
}

function isGoogleFont (family: string) {
return fonts.some(font => font.family === family)
}

async function getFontDetails (family: string, defaultSubsets: string[]) {
async function getFontDetails (family: string, variants: ResolveFontFacesOptions) {
const font = fonts.find(font => font.family === family)!
const subsets = defaultSubsets.filter(subset => font.subsets.includes(subset))
const weights = variants.weights.filter(weight => String(weight) in font.fonts)
const styleMap = {
italic: '1',
oblique: '1',
normal: '0'
}

return await fontAPI<FontDetail>(font.id, {
query: subsets.length ? { subsets: subsets.join(',') } : {}
})
const styles = new Set(variants.styles.map(i => styleMap[i]))
const resolvedVariants = weights.flatMap(w => [...styles].map(s => `${s},${w}`))

let css = ''

for (const extension in userAgents) {
css += await $fetch('/css2', {
baseURL: 'https://fonts.googleapis.com',
headers: { 'user-agent': userAgents[extension as keyof typeof userAgents] },
query: {
family: family.replace(/ /g, '+') + ':' + 'ital,wght@' + resolvedVariants.join(';')
}
})
}

// TODO: support subsets
return addLocalFallbacks(family, extractFontFaceData(css))
}

const userAgents = {
woff2: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36',
ttf: 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/534.54.16 (KHTML, like Gecko) Version/5.1.4 Safari/534.54.16'
// eot: 'Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0)',
// woff: 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0',
// 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',
}
80 changes: 64 additions & 16 deletions test/basic.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,24 +43,16 @@ describe('providers', async () => {
const html = await $fetch('/providers/google')
const poppins = extractFontFaces('Poppins', html)
const raleway = extractFontFaces('Raleway', html)
expect(poppins.length).toMatchInlineSnapshot(`18`)
expect(raleway.length).toMatchInlineSnapshot(`18`)
expect(poppins.length).toMatchInlineSnapshot(`8`)
// No `@font-face` is generated for second/fallback fonts
expect(raleway.length).toMatchInlineSnapshot(`0`)
expect(poppins[0]).toMatchInlineSnapshot(`
"@font-face {
font-family: 'Poppins';
src: local("Poppins"), url("/file.woff2") format(woff2), url("/file.woff") format(woff), url("/file.ttf") format(truetype), url("/file.svg") format(svg);
src: local("Poppins"), url("/_fonts/file.woff") format(woff);
font-display: swap;
font-weight: 900;
font-style: italic;
}"
`)
expect(raleway[0]).toMatchInlineSnapshot(`
"@font-face {
font-family: 'Raleway';
src: local("Raleway"), url("/file.woff2") format(woff2), url("/file.woff") format(woff), url("/file.ttf") format(truetype), url("/file.svg") format(svg);
font-display: swap;
font-weight: 900;
font-style: italic;
font-weight: 400;
font-style: normal;
}"
`)
})
Expand Down Expand Up @@ -113,8 +105,40 @@ describe('features', () => {
[
"@font-face {
font-family: 'Anta';
src: local("Anta"), url("/file.woff2") format(woff2), url("/file.woff") format(woff), url("/file.ttf") format(truetype), url("/file.svg") format(svg);
src: local("Anta"), url("/_fonts/file.woff") format(woff);
font-display: swap;
font-weight: 400;
font-style: normal;
}",
"@font-face {
font-family: 'Anta';
src: local("Anta"), url("/_fonts/file.woff2") format(woff2);
font-display: swap;
unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
font-weight: 400;
font-style: normal;
}",
"@font-face {
font-family: 'Anta';
src: local("Anta"), url("/_fonts/file.woff2") format(woff2);
font-display: swap;
unicode-range: U+0100-02AF,U+0304,U+0308,U+0329,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
font-weight: 400;
font-style: normal;
}",
"@font-face {
font-family: 'Anta';
src: local("Anta"), url("/_fonts/file.woff2") format(woff2);
font-display: swap;
unicode-range: U+0001-000C,U+000E-001F,U+007F-009F,U+20DD-20E0,U+20E2-20E4,U+2150-218F,U+2190,U+2192,U+2194-2199,U+21AF,U+21E6-21F0,U+21F3,U+2218-2219,U+2299,U+22C4-22C6,U+2300-243F,U+2440-244A,U+2460-24FF,U+25A0-27BF,U+2800-28FF,U+2921-2922,U+2981,U+29BF,U+29EB,U+2B00-2BFF,U+4DC0-4DFF,U+FFF9-FFFB,U+10140-1018E,U+10190-1019C,U+101A0,U+101D0-101FD,U+102E0-102FB,U+10E60-10E7E,U+1D2C0-1D2D3,U+1D2E0-1D37F,U+1F000-1F0FF,U+1F100-1F1AD,U+1F1E6-1F1FF,U+1F30D-1F30F,U+1F315,U+1F31C,U+1F31E,U+1F320-1F32C,U+1F336,U+1F378,U+1F37D,U+1F382,U+1F393-1F39F,U+1F3A7-1F3A8,U+1F3AC-1F3AF,U+1F3C2,U+1F3C4-1F3C6,U+1F3CA-1F3CE,U+1F3D4-1F3E0,U+1F3ED,U+1F3F1-1F3F3,U+1F3F5-1F3F7,U+1F408,U+1F415,U+1F41F,U+1F426,U+1F43F,U+1F441-1F442,U+1F444,U+1F446-1F449,U+1F44C-1F44E,U+1F453,U+1F46A,U+1F47D,U+1F4A3,U+1F4B0,U+1F4B3,U+1F4B9,U+1F4BB,U+1F4BF,U+1F4C8-1F4CB,U+1F4D6,U+1F4DA,U+1F4DF,U+1F4E3-1F4E6,U+1F4EA-1F4ED,U+1F4F7,U+1F4F9-1F4FB,U+1F4FD-1F4FE,U+1F503,U+1F507-1F50B,U+1F50D,U+1F512-1F513,U+1F53E-1F54A,U+1F54F-1F5FA,U+1F610,U+1F650-1F67F,U+1F687,U+1F68D,U+1F691,U+1F694,U+1F698,U+1F6AD,U+1F6B2,U+1F6B9-1F6BA,U+1F6BC,U+1F6C6-1F6CF,U+1F6D3-1F6D7,U+1F6E0-1F6EA,U+1F6F0-1F6F3,U+1F6F7-1F6FC,U+1F700-1F7FF,U+1F800-1F80B,U+1F810-1F847,U+1F850-1F859,U+1F860-1F887,U+1F890-1F8AD,U+1F8B0-1F8B1,U+1F900-1F90B,U+1F93B,U+1F946,U+1F984,U+1F996,U+1F9E9,U+1FA00-1FA6F,U+1FA70-1FA7C,U+1FA80-1FA88,U+1FA90-1FABD,U+1FABF-1FAC5,U+1FACE-1FADB,U+1FAE0-1FAE8,U+1FAF0-1FAF8,U+1FB00-1FBFF;
font-weight: 400;
font-style: normal;
}",
"@font-face {
font-family: 'Anta';
src: local("Anta"), url("/_fonts/file.woff2") format(woff2);
font-display: swap;
unicode-range: U+0302-0303,U+0305,U+0307-0308,U+0330,U+0391-03A1,U+03A3-03A9,U+03B1-03C9,U+03D1,U+03D5-03D6,U+03F0-03F1,U+03F4-03F5,U+2034-2037,U+2057,U+20D0-20DC,U+20E1,U+20E5-20EF,U+2102,U+210A-210E,U+2110-2112,U+2115,U+2119-211D,U+2124,U+2128,U+212C-212D,U+212F-2131,U+2133-2138,U+213C-2140,U+2145-2149,U+2190,U+2192,U+2194-21AE,U+21B0-21E5,U+21F1-21F2,U+21F4-2211,U+2213-2214,U+2216-22FF,U+2308-230B,U+2310,U+2319,U+231C-2321,U+2336-237A,U+237C,U+2395,U+239B-23B6,U+23D0,U+23DC-23E1,U+2474-2475,U+25AF,U+25B3,U+25B7,U+25BD,U+25C1,U+25CA,U+25CC,U+25FB,U+266D-266F,U+27C0-27FF,U+2900-2AFF,U+2B0E-2B11,U+2B30-2B4C,U+2BFE,U+FF5B,U+FF5D,U+1D400-1D7FF,U+1EE00-1EEFF;
font-weight: 400;
font-style: normal;
}",
Expand All @@ -128,8 +152,32 @@ describe('features', () => {
[
"@font-face {
font-family: 'Anton';
src: local("Anton"), url("/file.woff2") format(woff2), url("/file.woff") format(woff), url("/file.ttf") format(truetype), url("/file.svg") format(svg);
src: local("Anton"), url("/_fonts/file.woff") format(woff);
font-display: swap;
font-weight: 400;
font-style: normal;
}",
"@font-face {
font-family: 'Anton';
src: local("Anton"), url("/_fonts/file.woff2") format(woff2);
font-display: swap;
unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
font-weight: 400;
font-style: normal;
}",
"@font-face {
font-family: 'Anton';
src: local("Anton"), url("/_fonts/file.woff2") format(woff2);
font-display: swap;
unicode-range: U+0100-02AF,U+0304,U+0308,U+0329,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
font-weight: 400;
font-style: normal;
}",
"@font-face {
font-family: 'Anton';
src: local("Anton"), url("/_fonts/file.woff2") format(woff2);
font-display: swap;
unicode-range: U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB;
font-weight: 400;
font-style: normal;
}",
Expand Down

0 comments on commit 8399b32

Please sign in to comment.