Files
cloudflare__vinext/tests/jsx-in-js.test.ts
James Anderson 81d5426ee6 fix: enable JSX in plain .js files (Next.js compat) (#1199)
* fix: enable JSX in plain .js files (Next.js compat)

Add vinext:jsx-in-js transform plugin to handle JSX in plain .js files.
Next.js allows JSX in .js files (Babel/SWC handle it transparently),
but Vite 8's built-in vite:oxc plugin excludes .js files by default
(exclude: /\.js$/) AND infers lang: "js" from the extension (which
disables JSX parsing). Neither can be fixed via config alone.

The plugin runs with enforce: "pre" before vite:oxc, transforming .js
files with OXC using lang: "jsx" so JSX is compiled before vite:oxc
sees the code.

Tested: 972 tests pass (jsx-in-js + shims + routing), zero regressions.

* fix: suppress rules-of-hooks lint for Playwright fixture use()

The oxlint-disable-next-line only covered the function signature line,
not the use() call deeper in the function body. Use block-scoped
disable/enable to suppress the entire fixture definition.
2026-05-14 13:49:33 +01:00

47 lines
1.6 KiB
TypeScript

/**
* Test: JSX in plain .js files
*
* Next.js allows JSX syntax in .js files (Babel/SWC handle it transparently).
* Vite 8's OXC transform defaults exclude .js files (include: /\.(m?ts|[jt]sx)$/,
* exclude: /\.js$/). vinext overrides these defaults to match Next.js behavior.
*
* Without the fix, .js files containing JSX would fail with:
* "Unexpected JSX expression" (OXC parse error)
*/
import { describe, it, expect, beforeAll, afterAll } from "vite-plus/test";
import type { ViteDevServer } from "vite-plus";
import { APP_FIXTURE_DIR, startFixtureServer, fetchHtml } from "./helpers.js";
describe("JSX in plain .js files", () => {
let server: ViteDevServer;
let baseUrl: string;
beforeAll(async () => {
({ server, baseUrl } = await startFixtureServer(APP_FIXTURE_DIR, {
appRouter: true,
}));
// Warm up
await fetch(`${baseUrl}/`).catch(() => {});
}, 60_000);
afterAll(async () => {
await server?.close();
});
it("should render a page component defined in a .js file with JSX", async () => {
const { res, html } = await fetchHtml(baseUrl, "/nextjs-compat/jsx-in-js");
expect(res.status).toBe(200);
expect(html).toContain("Hello JSX in JS");
expect(html).toContain("jsx-in-js");
});
it("should not produce 'Unexpected JSX expression' errors for .js files", async () => {
const { res, html } = await fetchHtml(baseUrl, "/nextjs-compat/jsx-in-js");
// If OXC fails to parse JSX in .js, the response would contain an error message
expect(html).not.toContain("Unexpected");
expect(html).not.toContain("PARSE_ERROR");
expect(res.status).toBe(200);
});
});