From 6245632736847d440e2e02dd3b3770fb85dfca64 Mon Sep 17 00:00:00 2001 From: Evan Bacon Date: Wed, 27 Mar 2024 20:21:10 -0500 Subject: [PATCH] chore(babel): simplify rsc injection code (#27879) # Why The injection code is a bit of a hack to workaround Metro, this PR simplifies the transform so we can work on improving it in the future. --------- Co-authored-by: Expo Bot <34669131+expo-bot@users.noreply.github.com> --- packages/babel-preset-expo/CHANGELOG.md | 1 + .../build/client-module-proxy-plugin.d.ts | 8 +- .../build/client-module-proxy-plugin.js | 76 +++------ .../client-module-proxy-plugin.test.ts.snap | 9 +- .../src/client-module-proxy-plugin.ts | 146 +++--------------- 5 files changed, 47 insertions(+), 193 deletions(-) diff --git a/packages/babel-preset-expo/CHANGELOG.md b/packages/babel-preset-expo/CHANGELOG.md index bc2307d0a8f69..955780587bdc4 100644 --- a/packages/babel-preset-expo/CHANGELOG.md +++ b/packages/babel-preset-expo/CHANGELOG.md @@ -23,6 +23,7 @@ - Add additional tests for undefined platform minification behavior. ([#27515](https://github.com/expo/expo/pull/27515) by [@EvanBacon](https://github.com/EvanBacon)) - Upgrade `babel-plugin-react-native-web` for latest `react-native-web` aliases. ([#27214](https://github.com/expo/expo/pull/27214) by [@EvanBacon](https://github.com/EvanBacon)) - Directly resolve plugins. ([#27041](https://github.com/expo/expo/pull/27041) by [@EvanBacon](https://github.com/EvanBacon)) +- Simplify react server code injection by using more expensive template code. ([#27879](https://github.com/expo/expo/pull/27879) by [@EvanBacon](https://github.com/EvanBacon)) ## 10.0.1 - 2023-12-19 diff --git a/packages/babel-preset-expo/build/client-module-proxy-plugin.d.ts b/packages/babel-preset-expo/build/client-module-proxy-plugin.d.ts index 232d80f39f973..4e9b984e99396 100644 --- a/packages/babel-preset-expo/build/client-module-proxy-plugin.d.ts +++ b/packages/babel-preset-expo/build/client-module-proxy-plugin.d.ts @@ -1,7 +1 @@ -/** - * Copyright © 2024 650 Industries. - */ -import { ConfigAPI, types } from '@babel/core'; -export declare function reactClientReferencesPlugin(api: ConfigAPI & { - types: typeof types; -}): babel.PluginObj; +export declare function reactClientReferencesPlugin(): babel.PluginObj; diff --git a/packages/babel-preset-expo/build/client-module-proxy-plugin.js b/packages/babel-preset-expo/build/client-module-proxy-plugin.js index 34344405302bb..0453b9f48031d 100644 --- a/packages/babel-preset-expo/build/client-module-proxy-plugin.js +++ b/packages/babel-preset-expo/build/client-module-proxy-plugin.js @@ -4,10 +4,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) { }; Object.defineProperty(exports, "__esModule", { value: true }); exports.reactClientReferencesPlugin = void 0; +/** + * Copyright © 2024 650 Industries. + */ +const core_1 = require("@babel/core"); const url_1 = __importDefault(require("url")); -function reactClientReferencesPlugin(api) { - const { types: t } = api; - const reactServerAdapter = 'react-server-dom-webpack/server'; +function reactClientReferencesPlugin() { return { name: 'expo-client-references', visitor: { @@ -33,63 +35,21 @@ function reactClientReferencesPlugin(api) { if (isUseClient) { path.node.body = []; path.node.directives = []; - // Inject the following: - // - // module.exports = require('react-server-dom-webpack/server').createClientModuleProxy(`${outputKey}#${filePath}`) - // TODO: Use `require.resolveWeak` instead of `filePath` to avoid leaking the file path. - // module.exports = require('react-server-dom-webpack/server').createClientModuleProxy(`${outputKey}#${require.resolveWeak(filePath)}`) - path.pushContainer('body', t.expressionStatement(t.assignmentExpression('=', t.memberExpression(t.identifier('module'), t.identifier('exports')), t.callExpression(t.memberExpression(t.callExpression(t.identifier('require'), [ - t.stringLiteral(reactServerAdapter), - ]), t.identifier('createClientModuleProxy')), - // `${outputKey}#${require.resolveWeak(filePath)}` - [t.stringLiteral(outputKey)])))); + path.pushContainer('body', core_1.template.ast `module.exports = require("react-server-dom-webpack/server").createClientModuleProxy(${JSON.stringify(outputKey)});`); } else { - // Inject the following: - // - // ;(() => { - // const { registerServerReference } = require('react-server-dom-webpack/server'); - // if (typeof module.exports === 'function') registerServerReference(module.exports, moduleId, null); - // else { - // for (const key in module.exports) { - // if (typeof module.exports[key] === 'function') { - // registerServerReference(module.exports[key], moduleId, key); - // } - // } - // } - // })() - const mmexp = t.memberExpression(t.callExpression(t.identifier('require'), [t.stringLiteral(reactServerAdapter)]), t.identifier('registerServerReference')); - // Create the loop body - const loopBody = t.blockStatement([ - t.ifStatement(t.binaryExpression('===', t.unaryExpression('typeof', t.memberExpression(t.memberExpression(t.identifier('module'), t.identifier('exports')), t.identifier('key'), true)), t.stringLiteral('function')), t.expressionStatement(t.callExpression(mmexp, [ - t.memberExpression(t.memberExpression(t.identifier('module'), t.identifier('exports')), t.identifier('key'), true), - t.stringLiteral(outputKey), - t.identifier('key'), - ]))), - ]); - // Create the for-in loop - const forInStatement = t.forInStatement(t.variableDeclaration('const', [t.variableDeclarator(t.identifier('key'))]), t.memberExpression(t.identifier('module'), t.identifier('exports')), loopBody); - path.pushContainer('body', t.expressionStatement(t.callExpression(t.arrowFunctionExpression([], t.blockStatement([ - t.ifStatement(t.binaryExpression('===', t.unaryExpression('typeof', t.memberExpression(t.identifier('module'), t.identifier('exports'))), t.stringLiteral('function')), - // registerServerReference(module.exports, moduleId, null); - t.blockStatement([ - t.expressionStatement(t.callExpression(mmexp, [ - t.memberExpression(t.identifier('module'), t.identifier('exports')), - t.stringLiteral(outputKey), - t.nullLiteral(), - ])), - ]), - // Else - t.blockStatement([ - // for (const key in module.exports) { - // if (typeof module.exports[key] === 'function') { - // registerServerReference(module.exports[key], moduleId, key); - // } - // } - forInStatement, - ])), - ])), []))); - // + path.pushContainer('body', core_1.template.ast ` + ;(() => { + if (typeof module.exports === 'function') { + require('react-server-dom-webpack/server').registerServerReference(module.exports, ${JSON.stringify(outputKey)}, null); + } else { + for (const key in module.exports) { + if (typeof module.exports[key] === 'function') { + require('react-server-dom-webpack/server').registerServerReference(module.exports[key], ${JSON.stringify(outputKey)}, key); + } + } + } + })()`); } }, }, diff --git a/packages/babel-preset-expo/src/__tests__/__snapshots__/client-module-proxy-plugin.test.ts.snap b/packages/babel-preset-expo/src/__tests__/__snapshots__/client-module-proxy-plugin.test.ts.snap index ac8ae67cab26b..adf28a7c53924 100644 --- a/packages/babel-preset-expo/src/__tests__/__snapshots__/client-module-proxy-plugin.test.ts.snap +++ b/packages/babel-preset-expo/src/__tests__/__snapshots__/client-module-proxy-plugin.test.ts.snap @@ -19,12 +19,15 @@ exports[`use server replaces server action exports with React server references export var greet = function greet(name) { return \`Hello \${name} from server!\`; }; +; (function () { - if (typeof module.exports === "function") { - require("react-server-dom-webpack/server").registerServerReference(module.exports, "file:///unknown", null); + if (typeof module.exports === 'function') { + require('react-server-dom-webpack/server').registerServerReference(module.exports, "file:///unknown", null); } else { for (var key in module.exports) { - if (typeof module.exports[key] === "function") require("react-server-dom-webpack/server").registerServerReference(module.exports[key], "file:///unknown", key); + if (typeof module.exports[key] === 'function') { + require('react-server-dom-webpack/server').registerServerReference(module.exports[key], "file:///unknown", key); + } } } })();" diff --git a/packages/babel-preset-expo/src/client-module-proxy-plugin.ts b/packages/babel-preset-expo/src/client-module-proxy-plugin.ts index 25a44615a9128..e39bd3d74f9bd 100644 --- a/packages/babel-preset-expo/src/client-module-proxy-plugin.ts +++ b/packages/babel-preset-expo/src/client-module-proxy-plugin.ts @@ -1,14 +1,10 @@ /** * Copyright © 2024 650 Industries. */ -import { ConfigAPI, types } from '@babel/core'; +import { template } from '@babel/core'; import url from 'url'; -export function reactClientReferencesPlugin( - api: ConfigAPI & { types: typeof types } -): babel.PluginObj { - const { types: t } = api; - const reactServerAdapter = 'react-server-dom-webpack/server'; +export function reactClientReferencesPlugin(): babel.PluginObj { return { name: 'expo-client-references', visitor: { @@ -44,132 +40,32 @@ export function reactClientReferencesPlugin( if (isUseClient) { path.node.body = []; path.node.directives = []; - - // Inject the following: - // - // module.exports = require('react-server-dom-webpack/server').createClientModuleProxy(`${outputKey}#${filePath}`) - // TODO: Use `require.resolveWeak` instead of `filePath` to avoid leaking the file path. - // module.exports = require('react-server-dom-webpack/server').createClientModuleProxy(`${outputKey}#${require.resolveWeak(filePath)}`) path.pushContainer( 'body', - t.expressionStatement( - t.assignmentExpression( - '=', - t.memberExpression(t.identifier('module'), t.identifier('exports')), - t.callExpression( - t.memberExpression( - t.callExpression(t.identifier('require'), [ - t.stringLiteral(reactServerAdapter), - ]), - t.identifier('createClientModuleProxy') - ), - // `${outputKey}#${require.resolveWeak(filePath)}` - [t.stringLiteral(outputKey)] - ) - ) - ) + template.ast`module.exports = require("react-server-dom-webpack/server").createClientModuleProxy(${JSON.stringify( + outputKey + )});` ); } else { - // Inject the following: - // - // ;(() => { - // const { registerServerReference } = require('react-server-dom-webpack/server'); - // if (typeof module.exports === 'function') registerServerReference(module.exports, moduleId, null); - // else { - // for (const key in module.exports) { - // if (typeof module.exports[key] === 'function') { - // registerServerReference(module.exports[key], moduleId, key); - // } - // } - // } - // })() - - const mmexp = t.memberExpression( - t.callExpression(t.identifier('require'), [t.stringLiteral(reactServerAdapter)]), - t.identifier('registerServerReference') - ); - - // Create the loop body - const loopBody = t.blockStatement([ - t.ifStatement( - t.binaryExpression( - '===', - t.unaryExpression( - 'typeof', - t.memberExpression( - t.memberExpression(t.identifier('module'), t.identifier('exports')), - t.identifier('key'), - true - ) - ), - t.stringLiteral('function') - ), - t.expressionStatement( - t.callExpression(mmexp, [ - t.memberExpression( - t.memberExpression(t.identifier('module'), t.identifier('exports')), - t.identifier('key'), - true - ), - t.stringLiteral(outputKey), - t.identifier('key'), - ]) - ) - ), - ]); - - // Create the for-in loop - const forInStatement = t.forInStatement( - t.variableDeclaration('const', [t.variableDeclarator(t.identifier('key'))]), - t.memberExpression(t.identifier('module'), t.identifier('exports')), - loopBody - ); - path.pushContainer( 'body', - t.expressionStatement( - t.callExpression( - t.arrowFunctionExpression( - [], - - t.blockStatement([ - t.ifStatement( - t.binaryExpression( - '===', - t.unaryExpression( - 'typeof', - t.memberExpression(t.identifier('module'), t.identifier('exports')) - ), - t.stringLiteral('function') - ), - // registerServerReference(module.exports, moduleId, null); - t.blockStatement([ - t.expressionStatement( - t.callExpression(mmexp, [ - t.memberExpression(t.identifier('module'), t.identifier('exports')), - t.stringLiteral(outputKey), - t.nullLiteral(), - ]) - ), - ]), - // Else - t.blockStatement([ - // for (const key in module.exports) { - // if (typeof module.exports[key] === 'function') { - // registerServerReference(module.exports[key], moduleId, key); - // } - // } - forInStatement, - ]) - ), - ]) - ), - [] - ) - ) + template.ast` + ;(() => { + if (typeof module.exports === 'function') { + require('react-server-dom-webpack/server').registerServerReference(module.exports, ${JSON.stringify( + outputKey + )}, null); + } else { + for (const key in module.exports) { + if (typeof module.exports[key] === 'function') { + require('react-server-dom-webpack/server').registerServerReference(module.exports[key], ${JSON.stringify( + outputKey + )}, key); + } + } + } + })()` ); - - // } }, },