storybook: [Bug]: [@storybook/nextjs] Using @next/font breaks storybook v7

Describe the bug

Using Next 13’s new @next/font font loader, which is required for loading fonts in the new /app routes directory, breaks storybook v7 if it is referenced. Not sure if something can be done to shim it here or if it needs to be fixed upstream.

The workaround is to ensure that no code that touches storybook references the font loader (eg: global styles etc), which could be documented if nothing else.

To Reproduce

No response

System

System:
    OS: macOS 13.0
    CPU: (8) arm64 Apple M1
  Binaries:
    Node: 18.3.0 - /opt/homebrew/bin/node
    Yarn: 1.22.15 - /usr/local/bin/yarn
    npm: 8.11.0 - /opt/homebrew/bin/npm
  Browsers:
    Chrome: 107.0.5304.87
    Firefox: 103.0.2
    Safari: 16.1
  npmPackages:
    @storybook/addon-essentials: future => 7.0.0-alpha.34 
    @storybook/nextjs: ^7.0.0-alpha.41 => 7.0.0-alpha.41

Additional context

Screenshot 2022-11-02 at 4 54 19 PM

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 7
  • Comments: 24 (10 by maintainers)

Commits related to this issue

Most upvoted comments

@valentinpalkovic Thanks for the help! Local font import is now resolved.

My project folder structure is next:

lib
β”œβ”€β”€ createEmotionCache.ts
β”œβ”€β”€ fonts.ts
β”œβ”€β”€ index.ts
└── theme.ts
public
β”œβ”€β”€ favicon.ico
└── fonts
    └── neue-machina
        β”œβ”€β”€ NeueMachina-Black.woff2
        β”œβ”€β”€ NeueMachina-Bold.woff2
        β”œβ”€β”€ NeueMachina-Light.woff2
        β”œβ”€β”€ NeueMachina-Medium.woff2
        β”œβ”€β”€ NeueMachina-Regular.woff2
        β”œβ”€β”€ NeueMachina-Ultrabold.woff2
        β”œβ”€β”€ NeueMachina-Ultralight.woff2
        └── NeueMachina.css

Considering this, I had to correctly set up the staticDirs configuration.

Before:

// .storybook/main.ts

export default {
  // ...
  staticDirs: ['../public']
}

After:

