Skip to content

Commit 3035559

Browse files
committed
wip: fix framework props for reexported components
1 parent bb369c2 commit 3035559

File tree

1 file changed

+66
-0
lines changed

1 file changed

+66
-0
lines changed

packages/react-router-dev/vite/with-props.ts

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,72 @@ export const decorateComponentExportsWithProps = (
2222
return uid;
2323
}
2424

25+
/**
26+
* Rewrite any re-exports for named components (`default Component`, `HydrateFallback`, `ErrorBoundary`)
27+
* into `export const <name> = <expr>` form in preparation for adding props HOCs in the next traversal.
28+
*
29+
* Case 1: `export { name, ... }` or `export { value as name, ... }`
30+
* -> Rename `name` to `uid` where `uid` is a new unique identifier
31+
* -> Insert `export const name = uid`
32+
*
33+
* Case 2: `export { name1, value as name 2, ... } from "source"`
34+
* -> Insert `import { name as uid }` where `uid` is a new unique identifier
35+
* -> Insert `export const name = uid`
36+
*/
37+
traverse(ast, {
38+
ExportNamedDeclaration(path) {
39+
if (path.node.declaration) return;
40+
const { source } = path.node;
41+
42+
const exports: Array<{
43+
uid: Babel.Identifier;
44+
local: Babel.Identifier;
45+
exported: Babel.Identifier;
46+
}> = [];
47+
for (const specifier of path.get("specifiers")) {
48+
if (specifier.isExportSpecifier()) {
49+
const { local, exported } = specifier.node;
50+
const { name } = local;
51+
if (!t.isIdentifier(exported)) continue;
52+
const uid = path.scope.generateUidIdentifier(`_${name}`);
53+
if (exported.name === "default" || isNamedComponentExport(name)) {
54+
exports.push({ uid, local, exported });
55+
specifier.remove();
56+
}
57+
}
58+
}
59+
if (exports.length === 0) return;
60+
61+
if (source != null) {
62+
// `import { local as uid } from "source"`
63+
path.insertAfter([
64+
t.importDeclaration(
65+
exports.map(({ local, uid }) => t.importSpecifier(uid, local)),
66+
source,
67+
),
68+
]);
69+
} else {
70+
for (const { local, uid } of exports) {
71+
path.scope.getBinding(local.name)?.scope.rename(uid.name);
72+
}
73+
}
74+
75+
// `export const exported = uid`
76+
path.insertAfter(
77+
exports.map(({ uid, exported }) => {
78+
if (exported.name === "default") {
79+
return t.exportDefaultDeclaration(uid);
80+
}
81+
return t.exportNamedDeclaration(
82+
t.variableDeclaration("const", [
83+
t.variableDeclarator(exported, uid),
84+
]),
85+
);
86+
}),
87+
);
88+
},
89+
});
90+
2591
traverse(ast, {
2692
ExportDeclaration(path) {
2793
if (path.isExportDefaultDeclaration()) {

0 commit comments

Comments
 (0)