storybookjs / storybook

Storybook is the industry standard workshop for building, documenting, and testing UI components in isolation
https://storybook.js.org
MIT License
84.83k stars 9.34k forks source link

[Bug]: next/fonts are not loaded in Storybook 8 using next/font/google or next/font/local #26792

Open lapa182 opened 7 months ago

lapa182 commented 7 months ago

Describe the bug

We recently migrated to Storybook 8, but our fonts (either local or the one using Google Fonts) are not working at the moment, this used to work with Storybook 7.

Here's a snippet of our main.ts:

import { dirname, join } from 'path';
import type { StorybookConfig } from '@storybook/nextjs';
import * as path from 'path';

function getAbsolutePath(value: string): any {
    return dirname(require.resolve(join(value, 'package.json')));
}

const config: StorybookConfig = {
    stories: ['../**/*.stories.@(js|jsx|ts|tsx)'],
    addons: [
        getAbsolutePath('@storybook/addon-links'),
        getAbsolutePath('@storybook/addon-essentials'),
        getAbsolutePath('@storybook/addon-interactions'),
        getAbsolutePath('@storybook/manager-api'),
        getAbsolutePath('@storybook/preview-api'),
        getAbsolutePath('@chromatic-com/storybook'),
    ],
    framework: {
        name: getAbsolutePath('@storybook/nextjs'),
        options: {
            nextConfigPath: path.resolve(__dirname, '../next.config.js'),
        },
    },
    docs: {
        autodocs: 'tag',
    },
    staticDirs: [
        '../public',
        {
            from: '../src/styles/fonts',
            to: '/src/styles/fonts',
        },
    ],
    env: (config) => {
        const configMutation = {
            ...config,
            MEDIA_FOLDER: '/storybook/',
        };
        return configMutation;
    },
    webpackFinal: async (config) => {
        if (config.resolve) {
            config.resolve.alias = {
                ...config.resolve.alias,
                ['@/utils/getAccessToken']: path.resolve(__dirname, '../src/utils/mocks/getAccessToken.ts'),
                ['@/apis/apiFunctions/orderApi']: path.resolve(__dirname, '../src/apis/apiFunctions/mocks/orderApi.tsx'),
                ['@/styles']: path.resolve(__dirname, '../src/styles'),
                ['os']: path.resolve(__dirname, '../src/utils/mocks/storybook/mockOs.ts'),
                ['crypto']: path.resolve(__dirname, '../src/utils/mocks/storybook/mockCrypto.ts'),
                ['next/headers']: path.resolve(__dirname, '../src/utils/mocks/storybook/mockHeader.ts'),
                ['@/utils/authConfig/methods']: path.resolve(
                    __dirname,
                    '../src/utils/mocks/storybook/mockAuthConfigMethods.ts',
                ),
            };
        }

        // Modify or add SVG handling
        const svgRuleIndex = config.module.rules.findIndex((rule) => rule.test && rule.test.toString().includes('svg'));
        if (svgRuleIndex !== -1) {
            config.module.rules[svgRuleIndex] = {
                test: /\.svg$/,
                use: ['@svgr/webpack'],
                include: [
                    path.resolve(__dirname, '../src/components/Icon/BadgeIcon/svgs'),
                    path.resolve(__dirname, '../src/components/Icon/DietaryIcon/svgs'),
                    path.resolve(__dirname, '../src/components/Icon/InterfaceIcon/svgs'),
                    path.resolve(__dirname, '../src/components/Icon/SocialIcon/svgs'),
                    path.resolve(__dirname, '../src/components/Icon/StickerIcon/svgs'),
                ],
            };
        } else {
            config.module.rules.push({
                test: /\.svg$/,
                use: ['@svgr/webpack'],
                include: [
                    path.resolve(__dirname, '../src/components/Icon/BadgeIcon/svgs'),
                    path.resolve(__dirname, '../src/components/Icon/DietaryIcon/svgs'),
                    path.resolve(__dirname, '../src/components/Icon/InterfaceIcon/svgs'),
                    path.resolve(__dirname, '../src/components/Icon/SocialIcon/svgs'),
                    path.resolve(__dirname, '../src/components/Icon/StickerIcon/svgs'),
                ],
            });
        }

        // Return the altered config
        return config;
    },
};

export default config;

And preview.tsx:

import * as React from 'react';
import type { Preview } from '@storybook/react';
import { applesAndCarrots, montserrat } from '../src/styles/fonts';
import { clsx } from 'clsx';
import '../src/styles/global.scss';
import { customViewports } from './viewports';

