Skip to content

Commit 95039b7

Browse files
authored
Added additional support to wrapping the default export specifier (#201)
* Added additional support to wrapping the default export specifier * Added additional support to wrapping the default export specifier * version bump
1 parent 1ac6ca5 commit 95039b7

File tree

4 files changed

+89
-3
lines changed

4 files changed

+89
-3
lines changed

Diff for: package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "react-router-devtools",
33
"description": "Devtools for React Router - debug, trace, find hydration errors, catch bugs and inspect server/client data with react-router-devtools",
44
"author": "Alem Tuzlak",
5-
"version": "1.1.9",
5+
"version": "1.1.10",
66
"license": "MIT",
77
"keywords": [
88
"react-router",

Diff for: src/vite/utils/inject-client.test.ts

+50
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,56 @@ describe("transform", () => {
137137
expect(removeWhitespace(result.code)).toStrictEqual(expected)
138138
})
139139

140+
it("should wrap the default export properly even if it's declared as a variable and then exported via export { name as default }", () => {
141+
const result = injectRdtClient(
142+
`
143+
const App = () => {};
144+
export { App as default };
145+
`,
146+
'{ "config": { }, "plugins": "[]" }',
147+
"",
148+
"/file/path"
149+
)
150+
const expected = removeWhitespace(`
151+
import { withViteDevTools as _withViteDevTools } from "react-router-devtools/client";
152+
import rdtStylesheet from "react-router-devtools/client.css?url";
153+
const App = () => {};
154+
export default _withViteDevTools(App, {
155+
config: { },
156+
plugins: []
157+
});
158+
export const links = () => [{ rel: "stylesheet", href: rdtStylesheet }];
159+
`)
160+
expect(removeWhitespace(result.code)).toStrictEqual(expected)
161+
})
162+
163+
it("should wrap the default export properly even if it's declared as a variable and then exported via export { name as default } and has other exports as well", () => {
164+
const result = injectRdtClient(
165+
`
166+
import { test } from "./file/path";
167+
const App = () => {};
168+
export { App as default, test };
169+
`,
170+
'{ "config": { }, "plugins": "[]" }',
171+
"",
172+
"/file/path"
173+
)
174+
const expected = removeWhitespace(`
175+
import { withViteDevTools as _withViteDevTools } from "react-router-devtools/client";
176+
import rdtStylesheet from "react-router-devtools/client.css?url";
177+
import { test } from "./file/path";
178+
const App = () => {};
179+
export default _withViteDevTools(App, {
180+
config: { },
181+
plugins: []
182+
});
183+
export { test };
184+
export const links = () => [{ rel: "stylesheet", href: rdtStylesheet }];
185+
186+
`)
187+
expect(removeWhitespace(result.code)).toStrictEqual(expected)
188+
})
189+
140190
it("should wrap the default export properly even if it's declared as a function and then exported", () => {
141191
const result = injectRdtClient(
142192
`

Diff for: src/vite/utils/inject-client.ts

+35-1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ const transform = (ast: ParseResult<Babel.File>, clientConfig: string) => {
3030
function uppercaseFirstLetter(str: string) {
3131
return str.charAt(0).toUpperCase() + str.slice(1)
3232
}
33+
const transformations: Array<() => void> = []
3334
trav(ast, {
3435
ExportDeclaration(path) {
3536
if (path.isExportDefaultDeclaration()) {
@@ -83,10 +84,43 @@ const transform = (ast: ParseResult<Babel.File>, clientConfig: string) => {
8384
])
8485
)
8586
}
87+
88+
// Handle `export { App as default };`
89+
const specifiers = path.node.specifiers
90+
for (const specifier of specifiers) {
91+
if (
92+
t.isExportSpecifier(specifier) &&
93+
t.isIdentifier(specifier.exported) &&
94+
specifier.exported.name === "default" &&
95+
t.isIdentifier(specifier.local)
96+
) {
97+
const localName = specifier.local.name
98+
const uid = getHocUid(path, "withViteDevTools")
99+
100+
// Insert the wrapped default export
101+
transformations.push(() => {
102+
path.insertBefore(
103+
t.exportDefaultDeclaration(t.callExpression(uid, [t.identifier(localName), clientConfigExpression]))
104+
)
105+
106+
// Remove the original export specifier
107+
const remainingSpecifiers = path.node.specifiers.filter(
108+
(s) => !(t.isExportSpecifier(s) && t.isIdentifier(s.exported) && s.exported.name === "default")
109+
)
110+
if (remainingSpecifiers.length > 0) {
111+
path.replaceWith(t.exportNamedDeclaration(null, remainingSpecifiers, path.node.source))
112+
} else {
113+
path.remove()
114+
}
115+
})
116+
}
117+
}
86118
}
87119
},
88120
})
89-
121+
for (const transformation of transformations) {
122+
transformation()
123+
}
90124
if (hocs.length > 0) {
91125
ast.program.body.unshift(
92126
t.importDeclaration(

Diff for: test-apps/react-router-vite/app/root.tsx

+3-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ export const action =async ({devTools}: ActionFunctionArgs) => {
4242
return ({ message: "Hello World", bigInt: BigInt(10) });
4343
}
4444

45-
export default function App() {
45+
function App() {
4646
return (
4747
<html lang="en">
4848
<head>
@@ -66,3 +66,5 @@ export default function App() {
6666
</html>
6767
);
6868
}
69+
70+
export { App as default }

0 commit comments

Comments
 (0)