Skip to content

Commit 44b9680

Browse files
Merge remote-tracking branch 'upstream/main' into chore-rsc-nightly
2 parents f270aee + 8e0e8b6 commit 44b9680

File tree

34 files changed

+628
-126
lines changed

34 files changed

+628
-126
lines changed

packages/plugin-react/src/index.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -175,12 +175,6 @@ export default function viteReact(opts: Options = {}): Plugin[] {
175175
config.command === 'build' ||
176176
config.server.hmr === false
177177

178-
if ('jsxPure' in opts) {
179-
config.logger.warnOnce(
180-
'[@vitejs/plugin-react] jsxPure was removed. You can configure esbuild.jsxSideEffects directly.',
181-
)
182-
}
183-
184178
const hooks: ReactBabelHook[] = config.plugins
185179
.map((plugin) => plugin.api?.reactBabel)
186180
.filter(defined)

packages/plugin-rsc/README.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ This package provides [React Server Components](https://react.dev/reference/rsc/
1111

1212
## Getting Started
1313

14-
You can start a project by copying an example locally by:
14+
You can create a starter project by:
1515

1616
```sh
1717
npx degit vitejs/vite-plugin-react/packages/plugin-rsc/examples/starter my-app
@@ -22,11 +22,9 @@ npx degit vitejs/vite-plugin-react/packages/plugin-rsc/examples/starter my-app
2222
- [`./examples/starter`](./examples/starter)
2323
- This example provides an in-depth overview of API with inline comments to explain how they function within RSC-powered React application.
2424
- [`./examples/react-router`](./examples/react-router)
25-
- This demonstrates how to integrate [experimental React Router RSC API](https://remix.run/blog/rsc-preview) with this plugin.
26-
It also includes `@cloudflare/vite-plugin` integration.
25+
- This demonstrates how to integrate [experimental React Router RSC API](https://remix.run/blog/rsc-preview). React Router now provides [official RSC support](https://reactrouter.com/how-to/react-server-components), so it's recommended to follow React Router's official documentation for the latest integration.
2726
- [`./examples/basic`](./examples/basic)
2827
- This is mainly used for e2e testing and include various advanced RSC usages (e.g. `"use cache"` example).
29-
It also uses a high level `@vitejs/plugin-rsc/extra/{rsc,ssr,browser}` API for quick setup.
3028
- [`./examples/ssg`](./examples/ssg)
3129
- Static site generation (SSG) example with MDX and client components for interactivity.
3230

@@ -419,7 +417,10 @@ export default defineConfig({
419417
})
420418
```
421419

422-
## Higher level API
420+
## High level API
421+
422+
> [!NOTE]
423+
> High level API is deprecated. Please write on your own `@vitejs/plugin-rsc/{rsc,ssr,browser}` integration.
423424

424425
This is a wrapper of `react-server-dom` API and helper API to setup a minimal RSC app without writing own framework code like [`./examples/starter/src/framework`](./examples/starter/src/framework/). See [`./examples/basic`](./examples/basic/) for how this API is used.
425426

packages/plugin-rsc/e2e/basic.test.ts

Lines changed: 0 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -46,65 +46,6 @@ test.describe('build-default', () => {
4646
defineTest(f)
4747
})
4848

49-
test.describe('dev-base', () => {
50-
const f = useFixture({
51-
root: 'examples/basic',
52-
mode: 'dev',
53-
cliOptions: {
54-
env: {
55-
TEST_BASE: 'true',
56-
},
57-
},
58-
})
59-
defineTest(f)
60-
})
61-
62-
test.describe('build-base', () => {
63-
const f = useFixture({
64-
root: 'examples/basic',
65-
mode: 'build',
66-
cliOptions: {
67-
env: {
68-
TEST_BASE: 'true',
69-
},
70-
},
71-
})
72-
defineTest(f)
73-
})
74-
75-
test.describe('dev-react-compiler', () => {
76-
const f = useFixture({
77-
root: 'examples/basic',
78-
mode: 'dev',
79-
cliOptions: {
80-
env: {
81-
TEST_REACT_COMPILER: 'true',
82-
},
83-
},
84-
})
85-
defineTest(f)
86-
87-
test('verify react compiler', async ({ page }) => {
88-
await page.goto(f.url())
89-
await waitForHydration(page)
90-
const res = await page.request.get(f.url('src/routes/client.tsx'))
91-
expect(await res.text()).toContain('react.memo_cache_sentinel')
92-
})
93-
})
94-
95-
test.describe('build-react-compiler', () => {
96-
const f = useFixture({
97-
root: 'examples/basic',
98-
mode: 'build',
99-
cliOptions: {
100-
env: {
101-
TEST_REACT_COMPILER: 'true',
102-
},
103-
},
104-
})
105-
defineTest(f)
106-
})
107-
10849
test.describe(() => {
10950
// disabled by default
11051
if (process.env.TEST_ISOLATED !== 'true') return

packages/plugin-rsc/e2e/fixture.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,3 +192,38 @@ function editFileJson(filepath: string, edit: (s: string) => string) {
192192
),
193193
)
194194
}
195+
196+
// inspired by
197+
// https://github.com/remix-run/react-router/blob/433872f6ab098eaf946cc6c9cf80abf137420ad2/integration/helpers/vite.ts#L239
198+
// for syntax highlighting of /* js */, use this extension
199+
// https://github.com/mjbvz/vscode-comment-tagged-templates
200+
export async function setupInlineFixture(options: {
201+
src: string
202+
dest: string
203+
files?: Record<string, string>
204+
}) {
205+
fs.rmSync(options.dest, { recursive: true, force: true })
206+
fs.mkdirSync(options.dest, { recursive: true })
207+
208+
// copy src
209+
fs.cpSync(options.src, options.dest, {
210+
recursive: true,
211+
filter: (src) => !src.includes('node_modules') && !src.includes('dist'),
212+
})
213+
214+
// write additional files
215+
if (options.files) {
216+
for (let [filename, contents] of Object.entries(options.files)) {
217+
let filepath = path.join(options.dest, filename)
218+
fs.mkdirSync(path.dirname(filepath), { recursive: true })
219+
// strip indent
220+
contents = contents.replace(/^\n/, '')
221+
const indent = contents.match(/^\s*/)?.[0] ?? ''
222+
const strippedContents = contents
223+
.split('\n')
224+
.map((line) => line.replace(new RegExp(`^${indent}`), ''))
225+
.join('\n')
226+
fs.writeFileSync(filepath, strippedContents)
227+
}
228+
}
229+
}

packages/plugin-rsc/e2e/starter.test.ts

Lines changed: 201 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { expect, test } from '@playwright/test'
2-
import { type Fixture, useFixture } from './fixture'
2+
import { setupInlineFixture, type Fixture, useFixture } from './fixture'
33
import {
44
expectNoReload,
55
testNoJs,
@@ -42,6 +42,167 @@ test.describe('build-no-ssr', () => {
4242
})
4343
})
4444

45+
test.describe(() => {
46+
const root = 'examples/e2e/temp/react-compiler'
47+
48+
test.beforeAll(async () => {
49+
await setupInlineFixture({
50+
src: 'examples/starter',
51+
dest: root,
52+
files: {
53+
'vite.config.ts': /* js */ `
54+
import rsc from '@vitejs/plugin-rsc'
55+
import react from '@vitejs/plugin-react'
56+
import { defineConfig } from 'vite'
57+
58+
export default defineConfig({
59+
plugins: [
60+
react({
61+
babel: { plugins: ['babel-plugin-react-compiler'] },
62+
}).map((p) => ({
63+
...p,
64+
applyToEnvironment: (e) => e.name === 'client',
65+
})),
66+
rsc({
67+
entries: {
68+
client: './src/framework/entry.browser.tsx',
69+
ssr: './src/framework/entry.ssr.tsx',
70+
rsc: './src/framework/entry.rsc.tsx',
71+
}
72+
}),
73+
],
74+
})
75+
`,
76+
},
77+
})
78+
})
79+
80+
test.describe('dev-react-compiler', () => {
81+
const f = useFixture({ root, mode: 'dev' })
82+
defineTest(f)
83+
84+
test('verify react compiler', async ({ page }) => {
85+
await page.goto(f.url())
86+
await waitForHydration_(page)
87+
const res = await page.request.get(f.url('src/client.tsx'))
88+
expect(await res.text()).toContain('react.memo_cache_sentinel')
89+
})
90+
})
91+
92+
test.describe('build-react-compiler', () => {
93+
const f = useFixture({ root, mode: 'build' })
94+
defineTest(f)
95+
})
96+
})
97+
98+
test.describe(() => {
99+
const root = 'examples/e2e/temp/base'
100+
101+
test.beforeAll(async () => {
102+
await setupInlineFixture({
103+
src: 'examples/starter',
104+
dest: root,
105+
files: {
106+
'vite.config.ts': /* js */ `
107+
import rsc from '@vitejs/plugin-rsc'
108+
import react from '@vitejs/plugin-react'
109+
import { defineConfig } from 'vite'
110+
111+
export default defineConfig({
112+
base: '/custom-base/',
113+
plugins: [
114+
react(),
115+
rsc({
116+
entries: {
117+
client: './src/framework/entry.browser.tsx',
118+
ssr: './src/framework/entry.ssr.tsx',
119+
rsc: './src/framework/entry.rsc.tsx',
120+
}
121+
}),
122+
],
123+
})
124+
`,
125+
},
126+
})
127+
})
128+
129+
test.describe('dev-base', () => {
130+
const f = useFixture({ root, mode: 'dev' })
131+
defineTest({
132+
...f,
133+
url: (url) => new URL(url ?? './', f.url('./custom-base/')).href,
134+
})
135+
})
136+
137+
test.describe('build-base', () => {
138+
const f = useFixture({ root, mode: 'build' })
139+
defineTest({
140+
...f,
141+
url: (url) => new URL(url ?? './', f.url('./custom-base/')).href,
142+
})
143+
})
144+
})
145+
146+
test.describe(() => {
147+
const root = 'examples/e2e/temp/module-runner-hmr-false'
148+
149+
test.beforeAll(async () => {
150+
await setupInlineFixture({
151+
src: 'examples/starter',
152+
dest: root,
153+
files: {
154+
'vite.config.ts': /* js */ `
155+
import rsc from '@vitejs/plugin-rsc'
156+
import react from '@vitejs/plugin-react'
157+
import { defineConfig, createRunnableDevEnvironment } from 'vite'
158+
159+
export default defineConfig({
160+
plugins: [
161+
react(),
162+
rsc({
163+
entries: {
164+
client: './src/framework/entry.browser.tsx',
165+
ssr: './src/framework/entry.ssr.tsx',
166+
rsc: './src/framework/entry.rsc.tsx',
167+
}
168+
}),
169+
],
170+
environments: {
171+
ssr: {
172+
dev: {
173+
createEnvironment(name, config) {
174+
return createRunnableDevEnvironment(name, config, {
175+
runnerOptions: {
176+
hmr: false,
177+
},
178+
})
179+
},
180+
},
181+
},
182+
rsc: {
183+
dev: {
184+
createEnvironment(name, config) {
185+
return createRunnableDevEnvironment(name, config, {
186+
runnerOptions: {
187+
hmr: false,
188+
},
189+
})
190+
},
191+
},
192+
},
193+
},
194+
})
195+
`,
196+
},
197+
})
198+
})
199+
200+
test.describe('dev-module-runner-hmr-false', () => {
201+
const f = useFixture({ root, mode: 'dev' })
202+
defineTest(f)
203+
})
204+
})
205+
45206
function defineTest(f: Fixture, variant?: 'no-ssr') {
46207
const waitForHydration: typeof waitForHydration_ = (page) =>
47208
waitForHydration_(page, variant === 'no-ssr' ? '#root' : 'body')
@@ -110,6 +271,24 @@ function defineTest(f: Fixture, variant?: 'no-ssr') {
110271
await page.getByRole('button', { name: 'Client Counter: 0' }).click()
111272
})
112273

274+
test.describe(() => {
275+
test.skip(f.mode === 'build')
276+
277+
test('server hmr', async ({ page }) => {
278+
await page.goto(f.url())
279+
await waitForHydration(page)
280+
await using _ = await expectNoReload(page)
281+
await expect(page.getByText('Vite + RSC')).toBeVisible()
282+
const editor = f.createEditor('src/root.tsx')
283+
editor.edit((s) =>
284+
s.replace('<h1>Vite + RSC</h1>', '<h1>Vite x RSC</h1>'),
285+
)
286+
await expect(page.getByText('Vite x RSC')).toBeVisible()
287+
editor.reset()
288+
await expect(page.getByText('Vite + RSC')).toBeVisible()
289+
})
290+
})
291+
113292
test('image assets', async ({ page }) => {
114293
await page.goto(f.url())
115294
await waitForHydration(page)
@@ -122,4 +301,25 @@ function defineTest(f: Fixture, variant?: 'no-ssr') {
122301
0,
123302
)
124303
})
304+
305+
test('css @js', async ({ page }) => {
306+
await page.goto(f.url())
307+
await waitForHydration(page)
308+
await expect(page.locator('.read-the-docs')).toHaveCSS(
309+
'color',
310+
'rgb(136, 136, 136)',
311+
)
312+
})
313+
314+
test.describe(() => {
315+
test.skip(variant === 'no-ssr')
316+
317+
testNoJs('css @nojs', async ({ page }) => {
318+
await page.goto(f.url())
319+
await expect(page.locator('.read-the-docs')).toHaveCSS(
320+
'color',
321+
'rgb(136, 136, 136)',
322+
)
323+
})
324+
})
125325
}

packages/plugin-rsc/examples/basic/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
"@vitejs/test-dep-client-in-server2": "file:./test-dep/client-in-server2",
2626
"@vitejs/test-dep-server-in-client": "file:./test-dep/server-in-client",
2727
"@vitejs/test-dep-server-in-server": "file:./test-dep/server-in-server",
28-
"babel-plugin-react-compiler": "19.1.0-rc.2",
28+
"rsc-html-stream": "^0.0.7",
2929
"tailwindcss": "^4.1.11",
3030
"vite": "^7.0.4",
3131
"vite-plugin-inspect": "^11.3.0",

packages/plugin-rsc/examples/basic/src/client.tsx

Lines changed: 0 additions & 3 deletions
This file was deleted.

0 commit comments

Comments
 (0)