const preview: Preview = {
    parameters: {
        controls: { matchers: { color: /(background|color)$/i, date: /Date$/ } },
        viewport: {
            viewports: customViewports,
        },
        backgrounds: {
            default: 'light',
            values: [
                { name: 'light', value: '#fff' },
                { name: 'dark', value: '#3c3c3b' },
                { name: 'sunshine', value: '#fdc500' },
            ],
        },
    },
    decorators: [
        (Story) => (
            <div id="body-root" className={clsx(montserrat.className, montserrat.variable, applesAndCarrots.variable)}>
                <Story />
            </div>
        ),
    ],
};

export default preview;

src/styles/fonts:

import { Montserrat } from 'next/font/google';
import localFont from 'next/font/local';

export const montserrat = Montserrat({
    subsets: ['latin'],
    style: ['normal'],
    variable: '--font-montserrat',
    weight: ['400', '500', '600', '700'],
    display: 'swap',
});

export const applesAndCarrots = localFont({
    src: './applesAndCarrots.woff2',
    variable: '--font-apples-and-carrots',
});

To Reproduce

I've tried to replicate in Stackblitz and in a new project and everything works fine. The only difference I can see it's that when I'm creating the const montserrat like:

import { Montserrat } from 'next/font/google';

export const montserrat = Montserrat({
    subsets: ['latin'],
    style: ['normal'],
    variable: '--font-montserrat',
    weight: ['400', '500', '600', '700'],
    display: 'swap',
});

In Stackblitz and in a new project the typeof of it it's object (which is the expected one) and in my project is a big string.

System

Storybook Environment Info:

  System:
    OS: macOS 14.4
    CPU: (11) arm64 Apple M3 Pro
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 20.11.1 - ~/Library/Caches/fnm_multishells/10375_1712657257281/bin/node
    npm: 10.2.4 - ~/Library/Caches/fnm_multishells/10375_1712657257281/bin/npm
    pnpm: 8.15.4 - ~/Library/pnpm/pnpm <----- active
  Browsers:
    Safari: 17.4
  npmPackages:
    @storybook/addon-essentials: ^8.0.6 => 8.0.6
    @storybook/addon-interactions: ^8.0.6 => 8.0.6
    @storybook/addon-links: ^8.0.6 => 8.0.6
    @storybook/blocks: ^8.0.6 => 8.0.6
    @storybook/nextjs: ^8.0.6 => 8.0.6
    @storybook/preview-api: ^8.0.6 => 8.0.6
    @storybook/react: ^8.0.6 => 8.0.6
    @storybook/test: ^8.0.6 => 8.0.6
    eslint-plugin-storybook: 0.8.0 => 0.8.0
    storybook: ^8.0.6 => 8.0.6

Additional context

Package manager: pnpm and using monorepo.

Zero-1016 commented 7 months ago

Hi @lapa182

I experienced a similar problem. It was a problem when used with the vanila extract setting. Can you check if the error message is the same

image

issues-link

lapa182 commented 7 months ago

@Zero-1016 unfortunately in our case there's no error in the console.

info => Serving static files from ././public at /
info => Serving static files from ././src/styles/fonts at /src/styles/fonts
info => Starting manager..
info => Starting preview..
info Addon-docs: using MDX3
info => Using implicit CSS loaders
info => Using SWC as compiler
info => Using default Webpack5 setup
<i> [webpack-dev-middleware] wait until bundle finished
10% building 0/3 entries 1/3 dependencies 0/1 modulesinfo Using tsconfig paths for react-docgen
WARN export 'EmptyTabContent' (imported as 'EmptyTabContent') was not found in '@storybook/components' (possible exports: A, ActionBar, AddonPanel, Badge, Bar, Blockquote, Button, ClipboardCode, Code, DL, Div, DocumentWrapper, ErrorFormatter, FlexBar, Form, H1, H2, H3, H4, H5, H6, HR, IconButton, IconButtonSkeleton, Icons, Img, LI, Link, ListItem, Loader, OL, P, Placeholder, Pre, ResetWrapper, ScrollArea, Separator, Spaced, Span, StorybookIcon, StorybookLogo, Symbols, SyntaxHighlighter, TT, TabBar, TabButton, TabWrapper, Table, Tabs, TabsState, TooltipLinkList, TooltipMessage, TooltipNote, UL, WithTooltip, WithTooltipPure, Zoom, codeCommon, components, createCopyToClipboardFunction, getStoryHref, icons, interleaveSeparators, nameSpaceClassNames, resetComponents, withReset)
WARN Module not found: Error: Can't resolve '@emotion/is-prop-valid' in '/Users/igo.lapa/source/repos/ACStrawberry/node_modules/.pnpm/framer-motion@11.0.14_react-dom@18.2.0_react@18.2.0/node_modules/framer-motion/dist/es/render/dom/utils'
lapa182 commented 6 months ago

Hi @valentinpalkovic do we have any updates on this issue? We cannot update to Storybook 8 because the fonts are not rendering.