Skip to content

Commit

Permalink
Use an alias for react-dom/client if not installed (#410)
Browse files Browse the repository at this point in the history
This implements a suggestion in vitejs/vite#6007 (comment)
to alias react-dom/client to our placeholder file when the dependency is not found.

In vite 3.0, our current approach will no longer work, and we'll need to use this method instead.
  • Loading branch information
IanVS authored Jun 16, 2022
1 parent 305b51f commit 3d4b66b
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 26 deletions.
28 changes: 18 additions & 10 deletions packages/builder-vite/code-generator-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import { virtualAddonSetupFile, virtualFileId, virtualPreviewFile, virtualStorie
export function codeGeneratorPlugin(options: ExtendedOptions): Plugin {
const iframePath = path.resolve(__dirname, '..', 'input', 'iframe.html');
let iframeId: string;
let projRoot: string;

// noinspection JSUnusedGlobalSymbols
return {
Expand Down Expand Up @@ -59,9 +58,23 @@ export function codeGeneratorPlugin(options: ExtendedOptions): Plugin {
input: iframePath,
};
}

// Detect if react 18 is installed. If not, alias it to a virtual placeholder file.
try {
require.resolve('react-dom/client', { paths: [config.root || process.cwd()] });
} catch (e) {
if (isNodeError(e) && e.code === 'MODULE_NOT_FOUND') {
config.resolve = {
...config.resolve,
alias: {
...config.resolve?.alias,
'react-dom/client': path.resolve(__dirname, '..', 'input', 'react-dom-client-placeholder.js'),
},
};
}
}
},
configResolved(config) {
projRoot = config.root;
iframeId = `${config.root}/iframe.html`;
},
resolveId(source) {
Expand All @@ -75,14 +88,6 @@ export function codeGeneratorPlugin(options: ExtendedOptions): Plugin {
return virtualPreviewFile;
} else if (source === virtualAddonSetupFile) {
return virtualAddonSetupFile;
// Avoid error in react < 18 projects
} else if (source === 'react-dom/client') {
try {
return require.resolve('react-dom/client', { paths: [projRoot] });
} catch (e) {
// This is not a react 18 project, need to stub out to avoid error
return path.resolve(__dirname, '..', 'input', 'react-dom-client-placeholder.js');
}
}
},
async load(id) {
Expand Down Expand Up @@ -123,3 +128,6 @@ export function codeGeneratorPlugin(options: ExtendedOptions): Plugin {
},
};
}

// Refines an error received from 'catch' to be a NodeJS exception
const isNodeError = (error: unknown): error is NodeJS.ErrnoException => error instanceof Error;
16 changes: 0 additions & 16 deletions packages/builder-vite/optimizeDeps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,17 +109,6 @@ export async function getOptimizeDeps(
const stories = absoluteStories.map((storyPath) => normalizePath(path.relative(root, storyPath)));
const resolvedConfig = await resolveConfig(config, 'serve', 'development');

const exclude = [];
// This is necessary to support react < 18 with new versions of @storybook/react that support react 18.
// TODO: narrow this down to just framework === 'react'. But causes a vue dev start problem in this monorepo.
try {
require.resolve('react-dom/client', { paths: [config.root] });
} catch (e) {
if (isNodeError(e) && e.code === 'MODULE_NOT_FOUND') {
exclude.push('react-dom/client');
}
}

// This function converts ids which might include ` > ` to a real path, if it exists on disk.
// See https://github.com/vitejs/vite/blob/67d164392e8e9081dc3f0338c4b4b8eea6c5f7da/packages/vite/src/node/optimizer/index.ts#L182-L199
const resolve = resolvedConfig.createResolver({ asSrc: false });
Expand All @@ -131,10 +120,5 @@ export async function getOptimizeDeps(
// We need Vite to precompile these dependencies, because they contain non-ESM code that would break
// if we served it directly to the browser.
include,
// In some cases we need to prevent deps from being pre-bundled
exclude,
};
}

// Refines an error received from 'catch' to be a NodeJS exception
const isNodeError = (error: unknown): error is NodeJS.ErrnoException => error instanceof Error;

0 comments on commit 3d4b66b

Please sign in to comment.