From 2a02e134805f9659481f90237478a39516322c44 Mon Sep 17 00:00:00 2001 From: Kevin Yank Date: Tue, 19 Nov 2024 18:14:41 +1100 Subject: [PATCH] Fix webpack fsCache not working with @storybook/nextjs Next.js overrides certain internal webpack packages (particularly `webpack-sources`), which are involved with filesystem caching, with its own versions from next/dist/compiled. For filesystem caching to work, Next.js must be allowed to perform these overrides before webpack is first initialized by @storybook/builder-webpack5. If it is not, the objects to be serialized to disk in the caching process will be instantiated using the original (non-Next.js) modules, but the serializers will be created using the Next.js modules. This mismatch between the objects to be cached and the serializers that write the filesystem cache prevents the cache from being written; instead, webpack outputs a warning message to the console for every object that it tries and fails to find a matching serializer for. This fix works by invoking Next.js to configure webpack in the `core` hook of @storybook/nextjs/preset, immediately before loading @storybook/builder-webpack5. We don't actually use this configuration that Next.js creates; the actual configuration that will be used in the build is still generated in `webpackFinal` as before. `fsCache` has a large impact on Storybook build performance. Even in a minimal project with a single story, enabling it reduces build time by 66%! This is therefore a very valuable option to be able to enable. Fixes #29621 --- code/frameworks/nextjs/src/preset.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/code/frameworks/nextjs/src/preset.ts b/code/frameworks/nextjs/src/preset.ts index 3463910175e1..84255fc62e20 100644 --- a/code/frameworks/nextjs/src/preset.ts +++ b/code/frameworks/nextjs/src/preset.ts @@ -36,6 +36,19 @@ export const addons: PresetProperty<'addons'> = [ export const core: PresetProperty<'core'> = async (config, options) => { const framework = await options.presets.apply('framework'); + // Load the Next.js configuration before we need it in webpackFinal (below). + // This gives Next.js an opportunity to override some of webpack's internals + // (see next/dist/server/config-utils.js) before @storybook/builder-webpack5 + // starts to use it. Without this, webpack's file system cache (fsCache: true) + // does not work. + const { nextConfigPath } = await options.presets.apply('frameworkOptions'); + await configureConfig({ + // Pass in a dummy webpack config object for now, since we don't want to + // modify the real one yet. We pass in the real one in webpackFinal. + baseConfig: {}, + nextConfigPath, + }); + return { ...config, builder: {