Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(babel): simplify rsc injection code #27879

Merged
merged 4 commits into from Mar 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/babel-preset-expo/CHANGELOG.md
Expand Up @@ -22,6 +22,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

Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

76 changes: 18 additions & 58 deletions packages/babel-preset-expo/build/client-module-proxy-plugin.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Expand Up @@ -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);
}
}
}
})();"
Expand Down
146 changes: 21 additions & 125 deletions 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: {
Expand Down Expand Up @@ -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);
}
}
}
})()`
);

//
}
},
},
Expand Down