Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions packages/plugin-react/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,7 @@ export default function viteReact(opts: Options = {}): Plugin[] {
return {
oxc: {
jsx: {
runtime: 'automatic',
importSource: jsxImportSource,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I needed to remove runtime too since rolldown-vite merge oxc option with tsconfig only when runtime === undefined. Is this intended or allow also runtime === 'automatic'? @sapphi-red https://github.com/vitejs/rolldown-vite/blob/f88cb05e755457fd9ea99174a017c49964510c3f/packages/vite/src/node/plugins/oxc.ts#L65-L68

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the vite-rolldown code as is, this would mean that users having jsx === 'preserve' in tsconfig will now have broken apps I think.
Is this also the same logic for the esbuild?

Copy link
Contributor Author

@hi-ogawa hi-ogawa Aug 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I didn't know react plugin is ensuring automatic so that tsconfig's jsx preserve will be ignored. Probably rolldown-vite oxc option merging needs to be tweaked. I'll also add that test case too then.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't know react plugin is ensuring automatic so that tsconfig's jsx preserve will be ignored
I'm not sure it's a goal, but with the current implementation of vite-rolldown it happen to be the case.

importSource: opts.jsxImportSource,
refresh: command === 'serve',
},
jsxRefreshInclude: include,
Expand All @@ -174,7 +173,8 @@ export default function viteReact(opts: Options = {}): Plugin[] {
return {
esbuild: {
jsx: 'automatic',
jsxImportSource: jsxImportSource,
// keep undefined by default so that vite's esbuild transform can prioritize jsxImportSource from tsconfig
jsxImportSource: opts.jsxImportSource,
},
optimizeDeps: { esbuildOptions: { jsx: 'automatic' } },
}
Expand Down
10 changes: 10 additions & 0 deletions playground/tsconfig/__tests__/tsconfig.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { expect, test } from 'vitest'
import { page } from '~utils'

test('respect tsconfig jsxImportSource', async () => {
await expect
.poll(() =>
page.getByTestId('emotion').evaluate((el) => getComputedStyle(el).color),
)
.toBe('rgb(255, 0, 0)')
})
2 changes: 2 additions & 0 deletions playground/tsconfig/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<div id="app"></div>
<script type="module" src="./src/main.tsx"></script>
21 changes: 21 additions & 0 deletions playground/tsconfig/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"name": "@vitejs/test-react-tsconfig",
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"debug": "node --inspect-brk vite",
"preview": "vite preview"
},
"dependencies": {
"@emotion/react": "^11.14.0",
"react": "^19.1.1",
"react-dom": "^19.1.1"
},
"devDependencies": {
"@types/react": "^19.1.9",
"@types/react-dom": "^19.1.7",
"@vitejs/plugin-react": "workspace:*"
}
}
7 changes: 7 additions & 0 deletions playground/tsconfig/src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default function App() {
return (
<div data-testid="emotion" css={{ color: 'rgb(255, 0, 0)' }}>
This should be red
</div>
)
}
4 changes: 4 additions & 0 deletions playground/tsconfig/src/main.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import ReactDOM from 'react-dom/client'
import App from './App.jsx'

ReactDOM.createRoot(document.getElementById('app')!).render(<App />)
26 changes: 26 additions & 0 deletions playground/tsconfig/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"include": ["src"],
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"types": ["vite/client"],
"module": "ESNext",
"skipLibCheck": true,

/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"jsxImportSource": "@emotion/react",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can update the playground/emotion to comment the manual jsxImportSource (saying we expect to be infered from tsconfig)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea. I should reuse that but I'm not sure how to get esbuild to pickup tsconfig for jsx. I'll update the example to tsx in a later PR and remove this one.


/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
}
}
6 changes: 6 additions & 0 deletions playground/tsconfig/vite.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import react from '@vitejs/plugin-react'
import { defineConfig } from 'vite'

export default defineConfig({
plugins: [react()],
})
30 changes: 30 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading