Skip to content

Commit

Permalink
Font subsets in function call (#41694)
Browse files Browse the repository at this point in the history
Enable setting font specific subsets in the call.

## 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)


Co-authored-by: JJ Kasper <22380829+ijjk@users.noreply.github.com>
  • Loading branch information
Hannes Bornö and ijjk committed Oct 24, 2022
1 parent a9d1452 commit ef7de2a
Show file tree
Hide file tree
Showing 10 changed files with 1,950 additions and 12 deletions.
1,901 changes: 1,901 additions & 0 deletions packages/font/src/google/index.ts

Large diffs are not rendered by default.

25 changes: 15 additions & 10 deletions packages/font/src/google/loader.ts
Expand Up @@ -21,16 +21,8 @@ const downloadGoogleFonts: FontLoader = async ({
data,
config,
emitFontFile,
isServer,
}) => {
if (!config?.subsets) {
Log.warn(
`${chalk.bold('@next/font/google')} is missing ${chalk.bold(
'options.subsets'
)} in your ${chalk.bold(
'next.config.js'
)}. Please specify subsets, otherwise no fonts will be preloaded.`
)
}
const subsets = config?.subsets || []

const {
Expand All @@ -43,7 +35,19 @@ const downloadGoogleFonts: FontLoader = async ({
fallback,
adjustFontFallback,
variable,
subsets: callSubsets,
} = validateData(functionName, data)

if (isServer && preload && !callSubsets && !config?.subsets) {
Log.warn(
`The ${chalk.bold('@next/font/google')} font ${chalk.bold(
fontFamily
)} has no selected subsets. Please specify subsets in the function call or in your ${chalk.bold(
'next.config.js'
)}, otherwise no fonts will be preloaded. Read more: https://nextjs.org/docs/api-reference/components/font#nextfontgoogle`
)
}

const fontAxes = getFontAxes(fontFamily, weight, style, selectedVariableAxes)
const url = getUrl(fontFamily, fontAxes, display)

Expand Down Expand Up @@ -72,7 +76,8 @@ const downloadGoogleFonts: FontLoader = async ({
if (googleFontFileUrl) {
fontFiles.push({
googleFontFileUrl,
preloadFontFile: !!preload && subsets.includes(currentSubset),
preloadFontFile:
!!preload && (callSubsets ?? subsets).includes(currentSubset),
})
}
}
Expand Down
3 changes: 3 additions & 0 deletions packages/font/src/google/utils.ts
Expand Up @@ -16,6 +16,7 @@ type FontOptions = {
fallback?: string[]
adjustFontFallback: boolean
variable?: string
subsets?: string[]
}
export function validateData(functionName: string, data: any): FontOptions {
let {
Expand All @@ -27,6 +28,7 @@ export function validateData(functionName: string, data: any): FontOptions {
fallback,
adjustFontFallback = true,
variable,
subsets,
} = data[0] || ({} as any)
if (functionName === '') {
throw new Error(`@next/font/google has no default export`)
Expand Down Expand Up @@ -98,6 +100,7 @@ export function validateData(functionName: string, data: any): FontOptions {
fallback,
adjustFontFallback,
variable,
subsets,
}
}

Expand Down
Expand Up @@ -78,6 +78,7 @@ export default async function nextFontLoader(this: any) {
src.startsWith('.') ? src : `./${src}`
),
fs: this.fs,
isServer,
})

const { postcss } = await getPostcss()
Expand Down
1 change: 1 addition & 0 deletions packages/next/font/index.d.ts
Expand Up @@ -19,6 +19,7 @@ export type FontLoader = (options: {
emitFontFile: (content: Buffer, ext: string, preload: boolean) => string
resolve: (src: string) => string
fs: any
isServer: boolean
}) => Promise<{
css: string
fallbackFonts?: string[]
Expand Down
4 changes: 3 additions & 1 deletion scripts/update-google-fonts.js
Expand Up @@ -15,7 +15,8 @@ const fetch = require('node-fetch')
type CssVariable = \`--\${string}\`
`
const fontData = {}
for (let { family, fonts, axes } of familyMetadataList) {
for (let { family, fonts, axes, subsets } of familyMetadataList) {
subsets = subsets.filter((subset) => subset !== 'menu')
const weights = new Set()
const styles = new Set()

Expand Down Expand Up @@ -61,6 +62,7 @@ const fetch = require('node-fetch')
preload?:boolean
fallback?: string[]
adjustFontFallback?: boolean
subsets?: Array<${subsets.map((subset) => `"${subset}"`).join('|')}>
${
optionalAxes
? `axes?:(${optionalAxes.map(({ tag }) => `'${tag}'`).join('|')})[]`
Expand Down
1 change: 1 addition & 0 deletions test/e2e/next-font/app/components/CompWithFonts.js
Expand Up @@ -5,6 +5,7 @@ const roboto = Roboto({
style: 'italic',
display: 'swap',
preload: true,
subsets: ['vietnamese'],
})

export default function Component() {
Expand Down
2 changes: 1 addition & 1 deletion test/e2e/next-font/index.test.ts
Expand Up @@ -303,7 +303,7 @@ describe('@next/font/google', () => {
expect($('link[as="font"]').get(1).attribs).toEqual({
as: 'font',
crossorigin: 'anonymous',
href: '/_next/static/media/4f3dcdf40b3ca86d.p.woff2',
href: '/_next/static/media/675c25f648fd6a30.p.woff2',
rel: 'preload',
type: 'font/woff2',
})
Expand Down
16 changes: 16 additions & 0 deletions test/unit/google-font-loader.test.ts
Expand Up @@ -85,6 +85,7 @@ describe('@next/font/google loader', () => {
emitFontFile: jest.fn(),
resolve: jest.fn(),
fs: {} as any,
isServer: true,
})
expect(css).toBe('OK')
expect(fetch).toHaveBeenCalledTimes(1)
Expand All @@ -105,6 +106,7 @@ describe('@next/font/google loader', () => {
emitFontFile: jest.fn(),
resolve: jest.fn(),
fs: {} as any,
isServer: true,
})
expect(adjustFontFallback).toEqual({
ascentOverride: '88.84%',
Expand All @@ -128,6 +130,7 @@ describe('@next/font/google loader', () => {
emitFontFile: jest.fn(),
resolve: jest.fn(),
fs: {} as any,
isServer: true,
})
expect(adjustFontFallback).toEqual({
ascentOverride: '80.28%',
Expand All @@ -151,6 +154,7 @@ describe('@next/font/google loader', () => {
emitFontFile: jest.fn(),
resolve: jest.fn(),
fs: {} as any,
isServer: true,
})
expect(adjustFontFallback).toEqual({
ascentOverride: '83.79%',
Expand All @@ -174,6 +178,7 @@ describe('@next/font/google loader', () => {
emitFontFile: jest.fn(),
resolve: jest.fn(),
fs: {} as any,
isServer: true,
})
expect(css).toBe('')
expect(fallbackFonts).toEqual(['system-ui', 'Arial'])
Expand All @@ -194,6 +199,7 @@ describe('@next/font/google loader', () => {
emitFontFile: jest.fn(),
resolve: jest.fn(),
fs: {} as any,
isServer: true,
})
).rejects.toThrowErrorMatchingInlineSnapshot(`
"Failed to fetch font \`Alkalami\`.
Expand All @@ -210,6 +216,7 @@ describe('@next/font/google loader', () => {
emitFontFile: jest.fn(),
resolve: jest.fn(),
fs: {} as any,
isServer: true,
})
).rejects.toThrowErrorMatchingInlineSnapshot(
`"@next/font/google has no default export"`
Expand All @@ -225,6 +232,7 @@ describe('@next/font/google loader', () => {
emitFontFile: jest.fn(),
resolve: jest.fn(),
fs: {} as any,
isServer: true,
})
).rejects.toThrowErrorMatchingInlineSnapshot(
`"Unknown font \`Unknown Font\`"`
Expand All @@ -240,6 +248,7 @@ describe('@next/font/google loader', () => {
emitFontFile: jest.fn(),
resolve: jest.fn(),
fs: {} as any,
isServer: true,
})
).rejects.toThrowErrorMatchingInlineSnapshot(`
"Unknown weight \`123\` for font \`Inter\`.
Expand All @@ -256,6 +265,7 @@ describe('@next/font/google loader', () => {
emitFontFile: jest.fn(),
resolve: jest.fn(),
fs: {} as any,
isServer: true,
})
).rejects.toThrowErrorMatchingInlineSnapshot(`
"Missing weight for font \`Abel\`.
Expand All @@ -272,6 +282,7 @@ describe('@next/font/google loader', () => {
emitFontFile: jest.fn(),
resolve: jest.fn(),
fs: {} as any,
isServer: true,
})
).rejects.toThrowErrorMatchingInlineSnapshot(`
"Unknown style \`normal\` for font \`Molle\`.
Expand All @@ -288,6 +299,7 @@ describe('@next/font/google loader', () => {
emitFontFile: jest.fn(),
resolve: jest.fn(),
fs: {} as any,
isServer: true,
})
).rejects.toThrowErrorMatchingInlineSnapshot(`
"Invalid display value \`invalid\` for font \`Inter\`.
Expand All @@ -304,6 +316,7 @@ describe('@next/font/google loader', () => {
emitFontFile: jest.fn(),
resolve: jest.fn(),
fs: {} as any,
isServer: true,
})
).rejects.toThrowErrorMatchingInlineSnapshot(
`"Axes can only be defined for variable fonts"`
Expand All @@ -319,6 +332,7 @@ describe('@next/font/google loader', () => {
emitFontFile: jest.fn(),
resolve: jest.fn(),
fs: {} as any,
isServer: true,
})
).rejects.toThrowErrorMatchingInlineSnapshot(
`"Font \`Lora\` has no definable \`axes\`"`
Expand All @@ -334,6 +348,7 @@ describe('@next/font/google loader', () => {
emitFontFile: jest.fn(),
resolve: jest.fn(),
fs: {} as any,
isServer: true,
})
).rejects.toThrowErrorMatchingInlineSnapshot(`
"Invalid axes value for font \`Inter\`, expected an array of axes.
Expand All @@ -350,6 +365,7 @@ describe('@next/font/google loader', () => {
emitFontFile: jest.fn(),
resolve: jest.fn(),
fs: {} as any,
isServer: true,
})
).rejects.toThrowErrorMatchingInlineSnapshot(`
"Invalid axes value \`INVALID\` for font \`Roboto Flex\`.
Expand Down
8 changes: 8 additions & 0 deletions test/unit/local-font-loader.test.ts
Expand Up @@ -3,6 +3,7 @@ import loader from '@next/font/local/loader'
describe('@next/font/local', () => {
describe('generated CSS', () => {
test('Default CSS', async () => {
// @ts-expect-error
const { css } = await loader({
functionName: '',
data: [{ src: './my-font.woff2' }],
Expand All @@ -24,6 +25,7 @@ describe('@next/font/local', () => {
})

test('Weight and style', async () => {
// @ts-expect-error
const { css } = await loader({
functionName: '',
data: [{ src: './my-font.woff2', weight: '100 900', style: 'italic' }],
Expand All @@ -47,6 +49,7 @@ describe('@next/font/local', () => {
})

test('Other properties', async () => {
// @ts-expect-error
const { css } = await loader({
functionName: '',
data: [
Expand Down Expand Up @@ -81,6 +84,7 @@ describe('@next/font/local', () => {
describe('Errors', () => {
test('Not using default export', async () => {
await expect(
// @ts-expect-error
loader({
functionName: 'Named',
data: [],
Expand All @@ -96,6 +100,7 @@ describe('@next/font/local', () => {

test('Missing src', async () => {
await expect(
// @ts-expect-error
loader({
functionName: '',
data: [],
Expand All @@ -111,6 +116,7 @@ describe('@next/font/local', () => {

test('Invalid file extension', async () => {
await expect(
// @ts-expect-error
loader({
functionName: '',
data: [{ src: './font/font-file.abc' }],
Expand All @@ -126,6 +132,7 @@ describe('@next/font/local', () => {

test('Invalid display value', async () => {
await expect(
// @ts-expect-error
loader({
functionName: '',
data: [{ src: './font-file.woff2', display: 'invalid' }],
Expand All @@ -142,6 +149,7 @@ describe('@next/font/local', () => {

test('Invalid declaration', async () => {
await expect(
// @ts-expect-error
loader({
functionName: '',
data: [
Expand Down

0 comments on commit ef7de2a

Please sign in to comment.