Remove experimental fontLoaders option from next.config.js (#46886)
Currently there's an experimental option in `next.config.js` that lets you define default subset(s) to preload for all your fonts. [docs](https://nextjs.org/docs/basic-features/font-optimization#specifying-a-subset)
Over time we haven't seen much use of this option, and we are defining the subsets in the font function call in all our examples/docs. Imo it would be fine to drop this option.
This PR removes that experimental option. If you happen to use it you'll get a build error with [a link](f67af163cd/errors/google-fonts-missing-subsets.md
).
Next step (breaking change for next major) would probably be to remove the preload and subsets properties from `next/font/google` calls, and just have something like [`preloadSubsets´](https://vercel.slack.com/archives/C8EAN8A94/p1674868993169559?thread_ts=1674707555.461809&cid=C8EAN8A94) that is required.
This commit is contained in:
parent
49e8f2bbbf
commit
cb729c1087
34 changed files with 129 additions and 276 deletions
|
@ -117,29 +117,10 @@ export default function Home() {
|
||||||
|
|
||||||
Google Fonts are automatically [subset](https://fonts.google.com/knowledge/glossary/subsetting). This reduces the size of the font file and improves performance. You'll need to define which of these subsets you want to preload. Failing to specify any subsets while [`preload`](/docs/api-reference/next/font.md#preload) is true will result in a warning.
|
Google Fonts are automatically [subset](https://fonts.google.com/knowledge/glossary/subsetting). This reduces the size of the font file and improves performance. You'll need to define which of these subsets you want to preload. Failing to specify any subsets while [`preload`](/docs/api-reference/next/font.md#preload) is true will result in a warning.
|
||||||
|
|
||||||
This can be done in 2 ways:
|
```js
|
||||||
|
// pages/_app.js
|
||||||
- On a font per font basis by adding it to the function call
|
const inter = Inter({ subsets: ['latin'] })
|
||||||
|
```
|
||||||
```js
|
|
||||||
// pages/_app.js
|
|
||||||
const inter = Inter({ subsets: ['latin'] })
|
|
||||||
```
|
|
||||||
|
|
||||||
- Globally for all your fonts in your `next.config.js`
|
|
||||||
|
|
||||||
```js
|
|
||||||
// next.config.js
|
|
||||||
module.exports = {
|
|
||||||
experimental: {
|
|
||||||
fontLoaders: [
|
|
||||||
{ loader: 'next/font/google', options: { subsets: ['latin'] } },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
- If both are configured, the subset in the function call is used.
|
|
||||||
|
|
||||||
View the [Font API Reference](/docs/api-reference/next/font.md#nextfontgoogle) for more information.
|
View the [Font API Reference](/docs/api-reference/next/font.md#nextfontgoogle) for more information.
|
||||||
|
|
||||||
|
|
|
@ -8,26 +8,11 @@ Preload is enabled for a font that is missing a specified subset.
|
||||||
|
|
||||||
##### Specify which subsets to preload for that font.
|
##### Specify which subsets to preload for that font.
|
||||||
|
|
||||||
- On a font per font basis by adding it to the function call
|
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const inter = Inter({ subsets: ['latin'] })
|
const inter = Inter({ subsets: ['latin'] })
|
||||||
```
|
```
|
||||||
|
|
||||||
- Globally for all your fonts
|
Note: previously it was possible to specify default subsets in your `next.config.js` with the `experimental.fontLoaders` option, but this is no longer supported.
|
||||||
|
|
||||||
```js
|
|
||||||
// next.config.js
|
|
||||||
module.exports = {
|
|
||||||
experimental: {
|
|
||||||
fontLoaders: [
|
|
||||||
{ loader: 'next/font/google', options: { subsets: ['latin'] } },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
If both are configured, the subset in the function call is used.
|
|
||||||
|
|
||||||
##### Disable preloading for that font
|
##### Disable preloading for that font
|
||||||
|
|
||||||
|
|
|
@ -126,8 +126,13 @@ describe('next/font/google loader', () => {
|
||||||
})
|
})
|
||||||
const { css } = await nextFontGoogleFontLoader({
|
const { css } = await nextFontGoogleFontLoader({
|
||||||
functionName,
|
functionName,
|
||||||
data: [{ adjustFontFallback: false, ...fontFunctionArguments }],
|
data: [
|
||||||
config: { subsets: [] },
|
{
|
||||||
|
adjustFontFallback: false,
|
||||||
|
subsets: [],
|
||||||
|
...fontFunctionArguments,
|
||||||
|
},
|
||||||
|
],
|
||||||
emitFontFile: jest.fn(),
|
emitFontFile: jest.fn(),
|
||||||
resolve: jest.fn(),
|
resolve: jest.fn(),
|
||||||
loaderContext: {} as any,
|
loaderContext: {} as any,
|
||||||
|
|
|
@ -28,7 +28,6 @@ function escapeStringRegexp(str: string) {
|
||||||
const nextFontGoogleFontLoader: FontLoader = async ({
|
const nextFontGoogleFontLoader: FontLoader = async ({
|
||||||
functionName,
|
functionName,
|
||||||
data,
|
data,
|
||||||
config,
|
|
||||||
emitFontFile,
|
emitFontFile,
|
||||||
isDev,
|
isDev,
|
||||||
isServer,
|
isServer,
|
||||||
|
@ -44,7 +43,7 @@ const nextFontGoogleFontLoader: FontLoader = async ({
|
||||||
adjustFontFallback,
|
adjustFontFallback,
|
||||||
variable,
|
variable,
|
||||||
subsets,
|
subsets,
|
||||||
} = validateGoogleFontFunctionCall(functionName, data[0], config)
|
} = validateGoogleFontFunctionCall(functionName, data[0])
|
||||||
|
|
||||||
// Validate and get the font axes required to generated the URL
|
// Validate and get the font axes required to generated the URL
|
||||||
const fontAxes = getFontAxes(
|
const fontAxes = getFontAxes(
|
||||||
|
|
|
@ -5,8 +5,7 @@ describe('validateFontFunctionCall errors', () => {
|
||||||
expect(() =>
|
expect(() =>
|
||||||
validateGoogleFontFunctionCall(
|
validateGoogleFontFunctionCall(
|
||||||
'', // default import
|
'', // default import
|
||||||
undefined,
|
undefined
|
||||||
{ subsets: [] }
|
|
||||||
)
|
)
|
||||||
).toThrowErrorMatchingInlineSnapshot(
|
).toThrowErrorMatchingInlineSnapshot(
|
||||||
`"next/font/google has no default export"`
|
`"next/font/google has no default export"`
|
||||||
|
@ -15,19 +14,16 @@ describe('validateFontFunctionCall errors', () => {
|
||||||
|
|
||||||
test('Unknown font', () => {
|
test('Unknown font', () => {
|
||||||
expect(() =>
|
expect(() =>
|
||||||
validateGoogleFontFunctionCall('Unknown_Font', undefined, { subsets: [] })
|
validateGoogleFontFunctionCall('Unknown_Font', undefined)
|
||||||
).toThrowErrorMatchingInlineSnapshot(`"Unknown font \`Unknown Font\`"`)
|
).toThrowErrorMatchingInlineSnapshot(`"Unknown font \`Unknown Font\`"`)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('Unknown weight', () => {
|
test('Unknown weight', () => {
|
||||||
expect(() =>
|
expect(() =>
|
||||||
validateGoogleFontFunctionCall(
|
validateGoogleFontFunctionCall('Inter', {
|
||||||
'Inter',
|
weight: '123',
|
||||||
{ weight: '123' },
|
subsets: ['latin'],
|
||||||
{
|
})
|
||||||
subsets: [],
|
|
||||||
}
|
|
||||||
)
|
|
||||||
).toThrowErrorMatchingInlineSnapshot(`
|
).toThrowErrorMatchingInlineSnapshot(`
|
||||||
"Unknown weight \`123\` for font \`Inter\`.
|
"Unknown weight \`123\` for font \`Inter\`.
|
||||||
Available weights: \`100\`, \`200\`, \`300\`, \`400\`, \`500\`, \`600\`, \`700\`, \`800\`, \`900\`, \`variable\`"
|
Available weights: \`100\`, \`200\`, \`300\`, \`400\`, \`500\`, \`600\`, \`700\`, \`800\`, \`900\`, \`variable\`"
|
||||||
|
@ -35,7 +31,7 @@ describe('validateFontFunctionCall errors', () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
test('Missing weight for non variable font', () => {
|
test('Missing weight for non variable font', () => {
|
||||||
expect(() => validateGoogleFontFunctionCall('Abel', {}, { subsets: [] }))
|
expect(() => validateGoogleFontFunctionCall('Abel', { subsets: ['latin'] }))
|
||||||
.toThrowErrorMatchingInlineSnapshot(`
|
.toThrowErrorMatchingInlineSnapshot(`
|
||||||
"Missing weight for font \`Abel\`.
|
"Missing weight for font \`Abel\`.
|
||||||
Available weights: \`400\`"
|
Available weights: \`400\`"
|
||||||
|
@ -44,13 +40,11 @@ describe('validateFontFunctionCall errors', () => {
|
||||||
|
|
||||||
test('Unknown style', () => {
|
test('Unknown style', () => {
|
||||||
expect(() =>
|
expect(() =>
|
||||||
validateGoogleFontFunctionCall(
|
validateGoogleFontFunctionCall('Molle', {
|
||||||
'Molle',
|
weight: '400',
|
||||||
{ weight: '400', style: 'normal' },
|
style: 'normal',
|
||||||
{
|
subsets: ['latin'],
|
||||||
subsets: [],
|
})
|
||||||
}
|
|
||||||
)
|
|
||||||
).toThrowErrorMatchingInlineSnapshot(`
|
).toThrowErrorMatchingInlineSnapshot(`
|
||||||
"Unknown style \`normal\` for font \`Molle\`.
|
"Unknown style \`normal\` for font \`Molle\`.
|
||||||
Available styles: \`italic\`"
|
Available styles: \`italic\`"
|
||||||
|
@ -59,13 +53,10 @@ describe('validateFontFunctionCall errors', () => {
|
||||||
|
|
||||||
test('Invalid display value', () => {
|
test('Invalid display value', () => {
|
||||||
expect(() =>
|
expect(() =>
|
||||||
validateGoogleFontFunctionCall(
|
validateGoogleFontFunctionCall('Inter', {
|
||||||
'Inter',
|
display: 'Invalid',
|
||||||
{ display: 'Invalid' },
|
subsets: ['latin'],
|
||||||
{
|
})
|
||||||
subsets: [],
|
|
||||||
}
|
|
||||||
)
|
|
||||||
).toThrowErrorMatchingInlineSnapshot(`
|
).toThrowErrorMatchingInlineSnapshot(`
|
||||||
"Invalid display value \`Invalid\` for font \`Inter\`.
|
"Invalid display value \`Invalid\` for font \`Inter\`.
|
||||||
Available display values: \`auto\`, \`block\`, \`swap\`, \`fallback\`, \`optional\`"
|
Available display values: \`auto\`, \`block\`, \`swap\`, \`fallback\`, \`optional\`"
|
||||||
|
@ -74,13 +65,10 @@ describe('validateFontFunctionCall errors', () => {
|
||||||
|
|
||||||
test('Variable in weight array', async () => {
|
test('Variable in weight array', async () => {
|
||||||
expect(() =>
|
expect(() =>
|
||||||
validateGoogleFontFunctionCall(
|
validateGoogleFontFunctionCall('Inter', {
|
||||||
'Inter',
|
weight: ['100', 'variable'],
|
||||||
{ weight: ['100', 'variable'] },
|
subsets: ['latin'],
|
||||||
{
|
})
|
||||||
subsets: [],
|
|
||||||
}
|
|
||||||
)
|
|
||||||
).toThrowErrorMatchingInlineSnapshot(
|
).toThrowErrorMatchingInlineSnapshot(
|
||||||
`"Unexpected \`variable\` in weight array for font \`Inter\`. You only need \`variable\`, it includes all available weights."`
|
`"Unexpected \`variable\` in weight array for font \`Inter\`. You only need \`variable\`, it includes all available weights."`
|
||||||
)
|
)
|
||||||
|
@ -88,28 +76,7 @@ describe('validateFontFunctionCall errors', () => {
|
||||||
|
|
||||||
test('Invalid subset in call', async () => {
|
test('Invalid subset in call', async () => {
|
||||||
expect(() =>
|
expect(() =>
|
||||||
validateGoogleFontFunctionCall(
|
validateGoogleFontFunctionCall('Inter', { subsets: ['latin', 'oops'] })
|
||||||
'Inter',
|
|
||||||
{ subsets: ['latin', 'oops'] },
|
|
||||||
{
|
|
||||||
subsets: [],
|
|
||||||
}
|
|
||||||
)
|
|
||||||
).toThrowErrorMatchingInlineSnapshot(`
|
|
||||||
"Unknown subset \`oops\` for font \`Inter\`.
|
|
||||||
Available subsets: \`cyrillic\`, \`cyrillic-ext\`, \`greek\`, \`greek-ext\`, \`latin\`, \`latin-ext\`, \`vietnamese\`"
|
|
||||||
`)
|
|
||||||
})
|
|
||||||
|
|
||||||
test('Invalid subset in config', async () => {
|
|
||||||
expect(() =>
|
|
||||||
validateGoogleFontFunctionCall(
|
|
||||||
'Inter',
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
subsets: ['latin', 'oops'],
|
|
||||||
}
|
|
||||||
)
|
|
||||||
).toThrowErrorMatchingInlineSnapshot(`
|
).toThrowErrorMatchingInlineSnapshot(`
|
||||||
"Unknown subset \`oops\` for font \`Inter\`.
|
"Unknown subset \`oops\` for font \`Inter\`.
|
||||||
Available subsets: \`cyrillic\`, \`cyrillic-ext\`, \`greek\`, \`greek-ext\`, \`latin\`, \`latin-ext\`, \`vietnamese\`"
|
Available subsets: \`cyrillic\`, \`cyrillic-ext\`, \`greek\`, \`greek-ext\`, \`latin\`, \`latin-ext\`, \`vietnamese\`"
|
||||||
|
@ -117,22 +84,22 @@ describe('validateFontFunctionCall errors', () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
test('Missing subsets in config and call', async () => {
|
test('Missing subsets in config and call', async () => {
|
||||||
expect(() =>
|
expect(() => validateGoogleFontFunctionCall('Inter', {}))
|
||||||
validateGoogleFontFunctionCall('Inter', {}, {})
|
.toThrowErrorMatchingInlineSnapshot(`
|
||||||
).toThrowErrorMatchingInlineSnapshot(
|
"Preload is enabled but no subsets were specified for font \`Inter\`. Please specify subsets or disable preloading if your intended subset can't be preloaded.
|
||||||
`"Missing selected subsets for font \`Inter\`. Please specify subsets in the function call or in your \`next.config.js\`. Read more: https://nextjs.org/docs/messages/google-fonts-missing-subsets"`
|
Available subsets: \`cyrillic\`, \`cyrillic-ext\`, \`greek\`, \`greek-ext\`, \`latin\`, \`latin-ext\`, \`vietnamese\`
|
||||||
)
|
|
||||||
|
Read more: https://nextjs.org/docs/messages/google-fonts-missing-subsets"
|
||||||
|
`)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('Setting axes on non variable font', async () => {
|
test('Setting axes on non variable font', async () => {
|
||||||
expect(() =>
|
expect(() =>
|
||||||
validateGoogleFontFunctionCall(
|
validateGoogleFontFunctionCall('Abel', {
|
||||||
'Abel',
|
weight: '400',
|
||||||
{ weight: '400', axes: [] },
|
axes: [],
|
||||||
{
|
subsets: ['latin'],
|
||||||
subsets: [],
|
})
|
||||||
}
|
|
||||||
)
|
|
||||||
).toThrowErrorMatchingInlineSnapshot(
|
).toThrowErrorMatchingInlineSnapshot(
|
||||||
`"Axes can only be defined for variable fonts"`
|
`"Axes can only be defined for variable fonts"`
|
||||||
)
|
)
|
||||||
|
|
|
@ -20,8 +20,7 @@ type FontOptions = {
|
||||||
*/
|
*/
|
||||||
export function validateGoogleFontFunctionCall(
|
export function validateGoogleFontFunctionCall(
|
||||||
functionName: string,
|
functionName: string,
|
||||||
fontFunctionArgument: any,
|
fontFunctionArgument: any
|
||||||
config: any
|
|
||||||
): FontOptions {
|
): FontOptions {
|
||||||
let {
|
let {
|
||||||
weight,
|
weight,
|
||||||
|
@ -32,11 +31,8 @@ export function validateGoogleFontFunctionCall(
|
||||||
fallback,
|
fallback,
|
||||||
adjustFontFallback = true,
|
adjustFontFallback = true,
|
||||||
variable,
|
variable,
|
||||||
subsets: callSubsets,
|
subsets,
|
||||||
} = fontFunctionArgument || ({} as any)
|
} = fontFunctionArgument || ({} as any)
|
||||||
// Get the subsets defined for the font from either next.config.js or the function call. If both are present, pick the function call subsets.
|
|
||||||
const subsets = callSubsets ?? config?.subsets ?? []
|
|
||||||
|
|
||||||
if (functionName === '') {
|
if (functionName === '') {
|
||||||
nextFontError(`next/font/google has no default export`)
|
nextFontError(`next/font/google has no default export`)
|
||||||
}
|
}
|
||||||
|
@ -52,10 +48,12 @@ export function validateGoogleFontFunctionCall(
|
||||||
if (availableSubsets.length === 0) {
|
if (availableSubsets.length === 0) {
|
||||||
// If the font doesn't have any preloadeable subsets, disable preload
|
// If the font doesn't have any preloadeable subsets, disable preload
|
||||||
preload = false
|
preload = false
|
||||||
} else {
|
} else if (preload) {
|
||||||
if (preload && !callSubsets && !config?.subsets) {
|
if (!subsets) {
|
||||||
nextFontError(
|
nextFontError(
|
||||||
`Missing selected subsets for font \`${fontFamily}\`. Please specify subsets in the function call or in your \`next.config.js\`. Read more: https://nextjs.org/docs/messages/google-fonts-missing-subsets`
|
`Preload is enabled but no subsets were specified for font \`${fontFamily}\`. Please specify subsets or disable preloading if your intended subset can't be preloaded.\nAvailable subsets: ${formatAvailableValues(
|
||||||
|
availableSubsets
|
||||||
|
)}\n\nRead more: https://nextjs.org/docs/messages/google-fonts-missing-subsets`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
subsets.forEach((subset: string) => {
|
subsets.forEach((subset: string) => {
|
||||||
|
|
|
@ -6,7 +6,6 @@ describe('next/font/local loader', () => {
|
||||||
const { css } = await nextFontLocalFontLoader({
|
const { css } = await nextFontLocalFontLoader({
|
||||||
functionName: '',
|
functionName: '',
|
||||||
data: [{ src: './my-font.woff2' }],
|
data: [{ src: './my-font.woff2' }],
|
||||||
config: {},
|
|
||||||
emitFontFile: () => '/_next/static/media/my-font.woff2',
|
emitFontFile: () => '/_next/static/media/my-font.woff2',
|
||||||
resolve: jest.fn(),
|
resolve: jest.fn(),
|
||||||
isDev: false,
|
isDev: false,
|
||||||
|
@ -33,7 +32,6 @@ describe('next/font/local loader', () => {
|
||||||
const { css } = await nextFontLocalFontLoader({
|
const { css } = await nextFontLocalFontLoader({
|
||||||
functionName: '',
|
functionName: '',
|
||||||
data: [{ src: './my-font.woff2', weight: '100 900', style: 'italic' }],
|
data: [{ src: './my-font.woff2', weight: '100 900', style: 'italic' }],
|
||||||
config: {},
|
|
||||||
emitFontFile: () => '/_next/static/media/my-font.woff2',
|
emitFontFile: () => '/_next/static/media/my-font.woff2',
|
||||||
resolve: jest.fn(),
|
resolve: jest.fn(),
|
||||||
isDev: false,
|
isDev: false,
|
||||||
|
@ -70,7 +68,6 @@ describe('next/font/local loader', () => {
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
config: {},
|
|
||||||
emitFontFile: () => '/_next/static/media/my-font.woff2',
|
emitFontFile: () => '/_next/static/media/my-font.woff2',
|
||||||
resolve: jest.fn(),
|
resolve: jest.fn(),
|
||||||
isDev: false,
|
isDev: false,
|
||||||
|
@ -123,7 +120,6 @@ describe('next/font/local loader', () => {
|
||||||
adjustFontFallback: false,
|
adjustFontFallback: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
config: {},
|
|
||||||
emitFontFile: () => `/_next/static/media/my-font.woff2`,
|
emitFontFile: () => `/_next/static/media/my-font.woff2`,
|
||||||
resolve: jest.fn(),
|
resolve: jest.fn(),
|
||||||
isDev: false,
|
isDev: false,
|
||||||
|
@ -195,7 +191,6 @@ describe('next/font/local loader', () => {
|
||||||
adjustFontFallback: false,
|
adjustFontFallback: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
config: {},
|
|
||||||
emitFontFile: () => `/_next/static/media/my-font.woff2`,
|
emitFontFile: () => `/_next/static/media/my-font.woff2`,
|
||||||
resolve: jest.fn(),
|
resolve: jest.fn(),
|
||||||
isDev: false,
|
isDev: false,
|
||||||
|
|
1
packages/next/font/index.d.ts
vendored
1
packages/next/font/index.d.ts
vendored
|
@ -10,7 +10,6 @@ export type FontLoader = (options: {
|
||||||
functionName: string
|
functionName: string
|
||||||
variableName: string
|
variableName: string
|
||||||
data: any[]
|
data: any[]
|
||||||
config: any
|
|
||||||
emitFontFile: (
|
emitFontFile: (
|
||||||
content: Buffer,
|
content: Buffer,
|
||||||
ext: string,
|
ext: string,
|
||||||
|
|
|
@ -186,50 +186,28 @@ export const css = curry(async function css(
|
||||||
const localLoader = require.resolve(
|
const localLoader = require.resolve(
|
||||||
'next/dist/compiled/@next/font/local/loader'
|
'next/dist/compiled/@next/font/local/loader'
|
||||||
)
|
)
|
||||||
const googleLoaderOptions =
|
const nextFontLoaders: Array<[string | RegExp, string, any?]> = [
|
||||||
ctx.experimental?.fontLoaders?.find(
|
[require.resolve('next/font/google/target.css'), googleLoader],
|
||||||
(loaderConfig) =>
|
|
||||||
loaderConfig.loader === '@next/font/google' ||
|
|
||||||
loaderConfig.loader === 'next/font/google'
|
|
||||||
)?.options ?? {}
|
|
||||||
const fontLoaders: Array<[string | RegExp, string, any?]> = [
|
|
||||||
[
|
|
||||||
require.resolve('next/font/google/target.css'),
|
|
||||||
googleLoader,
|
|
||||||
googleLoaderOptions,
|
|
||||||
],
|
|
||||||
[require.resolve('next/font/local/target.css'), localLoader],
|
[require.resolve('next/font/local/target.css'), localLoader],
|
||||||
|
|
||||||
// TODO: remove this in the next major version
|
// TODO: remove this in the next major version
|
||||||
[
|
[/node_modules[\\/]@next[\\/]font[\\/]google[\\/]target.css/, googleLoader],
|
||||||
/node_modules[\\/]@next[\\/]font[\\/]google[\\/]target.css/,
|
|
||||||
googleLoader,
|
|
||||||
googleLoaderOptions,
|
|
||||||
],
|
|
||||||
[/node_modules[\\/]@next[\\/]font[\\/]local[\\/]target.css/, localLoader],
|
[/node_modules[\\/]@next[\\/]font[\\/]local[\\/]target.css/, localLoader],
|
||||||
]
|
]
|
||||||
|
|
||||||
fontLoaders.forEach(
|
nextFontLoaders.forEach(([fontLoaderTarget, fontLoaderPath]) => {
|
||||||
([fontLoaderTarget, fontLoaderPath, fontLoaderOptions]) => {
|
// Matches the resolved font loaders noop files to run next-font-loader
|
||||||
// Matches the resolved font loaders noop files to run next-font-loader
|
fns.push(
|
||||||
fns.push(
|
loader({
|
||||||
loader({
|
oneOf: [
|
||||||
oneOf: [
|
markRemovable({
|
||||||
markRemovable({
|
sideEffects: false,
|
||||||
sideEffects: false,
|
test: fontLoaderTarget,
|
||||||
test: fontLoaderTarget,
|
use: getNextFontLoader(ctx, lazyPostCSSInitializer, fontLoaderPath),
|
||||||
use: getNextFontLoader(
|
}),
|
||||||
ctx,
|
],
|
||||||
lazyPostCSSInitializer,
|
})
|
||||||
fontLoaderPath,
|
)
|
||||||
fontLoaderOptions
|
})
|
||||||
),
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// CSS cannot be imported in _document. This comes before everything because
|
// CSS cannot be imported in _document. This comes before everything because
|
||||||
// global CSS nor CSS modules work in said file.
|
// global CSS nor CSS modules work in said file.
|
||||||
|
|
|
@ -6,8 +6,7 @@ import { cssFileResolve } from './file-resolve'
|
||||||
export function getNextFontLoader(
|
export function getNextFontLoader(
|
||||||
ctx: ConfigurationContext,
|
ctx: ConfigurationContext,
|
||||||
postcss: any,
|
postcss: any,
|
||||||
fontLoaderPath: string,
|
fontLoaderPath: string
|
||||||
fontLoaderOptions: any
|
|
||||||
): webpack.RuleSetUseItem[] {
|
): webpack.RuleSetUseItem[] {
|
||||||
const loaders: webpack.RuleSetUseItem[] = []
|
const loaders: webpack.RuleSetUseItem[] = []
|
||||||
|
|
||||||
|
@ -64,7 +63,6 @@ export function getNextFontLoader(
|
||||||
isServer: ctx.isServer,
|
isServer: ctx.isServer,
|
||||||
assetPrefix: ctx.assetPrefix,
|
assetPrefix: ctx.assetPrefix,
|
||||||
fontLoaderPath,
|
fontLoaderPath,
|
||||||
fontLoaderOptions,
|
|
||||||
postcss,
|
postcss,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,16 +1,15 @@
|
||||||
import type { FontLoader } from '../../../../../font'
|
import type { FontLoader } from '../../../../../font'
|
||||||
|
|
||||||
import { promises as fs } from 'fs'
|
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import chalk from 'next/dist/compiled/chalk'
|
import chalk from 'next/dist/compiled/chalk'
|
||||||
import loaderUtils from 'next/dist/compiled/loader-utils3'
|
import loaderUtils from 'next/dist/compiled/loader-utils3'
|
||||||
import postcssNextFontPlugin from './postcss-next-font'
|
import postcssNextFontPlugin from './postcss-next-font'
|
||||||
import { promisify } from 'util'
|
import { promisify } from 'util'
|
||||||
import { CONFIG_FILES } from '../../../../shared/lib/constants'
|
|
||||||
|
|
||||||
export default async function nextFontLoader(this: any) {
|
export default async function nextFontLoader(this: any) {
|
||||||
const fontLoaderSpan = this.currentTraceSpan.traceChild('next-font-loader')
|
const nextFontLoaderSpan =
|
||||||
return fontLoaderSpan.traceAsyncFn(async () => {
|
this.currentTraceSpan.traceChild('next-font-loader')
|
||||||
|
return nextFontLoaderSpan.traceAsyncFn(async () => {
|
||||||
const callback = this.async()
|
const callback = this.async()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -47,28 +46,9 @@ export default async function nextFontLoader(this: any) {
|
||||||
isServer,
|
isServer,
|
||||||
assetPrefix,
|
assetPrefix,
|
||||||
fontLoaderPath,
|
fontLoaderPath,
|
||||||
fontLoaderOptions,
|
|
||||||
postcss: getPostcss,
|
postcss: getPostcss,
|
||||||
} = this.getOptions()
|
} = this.getOptions()
|
||||||
|
|
||||||
const nextConfigPaths = CONFIG_FILES.map((config) =>
|
|
||||||
path.join(this.rootContext, config)
|
|
||||||
)
|
|
||||||
// Add next.config.js as a dependency, loaders must rerun in case options changed
|
|
||||||
await Promise.all(
|
|
||||||
nextConfigPaths.map(async (configPath) => {
|
|
||||||
const hasConfig = await fs.access(configPath).then(
|
|
||||||
() => true,
|
|
||||||
() => false
|
|
||||||
)
|
|
||||||
if (hasConfig) {
|
|
||||||
this.addDependency(configPath)
|
|
||||||
} else {
|
|
||||||
this.addMissingDependency(configPath)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Emit font files to .next/static/media as [hash].[ext].
|
* Emit font files to .next/static/media as [hash].[ext].
|
||||||
*
|
*
|
||||||
|
@ -111,7 +91,6 @@ export default async function nextFontLoader(this: any) {
|
||||||
functionName,
|
functionName,
|
||||||
variableName,
|
variableName,
|
||||||
data,
|
data,
|
||||||
config: fontLoaderOptions,
|
|
||||||
emitFontFile,
|
emitFontFile,
|
||||||
resolve: (src: string) =>
|
resolve: (src: string) =>
|
||||||
promisify(this.resolve)(
|
promisify(this.resolve)(
|
||||||
|
|
|
@ -420,20 +420,6 @@ const configSchema = {
|
||||||
workerThreads: {
|
workerThreads: {
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
},
|
},
|
||||||
fontLoaders: {
|
|
||||||
items: {
|
|
||||||
additionalProperties: false,
|
|
||||||
properties: {
|
|
||||||
loader: {
|
|
||||||
type: 'string',
|
|
||||||
},
|
|
||||||
options: {},
|
|
||||||
},
|
|
||||||
type: 'object',
|
|
||||||
required: ['loader'],
|
|
||||||
},
|
|
||||||
type: 'array',
|
|
||||||
} as any,
|
|
||||||
webVitalsAttribution: {
|
webVitalsAttribution: {
|
||||||
type: 'array',
|
type: 'array',
|
||||||
items: {
|
items: {
|
||||||
|
|
|
@ -194,8 +194,6 @@ export interface ExperimentalConfig {
|
||||||
*/
|
*/
|
||||||
serverComponentsExternalPackages?: string[]
|
serverComponentsExternalPackages?: string[]
|
||||||
|
|
||||||
fontLoaders?: Array<{ loader: string; options?: any }>
|
|
||||||
|
|
||||||
webVitalsAttribution?: Array<typeof WEB_VITALS[number]>
|
webVitalsAttribution?: Array<typeof WEB_VITALS[number]>
|
||||||
|
|
||||||
turbo?: ExperimentalTurboOptions
|
turbo?: ExperimentalTurboOptions
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
experimental: {
|
experimental: {
|
||||||
appDir: true,
|
appDir: true,
|
||||||
fontLoaders: [],
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
import { Inter, Roboto } from '@next/font/google'
|
import { Inter, Roboto } from '@next/font/google'
|
||||||
const inter = Inter({ weight: '900', display: 'swap', preload: false })
|
const inter = Inter({
|
||||||
|
weight: '900',
|
||||||
|
display: 'swap',
|
||||||
|
preload: false,
|
||||||
|
subsets: ['latin'],
|
||||||
|
})
|
||||||
const roboto = Roboto({
|
const roboto = Roboto({
|
||||||
weight: '100',
|
weight: '100',
|
||||||
style: 'italic',
|
style: 'italic',
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
module.exports = {
|
|
||||||
experimental: {
|
|
||||||
fontLoaders: [
|
|
||||||
{
|
|
||||||
loader: '@next/font/google',
|
|
||||||
options: { subsets: ['latin'] },
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
}
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Open_Sans } from '@next/font/google'
|
import { Open_Sans } from '@next/font/google'
|
||||||
const openSans = Open_Sans({ variable: '--open-sans' })
|
const openSans = Open_Sans({ variable: '--open-sans', subsets: ['latin'] })
|
||||||
|
|
||||||
function MyApp({ Component, pageProps }) {
|
function MyApp({ Component, pageProps }) {
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { Nabla } from '@next/font/google'
|
import { Nabla } from '@next/font/google'
|
||||||
|
|
||||||
const nabla = Nabla()
|
const nabla = Nabla({ subsets: ['latin'] })
|
||||||
|
|
||||||
export default function VariableFontWithoutWeightRange() {
|
export default function VariableFontWithoutWeightRange() {
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -1,18 +1,20 @@
|
||||||
import { Fira_Code, Roboto } from '@next/font/google'
|
import { Fira_Code, Roboto } from '@next/font/google'
|
||||||
import localFont from '@next/font/local'
|
import localFont from '@next/font/local'
|
||||||
|
|
||||||
const firaCode = Fira_Code({ variable: '--fira-code' })
|
const firaCode = Fira_Code({ variable: '--fira-code', subsets: ['latin'] })
|
||||||
const roboto = Roboto({
|
const roboto = Roboto({
|
||||||
weight: '100',
|
weight: '100',
|
||||||
style: 'italic',
|
style: 'italic',
|
||||||
display: 'swap',
|
display: 'swap',
|
||||||
preload: true,
|
preload: true,
|
||||||
variable: '--roboto-100-italic',
|
variable: '--roboto-100-italic',
|
||||||
|
subsets: ['latin'],
|
||||||
})
|
})
|
||||||
const myFont = localFont({
|
const myFont = localFont({
|
||||||
src: '../fonts/my-font.woff2',
|
src: '../fonts/my-font.woff2',
|
||||||
preload: false,
|
preload: false,
|
||||||
variable: '--my-font',
|
variable: '--my-font',
|
||||||
|
subsets: ['latin'],
|
||||||
})
|
})
|
||||||
|
|
||||||
export default function WithFonts() {
|
export default function WithFonts() {
|
||||||
|
|
|
@ -4,6 +4,7 @@ const openSans = Open_Sans({
|
||||||
fallback: ['system-ui', 'Arial'],
|
fallback: ['system-ui', 'Arial'],
|
||||||
variable: '--open-sans',
|
variable: '--open-sans',
|
||||||
adjustFontFallback: false,
|
adjustFontFallback: false,
|
||||||
|
subsets: ['latin'],
|
||||||
})
|
})
|
||||||
|
|
||||||
const myFont = localFont({
|
const myFont = localFont({
|
||||||
|
|
|
@ -1,18 +1,27 @@
|
||||||
import { Fraunces, Indie_Flower, Roboto } from '@next/font/google'
|
import { Fraunces, Indie_Flower, Roboto } from '@next/font/google'
|
||||||
|
|
||||||
const indieFlower = Indie_Flower({ weight: '400', preload: false })
|
const indieFlower = Indie_Flower({
|
||||||
const fraunces = Fraunces({ weight: '400', preload: false })
|
weight: '400',
|
||||||
|
preload: false,
|
||||||
|
subsets: ['latin'],
|
||||||
|
})
|
||||||
|
const fraunces = Fraunces({ weight: '400', preload: false, subsets: ['latin'] })
|
||||||
|
|
||||||
const robotoMultiple = Roboto({
|
const robotoMultiple = Roboto({
|
||||||
weight: ['900', '100'],
|
weight: ['900', '100'],
|
||||||
style: ['normal', 'italic'],
|
style: ['normal', 'italic'],
|
||||||
|
subsets: ['latin'],
|
||||||
})
|
})
|
||||||
const frauncesMultiple = Fraunces({
|
const frauncesMultiple = Fraunces({
|
||||||
style: ['italic', 'normal'],
|
style: ['italic', 'normal'],
|
||||||
axes: ['SOFT', 'WONK', 'opsz'],
|
axes: ['SOFT', 'WONK', 'opsz'],
|
||||||
|
subsets: ['latin'],
|
||||||
})
|
})
|
||||||
|
|
||||||
const frauncesMultipleWeights = Fraunces({ weight: ['100', '400', '900'] })
|
const frauncesMultipleWeights = Fraunces({
|
||||||
|
weight: ['100', '400', '900'],
|
||||||
|
subsets: ['latin'],
|
||||||
|
})
|
||||||
|
|
||||||
export default function WithFonts() {
|
export default function WithFonts() {
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
import { Inter, Roboto } from 'next/font/google'
|
import { Inter, Roboto } from 'next/font/google'
|
||||||
const inter = Inter({ weight: '900', display: 'swap', preload: false })
|
const inter = Inter({
|
||||||
|
weight: '900',
|
||||||
|
display: 'swap',
|
||||||
|
preload: false,
|
||||||
|
subsets: ['latin'],
|
||||||
|
})
|
||||||
const roboto = Roboto({
|
const roboto = Roboto({
|
||||||
weight: '100',
|
weight: '100',
|
||||||
style: 'italic',
|
style: 'italic',
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
module.exports = {
|
|
||||||
experimental: {
|
|
||||||
fontLoaders: [
|
|
||||||
{
|
|
||||||
loader: 'next/font/google',
|
|
||||||
options: { subsets: ['latin'] },
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
}
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Open_Sans } from 'next/font/google'
|
import { Open_Sans } from 'next/font/google'
|
||||||
const openSans = Open_Sans({ variable: '--open-sans' })
|
const openSans = Open_Sans({ variable: '--open-sans', subsets: ['latin'] })
|
||||||
|
|
||||||
function MyApp({ Component, pageProps }) {
|
function MyApp({ Component, pageProps }) {
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { Nabla } from 'next/font/google'
|
import { Nabla } from 'next/font/google'
|
||||||
|
|
||||||
const nabla = Nabla()
|
const nabla = Nabla({ subsets: ['latin'] })
|
||||||
|
|
||||||
export default function VariableFontWithoutWeightRange() {
|
export default function VariableFontWithoutWeightRange() {
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
import { Fira_Code, Roboto } from 'next/font/google'
|
import { Fira_Code, Roboto } from 'next/font/google'
|
||||||
import localFont from 'next/font/local'
|
import localFont from 'next/font/local'
|
||||||
|
|
||||||
const firaCode = Fira_Code({ variable: '--fira-code' })
|
const firaCode = Fira_Code({ variable: '--fira-code', subsets: ['latin'] })
|
||||||
const roboto = Roboto({
|
const roboto = Roboto({
|
||||||
weight: '100',
|
weight: '100',
|
||||||
style: 'italic',
|
style: 'italic',
|
||||||
display: 'swap',
|
display: 'swap',
|
||||||
preload: true,
|
preload: true,
|
||||||
variable: '--roboto-100-italic',
|
variable: '--roboto-100-italic',
|
||||||
|
subsets: ['latin'],
|
||||||
})
|
})
|
||||||
const myFont = localFont({
|
const myFont = localFont({
|
||||||
src: '../fonts/my-font.woff2',
|
src: '../fonts/my-font.woff2',
|
||||||
|
|
|
@ -4,12 +4,14 @@ const openSans = Open_Sans({
|
||||||
fallback: ['system-ui', 'Arial'],
|
fallback: ['system-ui', 'Arial'],
|
||||||
variable: '--open-sans',
|
variable: '--open-sans',
|
||||||
adjustFontFallback: false,
|
adjustFontFallback: false,
|
||||||
|
subsets: ['latin'],
|
||||||
})
|
})
|
||||||
|
|
||||||
const myFont = localFont({
|
const myFont = localFont({
|
||||||
fallback: ['system-ui', 'Arial'],
|
fallback: ['system-ui', 'Arial'],
|
||||||
src: '../fonts/my-font.woff2',
|
src: '../fonts/my-font.woff2',
|
||||||
adjustFontFallback: false,
|
adjustFontFallback: false,
|
||||||
|
subsets: ['latin'],
|
||||||
})
|
})
|
||||||
|
|
||||||
export default function WithFonts() {
|
export default function WithFonts() {
|
||||||
|
|
|
@ -1,18 +1,27 @@
|
||||||
import { Fraunces, Indie_Flower, Roboto } from 'next/font/google'
|
import { Fraunces, Indie_Flower, Roboto } from 'next/font/google'
|
||||||
|
|
||||||
const indieFlower = Indie_Flower({ weight: '400', preload: false })
|
const indieFlower = Indie_Flower({
|
||||||
const fraunces = Fraunces({ weight: '400', preload: false })
|
weight: '400',
|
||||||
|
preload: false,
|
||||||
|
subsets: ['latin'],
|
||||||
|
})
|
||||||
|
const fraunces = Fraunces({ weight: '400', preload: false, subsets: ['latin'] })
|
||||||
|
|
||||||
const robotoMultiple = Roboto({
|
const robotoMultiple = Roboto({
|
||||||
weight: ['900', '100'],
|
weight: ['900', '100'],
|
||||||
style: ['normal', 'italic'],
|
style: ['normal', 'italic'],
|
||||||
|
subsets: ['latin'],
|
||||||
})
|
})
|
||||||
const frauncesMultiple = Fraunces({
|
const frauncesMultiple = Fraunces({
|
||||||
style: ['italic', 'normal'],
|
style: ['italic', 'normal'],
|
||||||
axes: ['SOFT', 'WONK', 'opsz'],
|
axes: ['SOFT', 'WONK', 'opsz'],
|
||||||
|
subsets: ['latin'],
|
||||||
})
|
})
|
||||||
|
|
||||||
const frauncesMultipleWeights = Fraunces({ weight: ['100', '400', '900'] })
|
const frauncesMultipleWeights = Fraunces({
|
||||||
|
weight: ['100', '400', '900'],
|
||||||
|
subsets: ['latin'],
|
||||||
|
})
|
||||||
|
|
||||||
export default function WithFonts() {
|
export default function WithFonts() {
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -31,9 +31,6 @@ describe('next/font', () => {
|
||||||
pages: new FileRef(join(__dirname, `${fixture}/pages`)),
|
pages: new FileRef(join(__dirname, `${fixture}/pages`)),
|
||||||
components: new FileRef(join(__dirname, `${fixture}/components`)),
|
components: new FileRef(join(__dirname, `${fixture}/components`)),
|
||||||
fonts: new FileRef(join(__dirname, `${fixture}/fonts`)),
|
fonts: new FileRef(join(__dirname, `${fixture}/fonts`)),
|
||||||
'next.config.js': new FileRef(
|
|
||||||
join(__dirname, `${fixture}/next.config.js`)
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
dependencies: {
|
dependencies: {
|
||||||
'@next/font': 'canary',
|
'@next/font': 'canary',
|
||||||
|
|
|
@ -33,9 +33,6 @@ describe('next/font/google with-font-declarations-file', () => {
|
||||||
'my-font.woff2': new FileRef(
|
'my-font.woff2': new FileRef(
|
||||||
join(__dirname, 'with-font-declarations-file/my-font.woff2')
|
join(__dirname, 'with-font-declarations-file/my-font.woff2')
|
||||||
),
|
),
|
||||||
'next.config.js': new FileRef(
|
|
||||||
join(__dirname, 'with-font-declarations-file/next.config.js')
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
env: {
|
env: {
|
||||||
NEXT_FONT_GOOGLE_MOCKED_RESPONSES: mockedGoogleFontResponses,
|
NEXT_FONT_GOOGLE_MOCKED_RESPONSES: mockedGoogleFontResponses,
|
||||||
|
|
|
@ -7,12 +7,16 @@ import {
|
||||||
Roboto,
|
Roboto,
|
||||||
} from 'next/font/google'
|
} from 'next/font/google'
|
||||||
|
|
||||||
const openSans = Open_Sans()
|
const openSans = Open_Sans({ subsets: ['latin'] })
|
||||||
const sourceCodePro = Source_Code_Pro({ display: 'swap', preload: false })
|
const sourceCodePro = Source_Code_Pro({ display: 'swap', preload: false })
|
||||||
const abel = Abel({ weight: '400', display: 'optional', preload: false })
|
const abel = Abel({ weight: '400', display: 'optional', preload: false })
|
||||||
|
|
||||||
export const inter = Inter({ display: 'block', preload: true })
|
export const inter = Inter({
|
||||||
export const roboto = Roboto({ weight: '400' })
|
display: 'block',
|
||||||
|
preload: true,
|
||||||
|
subsets: ['latin'],
|
||||||
|
})
|
||||||
|
export const roboto = Roboto({ weight: '400', subsets: ['latin'] })
|
||||||
|
|
||||||
export const myLocalFont = localFont({
|
export const myLocalFont = localFont({
|
||||||
src: './my-font.woff2',
|
src: './my-font.woff2',
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
module.exports = {
|
|
||||||
experimental: {
|
|
||||||
fontLoaders: [
|
|
||||||
{
|
|
||||||
loader: '@next/font/google',
|
|
||||||
options: { subsets: ['latin'] },
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
}
|
|
|
@ -25,9 +25,6 @@ describe('next/font/google without-preloaded-fonts without _app', () => {
|
||||||
'pages/without-fonts.js': new FileRef(
|
'pages/without-fonts.js': new FileRef(
|
||||||
join(__dirname, 'without-preloaded-fonts/pages/without-fonts.js')
|
join(__dirname, 'without-preloaded-fonts/pages/without-fonts.js')
|
||||||
),
|
),
|
||||||
'next.config.js': new FileRef(
|
|
||||||
join(__dirname, 'without-preloaded-fonts/next.config.js')
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
env: {
|
env: {
|
||||||
NEXT_FONT_GOOGLE_MOCKED_RESPONSES: mockedGoogleFontResponses,
|
NEXT_FONT_GOOGLE_MOCKED_RESPONSES: mockedGoogleFontResponses,
|
||||||
|
@ -82,9 +79,6 @@ describe('next/font/google no preloads with _app', () => {
|
||||||
'pages/without-fonts.js': new FileRef(
|
'pages/without-fonts.js': new FileRef(
|
||||||
join(__dirname, 'without-preloaded-fonts/pages/without-fonts.js')
|
join(__dirname, 'without-preloaded-fonts/pages/without-fonts.js')
|
||||||
),
|
),
|
||||||
'next.config.js': new FileRef(
|
|
||||||
join(__dirname, 'without-preloaded-fonts/next.config.js')
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
env: {
|
env: {
|
||||||
NEXT_FONT_GOOGLE_MOCKED_RESPONSES: mockedGoogleFontResponses,
|
NEXT_FONT_GOOGLE_MOCKED_RESPONSES: mockedGoogleFontResponses,
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
module.exports = {
|
|
||||||
experimental: {
|
|
||||||
fontLoaders: [
|
|
||||||
{
|
|
||||||
loader: '@next/font/google',
|
|
||||||
options: { subsets: ['latin'] },
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
}
|
|
Loading…
Reference in a new issue