Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use stable Next.js v13.2.0 next/font #21247

Merged
merged 13 commits into from
Mar 2, 2023
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
4 changes: 2 additions & 2 deletions code/frameworks/nextjs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@
"@babel/preset-react": "^7.18.6",
"@babel/preset-typescript": "^7.21.0",
"@babel/runtime": "^7.21.0",
"@next/font": "^13.0.7",
"@next/font": "^13.2.0",
"@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 @@ -103,7 +103,7 @@
"@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"
},
Expand Down
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
Expand Up @@ -6,7 +6,7 @@ import {
getFontAxes,
getUrl,
validateData,
} from '@next/font/dist/google/utils';
} from 'next/dist/compiled/@next/font/dist/google/utils';
valentinpalkovic marked this conversation as resolved.
Show resolved Hide resolved

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

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// 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 { validateData } from 'next/dist/compiled/@next/font/dist/local/utils';
import path from 'path';

import type { LoaderOptions } from '../types';
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;
};
1 change: 1 addition & 0 deletions code/frameworks/nextjs/src/routing/app-router-provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ const AppRouterProvider: React.FC<AppRouterProviderProps> = ({ children, action,
childNodes: new Map(),
tree: [pathname, { children: getParallelRoutes([...segments]) }],
url: pathname,
headRenderedAboveThisLevel: true,
}}
>
<PathnameContext.Provider value={pathname}>{children}</PathnameContext.Provider>
Expand Down
4 changes: 2 additions & 2 deletions code/frameworks/nextjs/template/stories_default-js/Font.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* eslint-disable react/prop-types */
import { Rubik_Puddles } from '@next/font/google';
import localFont from '@next/font/local';
import { Rubik_Puddles } from 'next/font/google';
import localFont from 'next/font/local';

import React from 'react';

Expand Down
2 changes: 1 addition & 1 deletion code/lib/core-common/src/utils/get-storybook-info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ const findConfigFile = (prefix: string, configDir: string) => {

const getConfigInfo = (packageJson: PackageJson, configDir?: string) => {
let storybookConfigDir = configDir ?? '.storybook';
const storybookScript = packageJson.scripts?.['storybook'];
valentinpalkovic marked this conversation as resolved.
Show resolved Hide resolved
const storybookScript = packageJson.scripts?.storybook;
if (storybookScript && !configDir) {
const configParam = getStorybookConfiguration(storybookScript, '-c', '--config-dir');
if (configParam) storybookConfigDir = configParam;
Expand Down