diff --git a/packages/plugin-react-swc/playground/bundled-dev/__tests__/bundled-dev.spec.ts b/packages/plugin-react-swc/playground/bundled-dev/__tests__/bundled-dev.spec.ts new file mode 100644 index 000000000..6fb03381c --- /dev/null +++ b/packages/plugin-react-swc/playground/bundled-dev/__tests__/bundled-dev.spec.ts @@ -0,0 +1,16 @@ +import { expect, test } from '@playwright/test' +import { setupDevServer } from '../../utils.ts' + +test('bundledDev mode does not throw config.server error', async ({ page }) => { + // The key verification: the dev server should start successfully + // without the "Cannot read properties of undefined (reading 'config')" error + // that the bug report (#1271) describes. + const { testUrl, server } = await setupDevServer('bundled-dev') + + // Verify the server responds to requests (no crash) + await page.goto(testUrl) + const bodyText = await page.textContent('body') + expect(bodyText).toBeTruthy() + + await server.close() +}) diff --git a/packages/plugin-react-swc/playground/bundled-dev/index.html b/packages/plugin-react-swc/playground/bundled-dev/index.html new file mode 100644 index 000000000..fb1aeef55 --- /dev/null +++ b/packages/plugin-react-swc/playground/bundled-dev/index.html @@ -0,0 +1,2 @@ +
+ diff --git a/packages/plugin-react-swc/playground/bundled-dev/package.json b/packages/plugin-react-swc/playground/bundled-dev/package.json new file mode 100644 index 000000000..da71b9337 --- /dev/null +++ b/packages/plugin-react-swc/playground/bundled-dev/package.json @@ -0,0 +1,20 @@ +{ + "name": "playground-bundled-dev", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "debug": "node --inspect-brk vite", + "preview": "vite preview" + }, + "dependencies": { + "react": "^19.2.7", + "react-dom": "^19.2.7" + }, + "devDependencies": { + "@types/react": "^19.2.17", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react-swc": "../../dist" + } +} diff --git a/packages/plugin-react-swc/playground/bundled-dev/src/App.tsx b/packages/plugin-react-swc/playground/bundled-dev/src/App.tsx new file mode 100644 index 000000000..7d9c3a262 --- /dev/null +++ b/packages/plugin-react-swc/playground/bundled-dev/src/App.tsx @@ -0,0 +1,14 @@ +import { useState } from 'react' + +export default function App() { + const [count, setCount] = useState(0) + + return ( + <> +

Hello Vite + React

+ + + ) +} diff --git a/packages/plugin-react-swc/playground/bundled-dev/src/main.tsx b/packages/plugin-react-swc/playground/bundled-dev/src/main.tsx new file mode 100644 index 000000000..1f5976c1d --- /dev/null +++ b/packages/plugin-react-swc/playground/bundled-dev/src/main.tsx @@ -0,0 +1,4 @@ +import ReactDOM from 'react-dom/client' +import App from './App.tsx' + +ReactDOM.createRoot(document.getElementById('app')!).render() diff --git a/packages/plugin-react-swc/playground/bundled-dev/tsconfig.json b/packages/plugin-react-swc/playground/bundled-dev/tsconfig.json new file mode 100644 index 000000000..195fe84e7 --- /dev/null +++ b/packages/plugin-react-swc/playground/bundled-dev/tsconfig.json @@ -0,0 +1,23 @@ +{ + "include": ["src"], + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM"], + "types": ["vite/client"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + } +} diff --git a/packages/plugin-react-swc/playground/bundled-dev/vite.config.ts b/packages/plugin-react-swc/playground/bundled-dev/vite.config.ts new file mode 100644 index 000000000..6c4b5d2b4 --- /dev/null +++ b/packages/plugin-react-swc/playground/bundled-dev/vite.config.ts @@ -0,0 +1,11 @@ +import react from '@vitejs/plugin-react-swc' +import { defineConfig } from 'vite' + +export default defineConfig({ + base: '/bundled-dev/', + server: { port: 8910 /* Should be unique */ }, + experimental: { + bundledDev: true, + }, + plugins: [react()], +}) diff --git a/packages/plugin-react-swc/src/index.ts b/packages/plugin-react-swc/src/index.ts index 50aee52bc..de0513940 100644 --- a/packages/plugin-react-swc/src/index.ts +++ b/packages/plugin-react-swc/src/index.ts @@ -78,6 +78,7 @@ const usingRolldown = 'rolldownVersion' in vite const react = (_options?: Options): Plugin[] => { let hmrDisabled = true + let isBundledDev = false let viteCacheRoot: string | undefined const options = { jsxImportSource: _options?.jsxImportSource ?? 'react', @@ -143,6 +144,9 @@ const react = (_options?: Options): Plugin[] => { }, configResolved(config) { viteCacheRoot = config.cacheDir + if (config.experimental.bundledDev) { + isBundledDev = true + } hmrDisabled = config.server.hmr === false const mdxIndex = config.plugins.findIndex( (p) => p.name === '@mdx-js/rollup', @@ -169,15 +173,25 @@ const react = (_options?: Options): Plugin[] => { } }, transformIndexHtml: (_, config) => { - if (!hmrDisabled) { + if (hmrDisabled) return + if (isBundledDev) { return [ { tag: 'script', attrs: { type: 'module' }, - children: getPreambleCode(config.server!.config.base), + // In bundled dev mode, the src does not go through the middlewares + // so we don't need to append the base + children: getPreambleCode('/'), }, ] } + return [ + { + tag: 'script', + attrs: { type: 'module' }, + children: getPreambleCode(config.server!.config.base), + }, + ] }, async transform(code, _id, transformOptions) { const id = _id.split('?')[0] diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ff4a4784f..91d305a9d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -165,6 +165,25 @@ importers: specifier: ../../dist version: link:../../dist + packages/plugin-react-swc/playground/bundled-dev: + dependencies: + react: + specifier: ^19.2.7 + version: 19.2.7 + react-dom: + specifier: ^19.2.7 + version: 19.2.7(react@19.2.7) + devDependencies: + '@types/react': + specifier: ^19.2.17 + version: 19.2.17 + '@types/react-dom': + specifier: ^19.2.3 + version: 19.2.3(@types/react@19.2.17) + '@vitejs/plugin-react-swc': + specifier: ../../dist + version: link:../../dist + packages/plugin-react-swc/playground/class-components: dependencies: react: