From f1964dd8e2b2c4c8711b70e00b8dcb1f1f60cc5b Mon Sep 17 00:00:00 2001 From: Valentin Palkovic Date: Fri, 6 Sep 2024 11:46:32 +0200 Subject: [PATCH] Fix Webpack aliasing --- code/frameworks/nextjs/src/config/webpack.ts | 30 +++++++++----------- code/frameworks/nextjs/src/utils.ts | 20 +++++++------ code/renderers/react/src/act-compat.ts | 5 +--- 3 files changed, 27 insertions(+), 28 deletions(-) diff --git a/code/frameworks/nextjs/src/config/webpack.ts b/code/frameworks/nextjs/src/config/webpack.ts index 57e7caa47bbe..337b3c574986 100644 --- a/code/frameworks/nextjs/src/config/webpack.ts +++ b/code/frameworks/nextjs/src/config/webpack.ts @@ -2,7 +2,7 @@ import type { NextConfig } from 'next'; import type { Configuration as WebpackConfig } from 'webpack'; import { DefinePlugin } from 'webpack'; -import { addScopedAlias, resolveNextConfig } from '../utils'; +import { addScopedAlias, resolveNextConfig, setAlias } from '../utils'; const tryResolve = (path: string) => { try { @@ -20,33 +20,31 @@ export const configureConfig = async ({ nextConfigPath?: string; }): Promise => { const nextConfig = await resolveNextConfig({ nextConfigPath }); - baseConfig.resolve ??= {}; - baseConfig.resolve.alias ??= {}; - const aliasConfig = baseConfig.resolve.alias; addScopedAlias(baseConfig, 'next/config'); + + // @ts-expect-error We know that alias is an object + if (baseConfig.resolve?.alias?.['react-dom']) { + // Removing the alias to react-dom to avoid conflicts with the alias we are setting + // because the react-dom alias is an exact match and we need to alias separate parts of react-dom + // in different places + // @ts-expect-error We know that alias is an object + delete baseConfig.resolve.alias?.['react-dom']; + } + if (tryResolve('next/dist/compiled/react')) { addScopedAlias(baseConfig, 'react', 'next/dist/compiled/react'); } if (tryResolve('next/dist/compiled/react-dom/cjs/react-dom-test-utils.production.js')) { - addScopedAlias( + setAlias( baseConfig, 'react-dom/test-utils', 'next/dist/compiled/react-dom/cjs/react-dom-test-utils.production.js' ); - } else { - const name = 'react-dom/test-utils'; - if (Array.isArray(aliasConfig)) { - aliasConfig.push({ - name, - alias: name, - }); - } else { - aliasConfig[name] = name; - } } if (tryResolve('next/dist/compiled/react-dom')) { - addScopedAlias(baseConfig, 'react-dom', 'next/dist/compiled/react-dom'); + setAlias(baseConfig, 'react-dom$', 'next/dist/compiled/react-dom'); + setAlias(baseConfig, 'react-dom/server', 'next/dist/compiled/react-dom/server'); } setupRuntimeConfig(baseConfig, nextConfig); diff --git a/code/frameworks/nextjs/src/utils.ts b/code/frameworks/nextjs/src/utils.ts index 9c8abc6c88c8..198917513166 100644 --- a/code/frameworks/nextjs/src/utils.ts +++ b/code/frameworks/nextjs/src/utils.ts @@ -27,23 +27,27 @@ export const resolveNextConfig = async ({ return loadConfig(PHASE_DEVELOPMENT_SERVER, dir, undefined); }; -// This is to help the addon in development -// Without it, webpack resolves packages in its node_modules instead of the example's node_modules -export const addScopedAlias = (baseConfig: WebpackConfig, name: string, alias?: string): void => { +export function setAlias(baseConfig: WebpackConfig, name: string, alias: string) { baseConfig.resolve ??= {}; baseConfig.resolve.alias ??= {}; const aliasConfig = baseConfig.resolve.alias; - const scopedAlias = scopedResolve(`${alias ?? name}`); - if (Array.isArray(aliasConfig)) { aliasConfig.push({ name, - alias: scopedAlias, + alias, }); } else { - aliasConfig[name] = scopedAlias; + aliasConfig[name] = alias; } +} + +// This is to help the addon in development +// Without it, webpack resolves packages in its node_modules instead of the example's node_modules +export const addScopedAlias = (baseConfig: WebpackConfig, name: string, alias?: string): void => { + const scopedAlias = scopedResolve(`${alias ?? name}`); + + setAlias(baseConfig, name, scopedAlias); }; /** @@ -64,7 +68,7 @@ export const scopedResolve = (id: string): string => { let scopedModulePath; try { - // TODO: Remove in next major release (SB 8.0) and use the statement in the catch block per default instead + // TODO: Remove in next major release (SB 9.0) and use the statement in the catch block per default instead scopedModulePath = require.resolve(id, { paths: [resolve()] }); } catch (e) { scopedModulePath = require.resolve(id); diff --git a/code/renderers/react/src/act-compat.ts b/code/renderers/react/src/act-compat.ts index 31b4fb72e54f..3eab722d3bb1 100644 --- a/code/renderers/react/src/act-compat.ts +++ b/code/renderers/react/src/act-compat.ts @@ -10,10 +10,7 @@ declare const globalThis: { const reactAct = // @ts-expect-error act might not be available in some versions of React - typeof React.act === 'function' - ? // @ts-expect-error act might not be available in some versions of React - React.act - : DeprecatedReactTestUtils.act ?? (async (cb: () => Promise | void) => cb()); + typeof React.act === 'function' ? React.act : DeprecatedReactTestUtils.act; export function setReactActEnvironment(isReactActEnvironment: boolean) { globalThis.IS_REACT_ACT_ENVIRONMENT = isReactActEnvironment;