Skip to content

Commit

Permalink
Support React 19
Browse files Browse the repository at this point in the history
  • Loading branch information
matthewp committed May 3, 2024
1 parent 9a231a4 commit fd218d2
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 21 deletions.
5 changes: 5 additions & 0 deletions .changeset/short-phones-breathe.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@astrojs/react": patch
---

Support React 19
4 changes: 2 additions & 2 deletions packages/integrations/react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@
"peerDependencies": {
"@types/react": "^17.0.50 || ^18.0.21",
"@types/react-dom": "^17.0.17 || ^18.0.6",
"react": "^17.0.2 || ^18.0.0",
"react-dom": "^17.0.2 || ^18.0.0"
"react": "^17.0.2 || ^18.0.0 || ^19.0.0-beta",
"react-dom": "^17.0.2 || ^18.0.0 || ^19.0.0-beta"
},
"engines": {
"node": "^18.17.1 || ^20.3.0 || >=21.0.0"
Expand Down
67 changes: 48 additions & 19 deletions packages/integrations/react/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,44 @@ export type ReactIntegrationOptions = Pick<

const FAST_REFRESH_PREAMBLE = react.preambleCode;

function getRenderer() {
const versionsConfig = {
17: {
server: '@astrojs/react/server-v17.js',
client: '@astrojs/react/client-v17.js',
externals: ['react-dom/server.js', 'react-dom/client.js'],
},
18: {
server: '@astrojs/react/server.js',
client: '@astrojs/react/client.js',
externals: ['react-dom/server', 'react-dom/client']
},
19: {
server: '@astrojs/react/server.js',
client: '@astrojs/react/client.js',
externals: ['react-dom/server', 'react-dom/client']
}
};

type SupportedReactVersion = keyof (typeof versionsConfig);
type ReactVersionConfig = (typeof versionsConfig)[SupportedReactVersion];

function getReactMajorVersion(): number {
const matches = /[0-9]+\./.exec(ReactVersion);
if(!matches) {
return NaN;
}
return Number(matches[0]);
}

function isUnsupportedVersion(majorVersion: number) {
return majorVersion < 17 || majorVersion > 19 || Number.isNaN(majorVersion);
}

function getRenderer(reactConfig: ReactVersionConfig) {
return {
name: '@astrojs/react',
clientEntrypoint: ReactVersion.startsWith('18.')
? '@astrojs/react/client.js'
: '@astrojs/react/client-v17.js',
serverEntrypoint: ReactVersion.startsWith('18.')
? '@astrojs/react/server.js'
: '@astrojs/react/server-v17.js',
clientEntrypoint: reactConfig.client,
serverEntrypoint: reactConfig.server,
};
}

Expand Down Expand Up @@ -51,32 +80,26 @@ function getViteConfiguration({
exclude,
babel,
experimentalReactChildren,
}: ReactIntegrationOptions = {}) {
}: ReactIntegrationOptions = {}, reactConfig: ReactVersionConfig) {
return {
optimizeDeps: {
include: [
ReactVersion.startsWith('18.')
? '@astrojs/react/client.js'
: '@astrojs/react/client-v17.js',
reactConfig.client,
'react',
'react/jsx-runtime',
'react/jsx-dev-runtime',
'react-dom',
],
exclude: [
ReactVersion.startsWith('18.')
? '@astrojs/react/server.js'
: '@astrojs/react/server-v17.js',
reactConfig.server,
],
},
plugins: [react({ include, exclude, babel }), optionsPlugin(!!experimentalReactChildren)],
resolve: {
dedupe: ['react', 'react-dom', 'react-dom/server'],
},
ssr: {
external: ReactVersion.startsWith('18.')
? ['react-dom/server', 'react-dom/client']
: ['react-dom/server.js', 'react-dom/client.js'],
external: reactConfig.externals,
noExternal: [
// These are all needed to get mui to work.
'@mui/material',
Expand All @@ -95,13 +118,19 @@ export default function ({
babel,
experimentalReactChildren,
}: ReactIntegrationOptions = {}): AstroIntegration {
const majorVersion = getReactMajorVersion();
if(isUnsupportedVersion(majorVersion)) {
throw new Error(`Unsupported version`);
}
const versionConfig = versionsConfig[majorVersion as SupportedReactVersion];

return {
name: '@astrojs/react',
hooks: {
'astro:config:setup': ({ command, addRenderer, updateConfig, injectScript }) => {
addRenderer(getRenderer());
addRenderer(getRenderer(versionConfig));
updateConfig({
vite: getViteConfiguration({ include, exclude, babel, experimentalReactChildren }),
vite: getViteConfiguration({ include, exclude, babel, experimentalReactChildren }, versionConfig),
});
if (command === 'dev') {
const preamble = FAST_REFRESH_PREAMBLE.replace(`__BASE__`, '/');
Expand Down

0 comments on commit fd218d2

Please sign in to comment.