Skip to content

Commit

Permalink
Merge pull request #29654 from sentience/fix-nextjs-webpack-fscache
Browse files Browse the repository at this point in the history
Next.js: Fix webpack fsCache not working
  • Loading branch information
valentinpalkovic authored Dec 13, 2024
2 parents 8690ee9 + 902dc18 commit cf24c98
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 20 deletions.
14 changes: 9 additions & 5 deletions code/frameworks/nextjs/src/config/webpack.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import type { NextConfig } from 'next';
import type { Configuration as WebpackConfig } from 'webpack';
import { DefinePlugin } from 'webpack';

import { addScopedAlias, resolveNextConfig, setAlias } from '../utils';
import { addScopedAlias, resolveNextConfig } from '../utils';

const tryResolve = (path: string) => {
try {
Expand Down Expand Up @@ -48,12 +47,15 @@ export const configureConfig = async ({
addScopedAlias(baseConfig, 'react-dom/server', 'next/dist/compiled/react-dom/server');
}

setupRuntimeConfig(baseConfig, nextConfig);
await setupRuntimeConfig(baseConfig, nextConfig);

return nextConfig;
};

const setupRuntimeConfig = (baseConfig: WebpackConfig, nextConfig: NextConfig): void => {
const setupRuntimeConfig = async (
baseConfig: WebpackConfig,
nextConfig: NextConfig
): Promise<void> => {
const definePluginConfig: Record<string, any> = {
// this mimics what nextjs does client side
// https://github.com/vercel/next.js/blob/57702cb2a9a9dba4b552e0007c16449cf36cfb44/packages/next/client/index.tsx#L101
Expand All @@ -67,5 +69,7 @@ const setupRuntimeConfig = (baseConfig: WebpackConfig, nextConfig: NextConfig):

definePluginConfig['process.env.__NEXT_NEW_LINK_BEHAVIOR'] = newNextLinkBehavior;

baseConfig.plugins?.push(new DefinePlugin(definePluginConfig));
// Load DefinePlugin with a dynamic import to ensure that Next.js can first
// replace webpack with its own internal instance, and we get that here.
baseConfig.plugins?.push(new (await import('webpack')).default.DefinePlugin(definePluginConfig));
};
44 changes: 29 additions & 15 deletions code/frameworks/nextjs/src/preset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,31 +10,29 @@ import type { ConfigItem, PluginItem, TransformOptions } from '@babel/core';
import { loadPartialConfig } from '@babel/core';
import semver from 'semver';

import { configureAliases } from './aliases/webpack';
import { configureBabelLoader } from './babel/loader';
import nextBabelPreset from './babel/preset';
import { configureCompatibilityAliases } from './compatibility/compatibility-map';
import { configureConfig } from './config/webpack';
import { configureCss } from './css/webpack';
import { configureNextExportMocks } from './export-mocks/webpack';
import { configureFastRefresh } from './fastRefresh/webpack';
import TransformFontImports from './font/babel';
import { configureNextFont } from './font/webpack/configureNextFont';
import { configureImages } from './images/webpack';
import { configureImports } from './imports/webpack';
import { configureNodePolyfills } from './nodePolyfills/webpack';
import { configureRSC } from './rsc/webpack';
import { configureStyledJsx } from './styledJsx/webpack';
import { configureSWCLoader } from './swc/loader';
import type { FrameworkOptions, StorybookConfig } from './types';
import { configureRuntimeNextjsVersionResolution, getNextjsVersion } from './utils';

export const addons: PresetProperty<'addons'> = [
dirname(require.resolve(join('@storybook/preset-react-webpack', 'package.json'))),
];

export const core: PresetProperty<'core'> = async (config, options) => {
const framework = await options.presets.apply('framework');
const framework = await options.presets.apply<StorybookConfig['framework']>('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.
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: typeof framework === 'string' ? undefined : framework.options.nextConfigPath,
});

return {
...config,
Expand Down Expand Up @@ -144,6 +142,22 @@ export const webpackFinal: StorybookConfig['webpackFinal'] = async (baseConfig,
nextConfigPath,
});

// Use dynamic imports to ensure these modules that use webpack load after
// Next.js has been configured (above), and has replaced webpack with its precompiled
// version.
const { configureNextFont } = await import('./font/webpack/configureNextFont');
const { configureRuntimeNextjsVersionResolution, getNextjsVersion } = await import('./utils');
const { configureImports } = await import('./imports/webpack');
const { configureCss } = await import('./css/webpack');
const { configureImages } = await import('./images/webpack');
const { configureStyledJsx } = await import('./styledJsx/webpack');
const { configureNodePolyfills } = await import('./nodePolyfills/webpack');
const { configureAliases } = await import('./aliases/webpack');
const { configureFastRefresh } = await import('./fastRefresh/webpack');
const { configureRSC } = await import('./rsc/webpack');
const { configureSWCLoader } = await import('./swc/loader');
const { configureBabelLoader } = await import('./babel/loader');

const babelRCPath = join(getProjectRoot(), '.babelrc');
const babelConfigPath = join(getProjectRoot(), 'babel.config.js');
const hasBabelConfig = existsSync(babelRCPath) || existsSync(babelConfigPath);
Expand Down

0 comments on commit cf24c98

Please sign in to comment.