From d03e000a9705fe5fce843934fab181f55e7d56a8 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Mon, 21 Jul 2025 13:47:28 +0900 Subject: [PATCH 01/11] test(rsc): add more basic tests to starter --- packages/plugin-rsc/e2e/starter.test.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/packages/plugin-rsc/e2e/starter.test.ts b/packages/plugin-rsc/e2e/starter.test.ts index 1ee2c2e0e..bc8d32c2a 100644 --- a/packages/plugin-rsc/e2e/starter.test.ts +++ b/packages/plugin-rsc/e2e/starter.test.ts @@ -110,6 +110,25 @@ function defineTest(f: Fixture, variant?: 'no-ssr') { await page.getByRole('button', { name: 'Client Counter: 0' }).click() }) + test.describe(() => { + test.skip(f.mode === 'build') + + test('server hmr', async ({ page }) => { + await page.goto(f.url()) + await waitForHydration(page) + await using _ = await expectNoReload(page) + const editor = f.createEditor('src/root.tsx') + editor.edit((s) => s.replace('Server Counter', 'Server [edit] Counter')) + await expect( + page.getByRole('button', { name: 'Server [edit] Counter: 0' }), + ).toBeVisible() + editor.reset() + await expect( + page.getByRole('button', { name: 'Server Counter: 0' }), + ).toBeVisible() + }) + }) + test('image assets', async ({ page }) => { await page.goto(f.url()) await waitForHydration(page) From 04e4eb1feb773ddc93cd4da69081f38988fa6f80 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Mon, 21 Jul 2025 13:57:13 +0900 Subject: [PATCH 02/11] test: css --- packages/plugin-rsc/e2e/starter.test.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/packages/plugin-rsc/e2e/starter.test.ts b/packages/plugin-rsc/e2e/starter.test.ts index bc8d32c2a..ec92efa94 100644 --- a/packages/plugin-rsc/e2e/starter.test.ts +++ b/packages/plugin-rsc/e2e/starter.test.ts @@ -141,4 +141,23 @@ function defineTest(f: Fixture, variant?: 'no-ssr') { 0, ) }) + + test('css @js', async ({ page }) => { + await page.goto(f.url()) + await waitForHydration(page) + await expect(page.locator('.read-the-docs')).toHaveCSS( + 'color', + 'rgb(136, 136, 136)', + ) + }) + + testNoJs('css @nojs', async ({ page }) => { + test.skip(variant === 'no-ssr') + + await page.goto(f.url()) + await expect(page.locator('.read-the-docs')).toHaveCSS( + 'color', + 'rgb(136, 136, 136)', + ) + }) } From cc64af874eda1e5a712104fe02c7021f3da2269f Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Mon, 21 Jul 2025 13:59:44 +0900 Subject: [PATCH 03/11] test: tweak skip --- packages/plugin-rsc/e2e/starter.test.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/plugin-rsc/e2e/starter.test.ts b/packages/plugin-rsc/e2e/starter.test.ts index ec92efa94..f74cde50b 100644 --- a/packages/plugin-rsc/e2e/starter.test.ts +++ b/packages/plugin-rsc/e2e/starter.test.ts @@ -151,13 +151,15 @@ function defineTest(f: Fixture, variant?: 'no-ssr') { ) }) - testNoJs('css @nojs', async ({ page }) => { + test.describe(() => { test.skip(variant === 'no-ssr') - await page.goto(f.url()) - await expect(page.locator('.read-the-docs')).toHaveCSS( - 'color', - 'rgb(136, 136, 136)', - ) + testNoJs('css @nojs', async ({ page }) => { + await page.goto(f.url()) + await expect(page.locator('.read-the-docs')).toHaveCSS( + 'color', + 'rgb(136, 136, 136)', + ) + }) }) } From 5420b62d199e9c88c9f2159c3dc7f54eddd4a17f Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Mon, 21 Jul 2025 14:52:27 +0900 Subject: [PATCH 04/11] test: tweak --- packages/plugin-rsc/e2e/starter.test.ts | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/packages/plugin-rsc/e2e/starter.test.ts b/packages/plugin-rsc/e2e/starter.test.ts index f74cde50b..1bee50b70 100644 --- a/packages/plugin-rsc/e2e/starter.test.ts +++ b/packages/plugin-rsc/e2e/starter.test.ts @@ -117,15 +117,14 @@ function defineTest(f: Fixture, variant?: 'no-ssr') { await page.goto(f.url()) await waitForHydration(page) await using _ = await expectNoReload(page) + await expect(page.getByText('Vite + RSC')).toBeVisible() const editor = f.createEditor('src/root.tsx') - editor.edit((s) => s.replace('Server Counter', 'Server [edit] Counter')) - await expect( - page.getByRole('button', { name: 'Server [edit] Counter: 0' }), - ).toBeVisible() + editor.edit((s) => + s.replace('

Vite + RSC

', '

Vite x RSC

'), + ) + await expect(page.getByText('Vite x RSC')).toBeVisible() editor.reset() - await expect( - page.getByRole('button', { name: 'Server Counter: 0' }), - ).toBeVisible() + await expect(page.getByText('Vite + RSC')).toBeVisible() }) }) From f2a725cd4e0760bb50a81fd6eaae5adaced95fe4 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Mon, 21 Jul 2025 17:25:23 +0900 Subject: [PATCH 05/11] test(rsc): refactor variant tests --- packages/plugin-rsc/e2e/fixture.ts | 5 +++++ packages/plugin-rsc/e2e/starter.test.ts | 23 ++++++++++++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/packages/plugin-rsc/e2e/fixture.ts b/packages/plugin-rsc/e2e/fixture.ts index b9cf2f070..2ba9a0915 100644 --- a/packages/plugin-rsc/e2e/fixture.ts +++ b/packages/plugin-rsc/e2e/fixture.ts @@ -192,3 +192,8 @@ function editFileJson(filepath: string, edit: (s: string) => string) { ), ) } + +export async function setupInlineFixture(options: { + src: string + dest: string +}) {} diff --git a/packages/plugin-rsc/e2e/starter.test.ts b/packages/plugin-rsc/e2e/starter.test.ts index 1bee50b70..e100d5ba8 100644 --- a/packages/plugin-rsc/e2e/starter.test.ts +++ b/packages/plugin-rsc/e2e/starter.test.ts @@ -1,5 +1,5 @@ import { expect, test } from '@playwright/test' -import { type Fixture, useFixture } from './fixture' +import { setupInlineFixture, type Fixture, useFixture } from './fixture' import { expectNoReload, testNoJs, @@ -42,6 +42,27 @@ test.describe('build-no-ssr', () => { }) }) +test.describe(() => { + const root = 'temp/starter-react-compiler' + + test.beforeAll(async () => { + await setupInlineFixture({ + src: 'examples/starter', + dest: root, + }) + }) + + test.describe('dev-react-compiler', () => { + const f = useFixture({ root, mode: 'dev' }) + defineTest(f) + }) + + test.describe('build-react-compiler', () => { + const f = useFixture({ root, mode: 'build' }) + defineTest(f) + }) +}) + function defineTest(f: Fixture, variant?: 'no-ssr') { const waitForHydration: typeof waitForHydration_ = (page) => waitForHydration_(page, variant === 'no-ssr' ? '#root' : 'body') From fade954175778a3a253a4ce29e8c3d2828ae7423 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Mon, 21 Jul 2025 18:17:47 +0900 Subject: [PATCH 06/11] test: move react-compiler tests --- packages/plugin-rsc/e2e/fixture.ts | 31 ++++++++++++++++- packages/plugin-rsc/e2e/starter.test.ts | 34 ++++++++++++++++++- packages/plugin-rsc/examples/e2e/package.json | 10 ++++++ pnpm-lock.yaml | 14 +++++++- 4 files changed, 86 insertions(+), 3 deletions(-) create mode 100644 packages/plugin-rsc/examples/e2e/package.json diff --git a/packages/plugin-rsc/e2e/fixture.ts b/packages/plugin-rsc/e2e/fixture.ts index 2ba9a0915..0f3e2c169 100644 --- a/packages/plugin-rsc/e2e/fixture.ts +++ b/packages/plugin-rsc/e2e/fixture.ts @@ -193,7 +193,36 @@ function editFileJson(filepath: string, edit: (s: string) => string) { ) } +// inspired by +// https://github.com/remix-run/react-router/blob/433872f6ab098eaf946cc6c9cf80abf137420ad2/integration/helpers/vite.ts#L239 +// for syntax highlighting of /* js */, use this extension +// https://github.com/mjbvz/vscode-comment-tagged-templates export async function setupInlineFixture(options: { src: string dest: string -}) {} + files?: Record +}) { + fs.rmSync(options.dest, { recursive: true, force: true }) + fs.mkdirSync(options.dest, { recursive: true }) + + // copy src + fs.cpSync(options.src, options.dest, { + recursive: true, + filter: (src) => !src.includes('node_modules') && !src.includes('dist'), + }) + + // write additional files + if (options.files) { + for (const [filename, contents] of Object.entries(options.files)) { + let filepath = path.join(options.dest, filename) + fs.mkdirSync(path.dirname(filepath), { recursive: true }) + // strip indent + const indent = contents.match(/^\s*/)?.[0] ?? '' + const strippedContents = contents + .split('\n') + .map((line) => line.replace(new RegExp(`^${indent}`), '')) + .join('\n') + fs.writeFileSync(filepath, strippedContents) + } + } +} diff --git a/packages/plugin-rsc/e2e/starter.test.ts b/packages/plugin-rsc/e2e/starter.test.ts index e100d5ba8..8c3148b41 100644 --- a/packages/plugin-rsc/e2e/starter.test.ts +++ b/packages/plugin-rsc/e2e/starter.test.ts @@ -43,18 +43,50 @@ test.describe('build-no-ssr', () => { }) test.describe(() => { - const root = 'temp/starter-react-compiler' + const root = 'examples/e2e/temp/starter-react-compiler' test.beforeAll(async () => { await setupInlineFixture({ src: 'examples/starter', dest: root, + files: { + 'vite.config.ts': /* js */ ` + import rsc from '@vitejs/plugin-rsc' + import react from '@vitejs/plugin-react' + import { defineConfig } from 'vite' + + export default defineConfig({ + plugins: [ + react({ + babel: { plugins: ['babel-plugin-react-compiler'] }, + }).map((p) => ({ + ...p, + applyToEnvironment: (e) => e.name === 'client', + })), + rsc({ + entries: { + client: './src/framework/entry.browser.tsx', + ssr: './src/framework/entry.ssr.tsx', + rsc: './src/framework/entry.rsc.tsx', + } + }), + ], + }) + `, + }, }) }) test.describe('dev-react-compiler', () => { const f = useFixture({ root, mode: 'dev' }) defineTest(f) + + test('verify react compiler', async ({ page }) => { + await page.goto(f.url()) + await waitForHydration_(page) + const res = await page.request.get(f.url('src/client.tsx')) + expect(await res.text()).toContain('react.memo_cache_sentinel') + }) }) test.describe('build-react-compiler', () => { diff --git a/packages/plugin-rsc/examples/e2e/package.json b/packages/plugin-rsc/examples/e2e/package.json new file mode 100644 index 000000000..e0f0a72d8 --- /dev/null +++ b/packages/plugin-rsc/examples/e2e/package.json @@ -0,0 +1,10 @@ +{ + "name": "@vitejs/plugin-rsc-examples-e2e-temp", + "private": true, + "type": "module", + "devDependencies": { + "@vitejs/plugin-rsc": "latest", + "@vitejs/plugin-react": "latest", + "babel-plugin-react-compiler": "19.1.0-rc.2" + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 42641f74b..fc4b9d6dc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -558,6 +558,18 @@ importers: specifier: ^4.24.3 version: 4.24.3 + packages/plugin-rsc/examples/e2e: + devDependencies: + '@vitejs/plugin-react': + specifier: latest + version: link:../../../plugin-react + '@vitejs/plugin-rsc': + specifier: latest + version: link:../.. + babel-plugin-react-compiler: + specifier: 19.1.0-rc.2 + version: 19.1.0-rc.2 + packages/plugin-rsc/examples/no-ssr: dependencies: '@vitejs/plugin-rsc': @@ -7741,7 +7753,7 @@ snapshots: babel-plugin-react-compiler@19.1.0-rc.2: dependencies: - '@babel/types': 7.27.7 + '@babel/types': 7.28.0 bail@2.0.2: {} From 343b29495044a595be94c627ac6d8908f6c0726a Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Mon, 21 Jul 2025 18:32:28 +0900 Subject: [PATCH 07/11] chore: tweak --- packages/plugin-rsc/e2e/starter.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/plugin-rsc/e2e/starter.test.ts b/packages/plugin-rsc/e2e/starter.test.ts index 8c3148b41..f92ed1093 100644 --- a/packages/plugin-rsc/e2e/starter.test.ts +++ b/packages/plugin-rsc/e2e/starter.test.ts @@ -43,7 +43,7 @@ test.describe('build-no-ssr', () => { }) test.describe(() => { - const root = 'examples/e2e/temp/starter-react-compiler' + const root = 'examples/e2e/temp/react-compiler' test.beforeAll(async () => { await setupInlineFixture({ From 87de917f61e995d2d2e04716f9b432596548861a Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Mon, 21 Jul 2025 18:36:09 +0900 Subject: [PATCH 08/11] chore: tweak --- packages/plugin-rsc/examples/e2e/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/plugin-rsc/examples/e2e/package.json b/packages/plugin-rsc/examples/e2e/package.json index e0f0a72d8..314068f26 100644 --- a/packages/plugin-rsc/examples/e2e/package.json +++ b/packages/plugin-rsc/examples/e2e/package.json @@ -1,5 +1,5 @@ { - "name": "@vitejs/plugin-rsc-examples-e2e-temp", + "name": "@vitejs/plugin-rsc-examples-e2e", "private": true, "type": "module", "devDependencies": { From bbe46682aeea954551e58275be51ac0e469f85c0 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Mon, 21 Jul 2025 18:36:56 +0900 Subject: [PATCH 09/11] chore: cleanup --- packages/plugin-rsc/e2e/basic.test.ts | 33 ------------------- .../plugin-rsc/examples/basic/package.json | 1 - .../plugin-rsc/examples/basic/vite.config.ts | 9 +---- pnpm-lock.yaml | 3 -- 4 files changed, 1 insertion(+), 45 deletions(-) diff --git a/packages/plugin-rsc/e2e/basic.test.ts b/packages/plugin-rsc/e2e/basic.test.ts index cc6cadd06..f8cc64571 100644 --- a/packages/plugin-rsc/e2e/basic.test.ts +++ b/packages/plugin-rsc/e2e/basic.test.ts @@ -72,39 +72,6 @@ test.describe('build-base', () => { defineTest(f) }) -test.describe('dev-react-compiler', () => { - const f = useFixture({ - root: 'examples/basic', - mode: 'dev', - cliOptions: { - env: { - TEST_REACT_COMPILER: 'true', - }, - }, - }) - defineTest(f) - - test('verify react compiler', async ({ page }) => { - await page.goto(f.url()) - await waitForHydration(page) - const res = await page.request.get(f.url('src/routes/client.tsx')) - expect(await res.text()).toContain('react.memo_cache_sentinel') - }) -}) - -test.describe('build-react-compiler', () => { - const f = useFixture({ - root: 'examples/basic', - mode: 'build', - cliOptions: { - env: { - TEST_REACT_COMPILER: 'true', - }, - }, - }) - defineTest(f) -}) - test.describe(() => { // disabled by default if (process.env.TEST_ISOLATED !== 'true') return diff --git a/packages/plugin-rsc/examples/basic/package.json b/packages/plugin-rsc/examples/basic/package.json index fc11d417a..bed815b99 100644 --- a/packages/plugin-rsc/examples/basic/package.json +++ b/packages/plugin-rsc/examples/basic/package.json @@ -25,7 +25,6 @@ "@vitejs/test-dep-client-in-server2": "file:./test-dep/client-in-server2", "@vitejs/test-dep-server-in-client": "file:./test-dep/server-in-client", "@vitejs/test-dep-server-in-server": "file:./test-dep/server-in-server", - "babel-plugin-react-compiler": "19.1.0-rc.2", "tailwindcss": "^4.1.11", "vite": "^7.0.4", "vite-plugin-inspect": "^11.3.0", diff --git a/packages/plugin-rsc/examples/basic/vite.config.ts b/packages/plugin-rsc/examples/basic/vite.config.ts index 38061c0f1..d6821f255 100644 --- a/packages/plugin-rsc/examples/basic/vite.config.ts +++ b/packages/plugin-rsc/examples/basic/vite.config.ts @@ -11,14 +11,7 @@ export default defineConfig({ clearScreen: false, plugins: [ tailwindcss(), - process.env.TEST_REACT_COMPILER - ? react({ - babel: { plugins: ['babel-plugin-react-compiler'] }, - }).map((p) => ({ - ...p, - applyToEnvironment: (e) => e.name === 'client', - })) - : react(), + react(), vitePluginUseCache(), rsc({ entries: { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fc4b9d6dc..74e6d51d0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -542,9 +542,6 @@ importers: '@vitejs/test-dep-server-in-server': specifier: file:./test-dep/server-in-server version: file:packages/plugin-rsc/examples/basic/test-dep/server-in-server(react@19.1.0) - babel-plugin-react-compiler: - specifier: 19.1.0-rc.2 - version: 19.1.0-rc.2 tailwindcss: specifier: ^4.1.11 version: 4.1.11 From a09d1c0bd0a4fc72bc3eac651ae584bfa3c46f55 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Mon, 21 Jul 2025 18:54:18 +0900 Subject: [PATCH 10/11] test: use temp/base --- packages/plugin-rsc/e2e/starter.test.ts | 48 +++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/packages/plugin-rsc/e2e/starter.test.ts b/packages/plugin-rsc/e2e/starter.test.ts index f92ed1093..cccdd7b1a 100644 --- a/packages/plugin-rsc/e2e/starter.test.ts +++ b/packages/plugin-rsc/e2e/starter.test.ts @@ -95,6 +95,54 @@ test.describe(() => { }) }) +test.describe(() => { + const root = 'examples/e2e/temp/base' + + test.beforeAll(async () => { + await setupInlineFixture({ + src: 'examples/starter', + dest: root, + files: { + 'vite.config.ts': /* js */ ` + import rsc from '@vitejs/plugin-rsc' + import react from '@vitejs/plugin-react' + import { defineConfig } from 'vite' + + export default defineConfig({ + base: '/custom-base/', + plugins: [ + react(), + rsc({ + entries: { + client: './src/framework/entry.browser.tsx', + ssr: './src/framework/entry.ssr.tsx', + rsc: './src/framework/entry.rsc.tsx', + } + }), + ], + }) + `, + }, + }) + }) + + test.describe('dev-base', () => { + const f = useFixture({ root, mode: 'dev' }) + defineTest({ + ...f, + url: (url) => new URL(url ?? './', f.url('./custom-base/')).href, + }) + }) + + test.describe('build-base', () => { + const f = useFixture({ root, mode: 'build' }) + defineTest({ + ...f, + url: (url) => new URL(url ?? './', f.url('./custom-base/')).href, + }) + }) +}) + function defineTest(f: Fixture, variant?: 'no-ssr') { const waitForHydration: typeof waitForHydration_ = (page) => waitForHydration_(page, variant === 'no-ssr' ? '#root' : 'body') From fdaa095cc0d5112f85af9cfcf707a031e5a5773e Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Mon, 21 Jul 2025 18:54:52 +0900 Subject: [PATCH 11/11] chore: cleanup --- packages/plugin-rsc/e2e/basic.test.ts | 26 ------------------- .../plugin-rsc/examples/basic/vite.config.ts | 1 - 2 files changed, 27 deletions(-) diff --git a/packages/plugin-rsc/e2e/basic.test.ts b/packages/plugin-rsc/e2e/basic.test.ts index f8cc64571..763cd379a 100644 --- a/packages/plugin-rsc/e2e/basic.test.ts +++ b/packages/plugin-rsc/e2e/basic.test.ts @@ -46,32 +46,6 @@ test.describe('build-default', () => { defineTest(f) }) -test.describe('dev-base', () => { - const f = useFixture({ - root: 'examples/basic', - mode: 'dev', - cliOptions: { - env: { - TEST_BASE: 'true', - }, - }, - }) - defineTest(f) -}) - -test.describe('build-base', () => { - const f = useFixture({ - root: 'examples/basic', - mode: 'build', - cliOptions: { - env: { - TEST_BASE: 'true', - }, - }, - }) - defineTest(f) -}) - test.describe(() => { // disabled by default if (process.env.TEST_ISOLATED !== 'true') return diff --git a/packages/plugin-rsc/examples/basic/vite.config.ts b/packages/plugin-rsc/examples/basic/vite.config.ts index d6821f255..97d0f30b8 100644 --- a/packages/plugin-rsc/examples/basic/vite.config.ts +++ b/packages/plugin-rsc/examples/basic/vite.config.ts @@ -7,7 +7,6 @@ import inspect from 'vite-plugin-inspect' import path from 'node:path' export default defineConfig({ - base: process.env.TEST_BASE ? '/custom-base/' : undefined, clearScreen: false, plugins: [ tailwindcss(),