Skip to content

Commit

Permalink
Font loader types (#41591)
Browse files Browse the repository at this point in the history
Make local and google font loaders more similar. Both should define `weight: string` and `style: string`.

## Bug

- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Errors have a helpful link attached, see `contributing.md`

## Feature

- [ ] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR.
- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Documentation added
- [ ] Telemetry added. In case of a feature if it's used or not.
- [ ] Errors have a helpful link attached, see `contributing.md`

## Documentation / Examples

- [ ] Make sure the linting passes by running `pnpm lint`
- [ ] The "examples guidelines" are followed from [our contributing doc](https://github.com/vercel/next.js/blob/canary/contributing/examples/adding-examples.md)
  • Loading branch information
Hannes Bornö committed Oct 20, 2022
1 parent 138a7bf commit 77ba4a8
Show file tree
Hide file tree
Showing 19 changed files with 5,986 additions and 6,482 deletions.
6,235 changes: 2,957 additions & 3,278 deletions packages/font/src/google/font-data.json

Large diffs are not rendered by default.

6,049 changes: 2,912 additions & 3,137 deletions packages/font/src/google/index.ts

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/font/src/google/loader.ts
Expand Up @@ -130,7 +130,7 @@ const downloadGoogleFonts: FontLoader = async ({
return {
css: updatedCssResponse,
fallbackFonts: fallback,
weight: weight === 'variable' ? undefined : Number(weight),
weight: weight === 'variable' ? undefined : weight,
style,
variable,
adjustFontFallback: adjustFontFallbackMetrics,
Expand Down
41 changes: 28 additions & 13 deletions packages/font/src/google/utils.ts
Expand Up @@ -19,7 +19,8 @@ type FontOptions = {
}
export function validateData(functionName: string, data: any): FontOptions {
let {
variant,
weight,
style,
display = 'optional',
preload = true,
axes,
Expand All @@ -33,28 +34,44 @@ export function validateData(functionName: string, data: any): FontOptions {

const fontFamily = functionName.replace(/_/g, ' ')

const fontVariants = (fontData as any)[fontFamily]?.variants
if (!fontVariants) {
const fontFamilyData = (fontData as any)[fontFamily]
const fontWeights = fontFamilyData?.weights
if (!fontWeights) {
throw new Error(`Unknown font \`${fontFamily}\``)
}
const fontStyles = fontFamilyData.styles

// Set variable as default, throw if not available
if (!variant) {
if (fontVariants.includes('variable')) {
variant = 'variable'
if (!weight) {
if (fontWeights.includes('variable')) {
weight = 'variable'
} else {
throw new Error(
`Missing variant for font \`${fontFamily}\`.\nAvailable variants: ${formatValues(
fontVariants
`Missing weight for font \`${fontFamily}\`.\nAvailable weights: ${formatValues(
fontWeights
)}`
)
}
}
if (!fontWeights.includes(weight)) {
throw new Error(
`Unknown weight \`${weight}\` for font \`${fontFamily}\`.\nAvailable weights: ${formatValues(
fontWeights
)}`
)
}

if (!fontVariants.includes(variant)) {
if (!style) {
if (fontStyles.length === 1) {
style = fontStyles[0]
} else {
style = 'normal'
}
}
if (!fontStyles.includes(style)) {
throw new Error(
`Unknown variant \`${variant}\` for font \`${fontFamily}\`.\nAvailable variants: ${formatValues(
fontVariants
`Unknown style \`${style}\` for font \`${fontFamily}\`.\nAvailable styles: ${formatValues(
fontStyles
)}`
)
}
Expand All @@ -67,8 +84,6 @@ export function validateData(functionName: string, data: any): FontOptions {
)
}

const [weight, style] = variant.split('-')

if (weight !== 'variable' && axes) {
throw new Error('Axes can only be defined for variable fonts')
}
Expand Down
2 changes: 1 addition & 1 deletion packages/font/src/local/index.ts
Expand Up @@ -5,7 +5,7 @@ type CssVariable = `--${string}`
type LocalFont = {
src: string
display?: Display
weight?: number
weight?: string
style?: string
adjustFontFallback?: 'Arial' | 'Times New Roman' | false
fallback?: string[]
Expand Down
2 changes: 1 addition & 1 deletion packages/font/src/local/utils.ts
Expand Up @@ -17,7 +17,7 @@ type FontOptions = {
ext: string
format: string
display: string
weight?: number
weight?: string
style?: string
fallback?: string[]
preload: boolean
Expand Down
Expand Up @@ -15,7 +15,7 @@ const postcssFontLoaderPlugn = ({
fallbackFonts?: string[]
adjustFontFallback?: AdjustFontFallback
variable?: string
weight?: number
weight?: string
style?: string
}) => {
return {
Expand Down Expand Up @@ -117,6 +117,8 @@ const postcssFontLoaderPlugn = ({
root.nodes.push(fallbackFontFace)
}

// Variable fonts can define ranges of values
const isRange = (value: string) => value.trim().includes(' ')
const formattedFontFamilies = [
formatFamily(fontFamily),
...fallbackFonts,
Expand All @@ -129,15 +131,15 @@ const postcssFontLoaderPlugn = ({
prop: 'font-family',
value: formattedFontFamilies,
}),
...(weight
...(weight && !isRange(weight)
? [
new postcss.Declaration({
prop: 'font-weight',
value: String(weight),
value: weight,
}),
]
: []),
...(style
...(style && !isRange(style)
? [
new postcss.Declaration({
prop: 'font-style',
Expand Down Expand Up @@ -165,8 +167,10 @@ const postcssFontLoaderPlugn = ({
name: 'style',
value: {
fontFamily: formattedFontFamilies,
fontWeight: weight && Number(weight),
fontStyle: style,
fontWeight: !Number.isNaN(Number(weight))
? Number(weight)
: undefined,
fontStyle: style && !isRange(style) ? style : undefined,
},
})
},
Expand Down
2 changes: 1 addition & 1 deletion packages/next/font/index.d.ts
Expand Up @@ -24,6 +24,6 @@ export type FontLoader = (options: {
fallbackFonts?: string[]
variable?: string
adjustFontFallback?: AdjustFontFallback
weight?: number
weight?: string
style?: string
}>
34 changes: 19 additions & 15 deletions scripts/update-google-fonts.js
Expand Up @@ -16,23 +16,25 @@ const fetch = require('node-fetch')
`
const fontData = {}
for (let { family, fonts, axes } of familyMetadataList) {
let hasItalic = false
const variants = Object.keys(fonts).map((variant) => {
const weights = new Set()
const styles = new Set()

for (const variant of Object.keys(fonts)) {
if (variant.endsWith('i')) {
hasItalic = true
return `${variant.slice(0, 3)}-italic`
styles.add('italic')
weights.add(variant.slice(0, -1))
continue
} else {
styles.add('normal')
weights.add(variant)
}
return variant
})
}

const hasVariableFont = axes.length > 0

let optionalAxes
if (hasVariableFont) {
variants.push('variable')
if (hasItalic) {
variants.push('variable-italic')
}
weights.add('variable')

const nonWeightAxes = axes.filter(({ tag }) => tag !== 'wght')
if (nonWeightAxes.length > 0) {
Expand All @@ -41,20 +43,22 @@ const fetch = require('node-fetch')
}

fontData[family] = {
variants,
weights: [...weights],
styles: [...styles],
axes: hasVariableFont ? axes : undefined,
}
const optionalIfVariableFont = hasVariableFont ? '?' : ''
fontFunctions += `export declare function ${family.replaceAll(
' ',
'_'
)}(options${optionalIfVariableFont}: {
variant${optionalIfVariableFont}:${variants
.map((variant) => `"${variant}"`)
weight${optionalIfVariableFont}:${[...weights]
.map((weight) => `"${weight}"`)
.join('|')}
display?:Display,
style?: ${[...styles].map((style) => `"${style}"`).join('|')}
display?:Display
variable?: CssVariable
preload?:boolean,
preload?:boolean
fallback?: string[]
adjustFontFallback?: boolean
${
Expand Down
5 changes: 3 additions & 2 deletions test/e2e/next-font/app/components/CompWithFonts.js
@@ -1,7 +1,8 @@
import { Inter, Roboto } from '@next/font/google'
const inter = Inter({ variant: '900', display: 'swap', preload: false })
const inter = Inter({ weight: '900', display: 'swap', preload: false })
const roboto = Roboto({
variant: '100-italic',
weight: '100',
style: 'italic',
display: 'swap',
preload: true,
})
Expand Down
3 changes: 2 additions & 1 deletion test/e2e/next-font/app/pages/variables.js
Expand Up @@ -3,7 +3,8 @@ import localFont from '@next/font/local'

const firaCode = Fira_Code({ variable: '--fira-code' })
const roboto = Roboto({
variant: '100-italic',
weight: '100',
style: 'italic',
display: 'swap',
preload: true,
variable: '--roboto-100-italic',
Expand Down
4 changes: 2 additions & 2 deletions test/e2e/next-font/app/pages/with-google-fonts.js
@@ -1,7 +1,7 @@
import { Fraunces, Indie_Flower } from '@next/font/google'

const indieFlower = Indie_Flower({ variant: '400' })
const fraunces = Fraunces({ variant: '400' })
const indieFlower = Indie_Flower({ weight: '400' })
const fraunces = Fraunces({ weight: '400' })

export default function WithFonts() {
return (
Expand Down
2 changes: 1 addition & 1 deletion test/e2e/next-font/app/pages/with-local-fonts.js
Expand Up @@ -3,7 +3,7 @@ import localFont from '@next/font/local'
const myFont1 = localFont({
src: '../fonts/my-font.woff2',
style: 'italic',
weight: 100,
weight: '100',
fallback: ['system-ui'],
adjustFontFallback: 'Times New Roman',
})
Expand Down
Expand Up @@ -2,7 +2,7 @@ import { Html, Head, Main, NextScript } from 'next/document'
import { Abel } from '@next/font/google'

// eslint-disable-next-line no-unused-vars
const abel = Abel({ variant: '400' })
const abel = Abel({ weight: '400' })

export default function Document() {
return (
Expand Down
4 changes: 4 additions & 0 deletions test/e2e/next-font/index.test.ts
Expand Up @@ -48,6 +48,7 @@ describe('@next/font/google', () => {
fontFamily: expect.stringMatching(
/^'__Open_Sans_.{6}', '__Open_Sans_Fallback_.{6}'$/
),
fontStyle: 'normal',
},
})

Expand All @@ -59,6 +60,7 @@ describe('@next/font/google', () => {
fontFamily: expect.stringMatching(
/^'__Open_Sans_.{6}', '__Open_Sans_Fallback_.{6}'$/
),
fontStyle: 'normal',
},
})

Expand All @@ -70,6 +72,7 @@ describe('@next/font/google', () => {
/^'__Inter_.{6}', '__Inter_Fallback_.{6}'$/
),
fontWeight: 900,
fontStyle: 'normal',
},
})
expect(JSON.parse($('#comp-with-fonts-roboto').text())).toEqual({
Expand All @@ -96,6 +99,7 @@ describe('@next/font/google', () => {
fontFamily: expect.stringMatching(
/^'__Open_Sans_.{6}', '__Open_Sans_Fallback_.{6}'$/
),
fontStyle: 'normal',
},
})

Expand Down
4 changes: 2 additions & 2 deletions test/e2e/next-font/with-font-declarations-file/fonts.js
Expand Up @@ -9,10 +9,10 @@ import {

const openSans = Open_Sans()
const sourceCodePro = Source_Code_Pro({ display: 'swap', preload: false })
const abel = Abel({ variant: '400', display: 'optional', preload: false })
const abel = Abel({ weight: '400', display: 'optional', preload: false })

export const inter = Inter({ display: 'block', preload: true })
export const roboto = Roboto({ variant: '400' })
export const roboto = Roboto({ weight: '400' })

export const myLocalFont = localFont({
src: './my-font.woff2',
Expand Down
2 changes: 1 addition & 1 deletion test/e2e/next-font/without-preloaded-fonts/pages/_app.js
@@ -1,5 +1,5 @@
import { Abel } from '@next/font/google'
const abel = Abel({ variant: '400', display: 'optional', preload: false })
const abel = Abel({ weight: '400', display: 'optional', preload: false })

function MyApp({ Component, pageProps }) {
return (
Expand Down
@@ -1,5 +1,5 @@
import { Abel } from '@next/font/google'
const abel = Abel({ variant: '400', display: 'optional', preload: false })
const abel = Abel({ weight: '400', display: 'optional', preload: false })

export default function NoPreload() {
return <p className={abel.className}>Hello world</p>
Expand Down

0 comments on commit 77ba4a8

Please sign in to comment.