diff --git a/.changeset/clever-months-swim.md b/.changeset/clever-months-swim.md
new file mode 100644
index 00000000000..b2891178dde
--- /dev/null
+++ b/.changeset/clever-months-swim.md
@@ -0,0 +1,5 @@
+---
+"@remix-run/dev": patch
+---
+
+Support JSX usage in `.jsx` files without manual `React` import in Vite
diff --git a/integration/vite-dev-test.ts b/integration/vite-dev-test.ts
index 18ec17b2f86..c948106e949 100644
--- a/integration/vite-dev-test.ts
+++ b/integration/vite-dev-test.ts
@@ -136,10 +136,10 @@ test.describe("Vite dev", () => {
);
}
`,
- "app/routes/non-ts.jsx": js`
- export default function Page() {
+ "app/routes/jsx.jsx": js`
+ export default function JsxRoute() {
return (
-
+
);
@@ -238,31 +238,32 @@ test.describe("Vite dev", () => {
);
});
- test("handle non-typescript jsx file", async ({ page }) => {
+ test("handles JSX in .jsx file without React import", async ({ page }) => {
let pageErrors: unknown[] = [];
page.on("pageerror", (error) => pageErrors.push(error));
- await page.goto(`http://localhost:${devPort}/non-ts`, {
+ await page.goto(`http://localhost:${devPort}/jsx`, {
waitUntil: "networkidle",
});
expect(pageErrors).toEqual([]);
- let hmrStatus = page.locator("#non-ts [data-hmr]");
+ let hmrStatus = page.locator("#jsx [data-hmr]");
await expect(hmrStatus).toHaveText("HMR updated: no");
let indexRouteContents = await fs.readFile(
- path.join(projectDir, "app/routes/non-ts.jsx"),
+ path.join(projectDir, "app/routes/jsx.jsx"),
"utf8"
);
await fs.writeFile(
- path.join(projectDir, "app/routes/non-ts.jsx"),
+ path.join(projectDir, "app/routes/jsx.jsx"),
indexRouteContents.replace("HMR updated: no", "HMR updated: yes"),
"utf8"
);
await page.waitForLoadState("networkidle");
await expect(hmrStatus).toHaveText("HMR updated: yes");
+
expect(pageErrors).toEqual([]);
- })
+ });
});
let bufferize = (stream: Readable): (() => string) => {
diff --git a/packages/remix-dev/vite/plugin.ts b/packages/remix-dev/vite/plugin.ts
index 9f48433346b..e580c2660d9 100644
--- a/packages/remix-dev/vite/plugin.ts
+++ b/packages/remix-dev/vite/plugin.ts
@@ -432,9 +432,9 @@ export const remixVitePlugin: RemixVitePlugin = (options = {}) => {
"react-dom/client",
],
},
- // for server module, JSX transpilation is done by vite's esbuild
esbuild: {
- jsx: 'automatic',
+ jsx: "automatic",
+ jsxDev: viteCommand !== "build",
},
resolve: {
// https://react.dev/warnings/invalid-hook-call-warning#duplicate-react