Skip to content

Commit

Permalink
Merge pull request #21247 from alex-ahumada/migrate-next-font
Browse files Browse the repository at this point in the history
Use stable Next.js v13.2.0 next/font
  • Loading branch information
valentinpalkovic committed Mar 2, 2023
2 parents 759ee41 + 0ee533a commit 0f3e9e5
Show file tree
Hide file tree
Showing 16 changed files with 242 additions and 158 deletions.
18 changes: 9 additions & 9 deletions code/frameworks/nextjs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@
- [Remote Images](#remote-images)
- [AVIF](#avif)
- [Next.js Font Optimization](#nextjs-font-optimization)
- [@next/font/google](#nextfontgoogle)
- [@next/font/local](#nextfontlocal)
- [Not supported features of @next/font](#not-supported-features-of-nextfont)
- [next/font/google](#nextfontgoogle)
- [next/font/local](#nextfontlocal)
- [Not supported features of next/font](#not-supported-features-of-nextfont)
- [Next.js Routing](#nextjs-routing)
- [Overriding defaults](#overriding-defaults)
- [Global Defaults](#global-defaults)
Expand Down Expand Up @@ -221,13 +221,13 @@ This format is not supported by this framework yet. Feel free to [open up an iss

### Next.js Font Optimization

[@next/font](https://nextjs.org/docs/basic-features/font-optimization) is partially supported in Storybook. The packages `@next/font/google` and `@next/font/local` are supported.
[next/font](https://nextjs.org/docs/basic-features/font-optimization) is partially supported in Storybook. The packages `next/font/google` and `next/font/local` are supported.

#### @next/font/google
#### next/font/google

You don't have to do anything. `@next/font/google` is supported out of the box.
You don't have to do anything. `next/font/google` is supported out of the box.

#### @next/font/local
#### next/font/local

For local fonts you have to define the [src](https://nextjs.org/docs/api-reference/next/font#src) property.
The path is relative to the directory where the font loader function is called.
Expand All @@ -236,7 +236,7 @@ If the following component defines your localFont like this:

```js
// src/components/MyComponent.js
import localFont from '@next/font/local';
import localFont from 'next/font/local';

const localRubikStorm = localFont({ src: './fonts/RubikStorm-Regular.ttf' });
```
Expand All @@ -256,7 +256,7 @@ export default {
}
```

#### Not supported features of @next/font
#### Not supported features of next/font

The following features are not supported (yet). Support for these features might be planned for the future:

Expand Down
8 changes: 6 additions & 2 deletions code/frameworks/nextjs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@
"@babel/preset-react": "^7.18.6",
"@babel/preset-typescript": "^7.21.0",
"@babel/runtime": "^7.21.0",
"@next/font": "^13.0.7",
"@storybook/addon-actions": "7.0.0-beta.59",
"@storybook/builder-webpack5": "7.0.0-beta.59",
"@storybook/core-common": "7.0.0-beta.59",
Expand Down Expand Up @@ -100,15 +99,17 @@
"devDependencies": {
"@babel/core": "^7.20.5",
"@babel/types": "^7.20.5",
"@next/font": "^13.2.0",
"@types/babel__core": "^7",
"@types/babel__plugin-transform-runtime": "^7",
"@types/babel__preset-env": "^7",
"next": "^13.0.5",
"next": "^13.2.0",
"typescript": "^4.9.3",
"webpack": "^5.65.0"
},
"peerDependencies": {
"@babel/core": "^7.11.5",
"@next/font": "^13.0.0",
"next": "^9.0.0 || ^10.0.0 || ^11.0.0 || ^12.0.0 || ^13.0.0",
"react": "^16.8.0 || ^17.0.0 || ^18.0.0",
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0",
Expand All @@ -118,6 +119,9 @@
"@babel/core": {
"optional": true
},
"@next/font": {
"optional": true
},
"@storybook/addon-actions": {
"optional": true
},
Expand Down
21 changes: 0 additions & 21 deletions code/frameworks/nextjs/src/babel/plugins/next-font-unsupported.ts

This file was deleted.

This file was deleted.

26 changes: 13 additions & 13 deletions code/frameworks/nextjs/src/font/babel/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export type VariableMeta = {
/**
* Variable Declaration name of the assigned function call
* @example
* import { Roboto } from '@next/font/google'
* import { Roboto } from 'next/font/google'
* const robotoName = Roboto({
* weight: '400'
* })
Expand All @@ -21,7 +21,7 @@ export type VariableMeta = {
/**
* Properties of the assigned function call
* @example
* import { Roboto } from '@next/font/google'
* import { Roboto } from 'next/font/google'
* const robotoName = Roboto({
* weight: '400'
* })
Expand All @@ -30,9 +30,9 @@ export type VariableMeta = {
*/
properties: JSReturnValue;
/**
* Function name of the imported @next/font/google function
* Function name of the imported next/font/google function
* @example
* import { Roboto } from '@next/font/google'
* import { Roboto } from 'next/font/google'
* const robotoName = Roboto({
* weight: '400'
* })
Expand Down Expand Up @@ -110,7 +110,7 @@ export function isDefined<T>(value: T): value is Exclude<T, undefined> {
* Removes transformed variable declarations, which were already replaced with parameterized imports
* @example
* // AST
* import { Roboto, Inter } from '@next/font/google'
* import { Roboto, Inter } from 'next/font/google'
* const interName = Inter({
* subsets: ['latin'],
* })
Expand All @@ -119,7 +119,7 @@ export function isDefined<T>(value: T): value is Exclude<T, undefined> {
* })
*
* // Result
* import { Roboto, Inter } from '@next/font/google'
* import { Roboto, Inter } from 'next/font/google'
*
* // Variable declarations are removed
*/
Expand Down Expand Up @@ -172,10 +172,10 @@ export function removeTransformedVariableDeclarations(
}

/**
* Replaces `@next/font` import with a parameterized import
* Replaces `next/font` import with a parameterized import
* @example
* // AST of src/example.js
* import { Roboto, Inter } from '@next/font/google'
* import { Roboto, Inter } from 'next/font/google'
* const interName = Inter({
* subsets: ['latin'],
* })
Expand All @@ -184,8 +184,8 @@ export function removeTransformedVariableDeclarations(
* })
*
* // Result
* import interName from 'storybook-nextjs-font-loader?{filename: "src/example.js", source: "@next/font/google", fontFamily: "Inter", props: {"subsets":["latin"]}}!@next/font/google'
* import robotoName from 'storybook-nextjs-font-loader?{filename: "src/example.js", source: "@next/font/google", fontFamily: "Roboto", props: {"weight": "400"}}!@next/font/google'
* import interName from 'storybook-nextjs-font-loader?{filename: "src/example.js", source: "next/font/google", fontFamily: "Inter", props: {"subsets":["latin"]}}!next/font/google'
* import robotoName from 'storybook-nextjs-font-loader?{filename: "src/example.js", source: "next/font/google", fontFamily: "Roboto", props: {"weight": "400"}}!next/font/google'
*
* // Following code will be removed from removeUnusedVariableDeclarations function
* const interName = Inter({
Expand Down Expand Up @@ -225,7 +225,7 @@ export function replaceImportWithParamterImport(
* Get meta information for the provided import specifier
* @example
* // AST
* import { Roboto, Inter } from '@next/font/google'
* import { Roboto, Inter } from 'next/font/google'
* const interName = Inter({
* subsets: ['latin'],
* })
Expand Down Expand Up @@ -297,14 +297,14 @@ export function getVariableMetasBySpecifier(

if (!types.isObjectExpression(options)) {
throw program.buildCodeFrameError(
'Please pass an options object to the call expression of @next/font functions'
'Please pass an options object to the call expression of next/font functions'
);
}

options.properties.forEach((property) => {
if (types.isSpreadElement(property)) {
throw program.buildCodeFrameError(
'Please do not use spread elements in the options object in @next/font function calls'
'Please do not use spread elements in the options object in next/font function calls'
);
}
});
Expand Down
29 changes: 28 additions & 1 deletion code/frameworks/nextjs/src/font/babel/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,23 @@ import { transform } from '@babel/core';
import TransformFontImports from '.';

const example = `
import { Inter, Roboto } from 'next/font/google'
import localFont from 'next/font/local'
const myFont = localFont({ src: './my-font.woff2' })
const roboto = Roboto({
weight: '400',
})
const inter = Inter({
subsets: ['latin'],
});
const randomObj = {}
`;

const exampleLegacy = `
import { Inter, Roboto } from '@next/font/google'
import localFont from '@next/font/local'
Expand All @@ -19,8 +36,18 @@ const inter = Inter({
const randomObj = {}
`;

it('should transform AST properly', () => {
it('should transform next/font AST properly', () => {
const { code } = transform(example, { plugins: [TransformFontImports] })!;
expect(code).toMatchInlineSnapshot(`
"import inter from \\"storybook-nextjs-font-loader?{\\\\\\"source\\\\\\":\\\\\\"next/font/google\\\\\\",\\\\\\"props\\\\\\":{\\\\\\"subsets\\\\\\":[\\\\\\"latin\\\\\\"]},\\\\\\"fontFamily\\\\\\":\\\\\\"Inter\\\\\\",\\\\\\"filename\\\\\\":\\\\\\"\\\\\\"}!next/font/google\\";
import roboto from \\"storybook-nextjs-font-loader?{\\\\\\"source\\\\\\":\\\\\\"next/font/google\\\\\\",\\\\\\"props\\\\\\":{\\\\\\"weight\\\\\\":\\\\\\"400\\\\\\"},\\\\\\"fontFamily\\\\\\":\\\\\\"Roboto\\\\\\",\\\\\\"filename\\\\\\":\\\\\\"\\\\\\"}!next/font/google\\";
import myFont from \\"storybook-nextjs-font-loader?{\\\\\\"source\\\\\\":\\\\\\"next/font/local\\\\\\",\\\\\\"props\\\\\\":{\\\\\\"src\\\\\\":\\\\\\"./my-font.woff2\\\\\\"},\\\\\\"fontFamily\\\\\\":\\\\\\"localFont\\\\\\",\\\\\\"filename\\\\\\":\\\\\\"\\\\\\"}!next/font/local\\";
const randomObj = {};"
`);
});

it('should transform @next/font AST properly', () => {
const { code } = transform(exampleLegacy, { plugins: [TransformFontImports] })!;
expect(code).toMatchInlineSnapshot(`
"import inter from \\"storybook-nextjs-font-loader?{\\\\\\"source\\\\\\":\\\\\\"@next/font/google\\\\\\",\\\\\\"props\\\\\\":{\\\\\\"subsets\\\\\\":[\\\\\\"latin\\\\\\"]},\\\\\\"fontFamily\\\\\\":\\\\\\"Inter\\\\\\",\\\\\\"filename\\\\\\":\\\\\\"\\\\\\"}!@next/font/google\\";
import roboto from \\"storybook-nextjs-font-loader?{\\\\\\"source\\\\\\":\\\\\\"@next/font/google\\\\\\",\\\\\\"props\\\\\\":{\\\\\\"weight\\\\\\":\\\\\\"400\\\\\\"},\\\\\\"fontFamily\\\\\\":\\\\\\"Roboto\\\\\\",\\\\\\"filename\\\\\\":\\\\\\"\\\\\\"}!@next/font/google\\";
Expand Down
18 changes: 9 additions & 9 deletions code/frameworks/nextjs/src/font/babel/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ import {
type Babel = typeof BabelCoreNamespace;

/**
* Transforms "@next/font" imports and usages to a webpack loader friendly format with parameters
* Transforms "next/font" imports and usages to a webpack loader friendly format with parameters
* @example
* // src/example.js
* // Turns this code:
* import { Inter, Roboto } from '@next/font/google'
* import localFont from '@next/font/local'
* import { Inter, Roboto } from 'next/font/google'
* import localFont from 'next/font/local'
*
* const myFont = localFont({ src: './my-font.woff2' })
* const roboto = Roboto({
Expand All @@ -26,9 +26,9 @@ type Babel = typeof BabelCoreNamespace;
* });
*
* // Into this code:
* import inter from 'storybook-nextjs-font-loader?{filename: "src/example.js", source: "@next/font/google", fontFamily: "Inter", props: {"subsets":["latin"]}}!@next/font/google'
* import roboto from 'storybook-nextjs-font-loader?{filename: "src/example.js", source: "@next/font/google", fontFamily: "Roboto", props: {"weight": "400"}}!@next/font/google'
* import myFont from 'storybook-nextjs-font-loader?{filename: "src/example.js", source: "@next/font/local", props: {"src": "./my-font.woff2"}}!@next/font/local'
* import inter from 'storybook-nextjs-font-loader?{filename: "src/example.js", source: "next/font/google", fontFamily: "Inter", props: {"subsets":["latin"]}}!next/font/google'
* import roboto from 'storybook-nextjs-font-loader?{filename: "src/example.js", source: "next/font/google", fontFamily: "Roboto", props: {"weight": "400"}}!next/font/google'
* import myFont from 'storybook-nextjs-font-loader?{filename: "src/example.js", source: "next/font/local", props: {"src": "./my-font.woff2"}}!next/font/local'
*
* This Plugin tries to adopt the functionality which is provided by the nextjs swc plugin
* https://github.com/vercel/next.js/pull/40221
Expand All @@ -42,10 +42,10 @@ export default function TransformFontImports({ types }: Babel): BabelCoreNamespa
const { source } = node;
const { filename = '' } = state;

if (source.value === '@next/font/local') {
if (source.value === 'next/font/local' || source.value === '@next/font/local') {
const { specifiers } = node;

// @next/font/local only provides a default export
// next/font/local only provides a default export
const specifier = specifiers[0];

if (!path.parentPath.isProgram()) {
Expand All @@ -60,7 +60,7 @@ export default function TransformFontImports({ types }: Babel): BabelCoreNamespa
replaceImportWithParamterImport(path, types, source, variableMetas, filename);
}

if (source.value === '@next/font/google') {
if (source.value === 'next/font/google' || source.value === '@next/font/google') {
const { specifiers } = node;

const variableMetas = specifiers
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
import loaderUtils from 'next/dist/compiled/loader-utils3';
import {
fetchCSSFromGoogleFonts,
getFontAxes,
getUrl,
validateData,
} from '@next/font/dist/google/utils';

import type { LoaderOptions } from '../types';

const cssCache = new Map<string, Promise<string>>();

export async function getFontFaceDeclarations(options: LoaderOptions) {
const {
fetchCSSFromGoogleFonts,
getFontAxes,
getUrl,
validateData,
} = require('../utils/google-font-utils');

const { fontFamily, weights, styles, selectedVariableAxes, display, variable } = validateData(
options.fontFamily,
[options.props],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
import loaderUtils from 'next/dist/compiled/loader-utils3';
import { validateData } from '@next/font/dist/local/utils';
import path from 'path';

import type { LoaderOptions } from '../types';
Expand All @@ -14,6 +13,7 @@ export async function getFontFaceDeclarations(options: LoaderOptions, rootContex
// Parent folder relative to the root context
const parentFolder = options.filename.split('/').slice(0, -1).join('/').replace(rootContext, '');

const { validateData } = require('../utils/local-font-utils');
const { weight, style, variable } = validateData('', options.props);

const id = `font-${loaderUtils.getHashDigest(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ export default async function storybookNextjsFontLoader(this: any) {

let fontFaceDeclaration: FontFaceDeclaration | undefined;

if (options.source === '@next/font/google') {
if (options.source === 'next/font/google' || options.source === '@next/font/google') {
fontFaceDeclaration = await getGoogleFontFaceDeclarations(options);
}

if (options.source === '@next/font/local') {
if (options.source === 'next/font/local' || options.source === '@next/font/local') {
fontFaceDeclaration = await getLocalFontFaceDeclarations(options, rootCtx);
}

Expand Down
6 changes: 3 additions & 3 deletions code/frameworks/nextjs/src/font/webpack/loader/types.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
export type LoaderOptions = {
/**
* Initial import name. Can be `@next/font/google` or `@next/font/local`
* Initial import name. Can be `next/font/google` or `next/font/local`
*/
source: string;
/**
* Props passed to the `@next/font` function call
* Props passed to the `next/font` function call
*/
props: Record<string, any>;
/**
* Font Family name
*/
fontFamily: string;
/**
* Filename of the issuer file, which imports `@next/font/google` or `@next/font/local
* Filename of the issuer file, which imports `next/font/google` or `next/font/local
*/
filename: string;
};

0 comments on commit 0f3e9e5

Please sign in to comment.