// .storybook/main.ts
export default {
  // ...
  staticDirs: [
    {
      from: '../public',
      to: 'public'
    }
  ]

So I could import the fonts like this:

// lib/fonts.ts
import { Inter_Tight } from '@next/font/google'
import localFont from '@next/font/local'

export const inter = Inter_Tight({
  weight: ['400'],
  subsets: ['latin'],
  fallback: ['sans-serif']
})

export const neueMachina = localFont({
  src: [
    {
      path: '../public/fonts/neue-machina/NeueMachina-Regular.woff2',
      weight: '400',
      style: 'normal'
    },
    {
      path: '../public/fonts/neue-machina/NeueMachina-Bold.woff2',
      weight: '700',
      style: 'normal'
    }
  ]
})

Hope this helps out someone else!

Absolutely love this nextjs extension, great job guys!

@next/font is now mocked in next/jest.

I also got this to work to mock @next/font/google in a story.

  webpackFinal: async (config) => {
    config.resolve.alias = {
      ...config.resolve.alias,
      "@next/font/google": require.resolve("./nextFontGoogle"),
    }

    return config;
}

This will set the class in .className to be named the same as the function imported from @next/font/google, e.g. Playfair_Display.

// nextFontGoogle.js
module.exports = new Proxy(
    {},
    {
      get: function getter(_, receiver) {
        return () => ({
          className: receiver,
        })
      },
    }
  )
  

And then import a CSS files that defines the font inside the story.

@font-face {
  font-family: "Playfair_Display";
  font-style: normal;
  font-weight: 400 900;
  font-display: swap;
  src: url(https://fonts.gstatic.com/s/playfairdisplay/v30/nuFiD-vYSZviVYUb_rj3ij__anPXDTzYgEM86xQ.woff2)
    format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
    U+FEFF, U+FFFD;
}

.Playfair_Display {
  font-family: "Playfair_Display", serif;
}

I tried this for a while now and I somehow just can’t get it to work on my NX setup. I always either get this error when starting up Storybook:

Failed to load static files, no such directory: /some/path/fonts

Or this error on the Storybook web page:

index.js:15 Uncaught Error: @next/font/local failed to run or is incorrectly configured.
If you just installed `@next/font`, please try restarting `next dev` and resaving your file.

My workaround is to serve the files at / and then loading them with regular @font-face css. We are only using Storybook locally, so this setup is totally fine. You can continue reading if you want to dig into this though.


My setup basically looks like this. I got a StorybookWrapper.tsx component for the that gets imported in the preview.tsx:

apps/website/.storybook/StorybookWrapper.tsx:

import { interFont, sculpinFont } from "@my-project/components/containers/Global";
import { theme as baseTheme } from "@my-project/styles/theme";
import React from "react";
import { ThemeProvider } from "styled-components";

const theme = {
  ...baseTheme,
  fontFamily: {
    headlines: sculpinFont.style.fontFamily,
    body: interFont.style.fontFamily,
  },
};

const StorybookWrapper: React.FC<{ children: React.ReactNode }> = ({ children }) => {
  return <ThemeProvider theme={theme}>{children}</ThemeProvider>;
};

export default StorybookWrapper;

apps/website/.storybook/preview.tsx:

import StorybookWrapper from "./StorybookWrapper";

export const decorators = [
  (Story) => {
    return <StorybookWrapper>{Story}</StorybookWrapper>;
  },
];

Fonts get created in a Global.tsx. libs/components/src/lib/containers/Global.tsx:

import localFont from "@next/font/local";

export const interFont = localFont({
  src: [
    {
      path: "../../assets/fonts/inter-v12-latin-regular.woff2",
      weight: "400",
    },
  ],
  fallback: ["Arial", "sans-serif"],
  display: "swap",
});

export const sculpinFont = localFont({
  src: [
    {
      path: "../../assets/fonts/sculpin-700.woff2",
      weight: "400",
    },
  ],
  fallback: ["Arial", "sans-serif"],
  display: "swap",
});

My file structure looks like this:

.storybook/
β”œβ”€ main.ts
apps/
β”œβ”€ website/
β”‚  β”œβ”€ .storybook/
β”‚  β”‚  β”œβ”€ main.ts
β”‚  β”‚  β”œβ”€ preview.tsx
β”‚  β”‚  β”œβ”€ StorybookWrapper.tsx
libs/
β”œβ”€ components/
β”‚  β”œβ”€ src/
β”‚  β”‚  β”œβ”€ lib/
β”‚  β”‚  β”‚  β”œβ”€ containers/
β”‚  β”‚  β”‚  β”‚  β”œβ”€ Global.tsx
β”‚  β”‚  β”œβ”€ assets/
β”‚  β”‚  β”‚  β”œβ”€ fonts/

In my main.ts I therefore got this: apps/website/.storybook/main.ts:

staticDirs: [
    {
      from: '../../../libs/components/src/assets/fonts/',
      to: 'libs/components/src/assets/fonts/',
    },
  ],

From is from the storybook directory and I guess in this case its the nested storybook directory because everything else than the value above throws an error. The to value should be from the root of my project so the one above should be fine as well (and does not throw an error). ../../../../../../../libs/components/src/assets/fonts/ is working as well, other paths throw an error.

I’m not quite sure where the problem is. It’s either that I don’t really get how to work with the β€˜β€¦/…/’ in my local font, that my custom ts paths are not working correctly or that NX is in the way.

Hi @hobadams.

I am working on a fully-fledged solution right now. Due to the upcoming holiday season, the release of @next/font support might occur at the year’s end or in the first weeks of January. Maybe I can already release something tomorrow that doesn’t break Storybook completely.

Hey there @seanhakbb thank you for providing a repro! If you upgrade to the latest Storybook 7 release you will notice that it works correctly:

image

@AdrianFahrbach thanks for providing all this info, would you mind upgrading to the latest Storybook 7 and checking whether you still experience the issues?

@valentinpalkovic Thanks for the help! Local font import is now resolved.

My project folder structure is next:

lib
β”œβ”€β”€ createEmotionCache.ts
β”œβ”€β”€ fonts.ts
β”œβ”€β”€ index.ts
└── theme.ts
public
β”œβ”€β”€ favicon.ico
└── fonts
    └── neue-machina
        β”œβ”€β”€ NeueMachina-Black.woff2
        β”œβ”€β”€ NeueMachina-Bold.woff2
        β”œβ”€β”€ NeueMachina-Light.woff2
        β”œβ”€β”€ NeueMachina-Medium.woff2
        β”œβ”€β”€ NeueMachina-Regular.woff2
        β”œβ”€β”€ NeueMachina-Ultrabold.woff2
        β”œβ”€β”€ NeueMachina-Ultralight.woff2
        └── NeueMachina.css

Considering this, I had to correctly set up the staticDirs configuration.

Before:

// .storybook/main.ts

export default {
  // ...
  staticDirs: ['../public']
}

After:

// .storybook/main.ts
export default {
  // ...
  staticDirs: [
    {
      from: '../public',
      to: 'public'
    }
  ]

So I could import the fonts like this:

// lib/fonts.ts
import { Inter_Tight } from '@next/font/google'
import localFont from '@next/font/local'

export const inter = Inter_Tight({
  weight: ['400'],
  subsets: ['latin'],
  fallback: ['sans-serif']
})

export const neueMachina = localFont({
  src: [
    {
      path: '../public/fonts/neue-machina/NeueMachina-Regular.woff2',
      weight: '400',
      style: 'normal'
    },
    {
      path: '../public/fonts/neue-machina/NeueMachina-Bold.woff2',
      weight: '700',
      style: 'normal'
    }
  ]
})

Hope this helps out someone else!

love this nextjs extension, great job guys!

Worked for me.

@seanhakbb Can you please create a reproduction and provide me a link to it? Then I will be able to debug it if you want πŸ˜ƒ

https://github.com/seanhakbb/storybookdebug I set this quick demo up that shows it working with npm run dev, but not in npm run storybook. (check in the iframe <head> after a class called something like β€œfont-face-font-98bc83”)

Im running on Node v18.13.0 btw. Thanks for the help! @valentinpalkovic

@seanhakbb Can you please create a reproduction and provide me a link to it? Then I will be able to debug it if you want πŸ˜ƒ

Hi @valentinpalkovic, I’m on ^7.0.0-beta.45 and can confirm that @nextjs/font is not picked up by storybook.

Hi @salchichongallo,

this workaround shouldnβ€˜t be necessary anymore. Have you tried the latest prerelease version?

Also make sure to use the @storybook/next framework, like described here: https://storybook.js.org/blog/integrate-nextjs-and-storybook-automatically/