generated from rspack-contrib/rsbuild-plugin-template
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
a388728
commit 6ae09fe
Showing
27 changed files
with
1,212 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import { dirname } from 'node:path'; | ||
import { fileURLToPath } from 'node:url'; | ||
import { expect, test } from '@playwright/test'; | ||
import { createRsbuild, loadConfig } from '@rsbuild/core'; | ||
|
||
const __dirname = dirname(fileURLToPath(import.meta.url)); | ||
|
||
test('should build basic Vue jsx correctly', async ({ page }) => { | ||
const rsbuild = await createRsbuild({ | ||
cwd: __dirname, | ||
rsbuildConfig: (await loadConfig({ cwd: __dirname })).content, | ||
}); | ||
|
||
await rsbuild.build(); | ||
const { server, urls } = await rsbuild.preview(); | ||
|
||
await page.goto(urls[0]); | ||
|
||
const button1 = page.locator('#button1'); | ||
await expect(button1).toHaveText('A: 0'); | ||
|
||
await server.close(); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { defineConfig } from '@rsbuild/core'; | ||
import { pluginBabel } from '@rsbuild/plugin-babel'; | ||
import { pluginVue } from '@rsbuild/plugin-vue'; | ||
import { pluginVueJsx } from '@rsbuild/plugin-vue-jsx'; | ||
import { getRandomPort } from '../helper'; | ||
|
||
export default defineConfig({ | ||
plugins: [ | ||
pluginVue(), | ||
pluginVueJsx(), | ||
pluginBabel({ | ||
include: /\.(?:jsx|tsx)$/, | ||
}), | ||
], | ||
server: { | ||
port: getRandomPort(), | ||
}, | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import { defineComponent, ref } from 'vue'; | ||
|
||
export default defineComponent({ | ||
name: 'Test', | ||
|
||
setup() { | ||
const count = ref(0); | ||
return () => ( | ||
<button id="button1" type="button" onClick={() => count.value++}> | ||
A: {count.value} | ||
</button> | ||
); | ||
}, | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import { createApp } from 'vue'; | ||
import A from './A'; | ||
|
||
console.log(A); | ||
|
||
createApp(A).mount('#root'); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,263 @@ | ||
import fs from 'node:fs'; | ||
import path from 'node:path'; | ||
import { fileURLToPath } from 'node:url'; | ||
import { type Page, expect, test } from '@playwright/test'; | ||
import { createRsbuild, loadConfig } from '@rsbuild/core'; | ||
import { pluginVueJsx } from '../../src'; | ||
|
||
const __dirname = path.dirname(fileURLToPath(import.meta.url)); | ||
|
||
test('should render', async ({ page }) => { | ||
const rsbuild = await createRsbuild({ | ||
cwd: __dirname, | ||
rsbuildConfig: (await loadConfig({ cwd: __dirname })).content, | ||
}); | ||
|
||
const { server, urls } = await rsbuild.startDevServer(); | ||
|
||
await page.goto(urls[0]); | ||
|
||
await expect(page.locator('.named')).toHaveText('named 0'); | ||
await expect(page.locator('.named-specifier')).toHaveText( | ||
'named specifier 1', | ||
); | ||
await expect(page.locator('.default')).toHaveText('default 2'); | ||
await expect(page.locator('.default-tsx')).toHaveText('default tsx 3'); | ||
await expect(page.locator('.script')).toHaveText('script 4'); | ||
await expect(page.locator('.ts-import')).toHaveText('success'); | ||
|
||
await server.close(); | ||
}); | ||
|
||
test('should update', async ({ page }) => { | ||
const rsbuild = await createRsbuild({ | ||
cwd: __dirname, | ||
rsbuildConfig: (await loadConfig({ cwd: __dirname })).content, | ||
}); | ||
|
||
const { server, urls } = await rsbuild.startDevServer(); | ||
|
||
await page.goto(urls[0]); | ||
|
||
await page.locator('.named').click(); | ||
await expect(page.locator('.named')).toHaveText('named 1'); | ||
|
||
await page.locator('.named-specifier').click(); | ||
await expect(page.locator('.named-specifier')).toHaveText( | ||
'named specifier 2', | ||
); | ||
|
||
await page.locator('.default').click(); | ||
await expect(page.locator('.default')).toHaveText('default 3'); | ||
|
||
await page.locator('.default-tsx').click(); | ||
await expect(page.locator('.default-tsx')).toHaveText('default tsx 4'); | ||
|
||
await page.locator('.script').click(); | ||
await expect(page.locator('.script')).toHaveText('script 5'); | ||
|
||
await server.close(); | ||
}); | ||
|
||
test.describe('vue jsx hmr', () => { | ||
// HMR cases will fail in Windows | ||
if (process.platform === 'win32') { | ||
test.skip(); | ||
} | ||
|
||
let server: { | ||
close: () => Promise<void>; | ||
}; | ||
let page: Page; | ||
|
||
test.beforeAll(async ({ browser }) => { | ||
page = await browser.newPage(); | ||
const rsbuild = await createRsbuild({ | ||
cwd: __dirname, | ||
rsbuildConfig: (await loadConfig({ cwd: __dirname })).content, | ||
}); | ||
|
||
const result = await rsbuild.startDevServer(); | ||
server = result.server; | ||
|
||
await page.goto(result.urls[0]); | ||
}); | ||
|
||
test.afterAll(async () => { | ||
// reset files | ||
editFile('Comps.jsx', (code) => | ||
code.replace('named updated {count', 'named {count'), | ||
); | ||
editFile('Comps.jsx', (code) => | ||
code.replace('named specifier updated {count', 'named specifier {count'), | ||
); | ||
editFile('Comps.jsx', (code) => | ||
code.replace('default updated {count', 'default {count'), | ||
); | ||
editFile('Comp.tsx', (code) => | ||
code.replace('default tsx updated {count', 'default tsx {count'), | ||
); | ||
editFile('setup-syntax-jsx.vue', (code) => | ||
code.replace('let count = ref(1000)', 'let count = ref(100)'), | ||
); | ||
|
||
await server.close(); | ||
}); | ||
|
||
test('hmr: named export', async () => { | ||
await page.locator('.named').click(); | ||
await expect(page.locator('.named')).toHaveText('named 1'); | ||
await page.locator('.named-specifier').click(); | ||
await expect(page.locator('.named-specifier')).toHaveText( | ||
'named specifier 2', | ||
); | ||
await page.locator('.default').click(); | ||
await expect(page.locator('.default')).toHaveText('default 3'); | ||
await page.locator('.default-tsx').click(); | ||
await expect(page.locator('.default-tsx')).toHaveText('default tsx 4'); | ||
|
||
editFile('Comps.jsx', (code) => | ||
code.replace('named {count', 'named updated {count'), | ||
); | ||
await untilUpdated(() => page.textContent('.named'), 'named updated 0'); | ||
|
||
// affect all components in same file | ||
await expect(page.locator('.named-specifier')).toHaveText( | ||
'named specifier 1', | ||
); | ||
await expect(page.locator('.default')).toHaveText('default 2'); | ||
// should not affect other components from different file | ||
await expect(page.locator('.default-tsx')).toHaveText('default tsx 4'); | ||
}); | ||
|
||
test('hmr: named export via specifier', async () => { | ||
editFile('Comps.jsx', (code) => | ||
code.replace('named specifier {count', 'named specifier updated {count'), | ||
); | ||
await untilUpdated( | ||
() => page.textContent('.named-specifier'), | ||
'named specifier updated 1', | ||
); | ||
|
||
// affect all components in same file | ||
await expect(page.locator('.default')).toHaveText('default 2'); | ||
// should not affect other components on the page | ||
await expect(page.locator('.default-tsx')).toHaveText('default tsx 4'); | ||
}); | ||
|
||
test('hmr: default export', async () => { | ||
editFile('Comps.jsx', (code) => | ||
code.replace('default {count', 'default updated {count'), | ||
); | ||
await untilUpdated(() => page.textContent('.default'), 'default updated 2'); | ||
|
||
// should not affect other components on the page | ||
await expect(page.locator('.default-tsx')).toHaveText('default tsx 4'); | ||
}); | ||
|
||
test('hmr: default Default export', async () => { | ||
await page.locator('.named').click(); | ||
await expect(page.locator('.named')).toHaveText('named updated 1'); | ||
|
||
editFile('Comp.tsx', (code) => | ||
code.replace('default tsx {count', 'default tsx updated {count'), | ||
); | ||
await untilUpdated( | ||
() => page.textContent('.default-tsx'), | ||
'default tsx updated 3', | ||
); | ||
|
||
// should not affect other components on the page | ||
await expect(page.locator('.named')).toHaveText('named updated 1'); | ||
}); | ||
|
||
// not pass | ||
test.skip('hmr: vue script lang=jsx', async () => { | ||
await page.locator('.script').click(); | ||
await expect(page.locator('.script')).toHaveText('script 5'); | ||
|
||
editFile('Script.vue', (code) => | ||
code.replace('script {count', 'script updated {count'), | ||
); | ||
|
||
await untilUpdated(() => page.textContent('.script'), 'script updated 4'); | ||
|
||
// reset code | ||
editFile('Script.vue', (code) => | ||
code.replace('script updated {count', 'script {count'), | ||
); | ||
}); | ||
|
||
// not pass | ||
test.skip('hmr: script in .vue', async () => { | ||
await page.locator('.src-import').click(); | ||
await expect(page.locator('.src-import')).toHaveText('src import 6'); | ||
|
||
editFile('Script.vue', (code) => | ||
code.replace('script {count', 'script updated {count'), | ||
); | ||
await untilUpdated(() => page.textContent('.script'), 'script updated 4'); | ||
|
||
await expect(page.locator('.src-import')).toHaveText('src import 6'); | ||
|
||
// reset code | ||
editFile('Script.vue', (code) => | ||
code.replace('script updated {count', 'script {count'), | ||
); | ||
}); | ||
|
||
// not pass | ||
test.skip('hmr: src import in .vue', async () => { | ||
await page.locator('.script').click(); | ||
await expect(page.locator('.script')).toHaveText('script 5'); | ||
|
||
editFile('SrcImport.jsx', (code) => | ||
code.replace('src import {count', 'src import updated {count'), | ||
); | ||
|
||
await untilUpdated( | ||
() => page.textContent('.src-import'), | ||
'src import updated 5', | ||
); | ||
|
||
await expect(page.locator('.script')).toHaveText('script 5'); | ||
|
||
// reset code | ||
editFile('SrcImport.jsx', (code) => | ||
code.replace('src import updated {count', 'src import {count'), | ||
); | ||
}); | ||
|
||
test('hmr: setup jsx in .vue', async () => { | ||
editFile('setup-syntax-jsx.vue', (code) => | ||
code.replace('let count = ref(100)', 'let count = ref(1000)'), | ||
); | ||
|
||
await untilUpdated(() => page.textContent('.setup-jsx'), '1000'); | ||
}); | ||
}); | ||
|
||
function editFile(filename: string, replacer: (str: string) => string): void { | ||
const fileName = path.join(__dirname, 'src', filename); | ||
const content = fs.readFileSync(fileName, 'utf-8'); | ||
const modified = replacer(content); | ||
fs.writeFileSync(fileName, modified); | ||
} | ||
|
||
const timeout = (n: number) => new Promise((r) => setTimeout(r, n)); | ||
|
||
async function untilUpdated( | ||
poll: () => Promise<string | null>, | ||
expected: string, | ||
): Promise<void> { | ||
const maxTries = 50; | ||
for (let tries = 0; tries < maxTries; tries++) { | ||
const actual = (await poll()) ?? ''; | ||
if (actual.indexOf(expected) > -1 || tries === maxTries - 1) { | ||
expect(actual).toMatch(expected); | ||
break; | ||
} | ||
|
||
await timeout(50); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { defineConfig } from '@rsbuild/core'; | ||
import { pluginBabel } from '@rsbuild/plugin-babel'; | ||
import { pluginVue } from '@rsbuild/plugin-vue'; | ||
import { pluginVueJsx } from '@rsbuild/plugin-vue-jsx'; | ||
import { getRandomPort } from '../helper'; | ||
|
||
export default defineConfig({ | ||
plugins: [ | ||
pluginVue(), | ||
pluginBabel({ | ||
include: /\.(?:jsx|tsx)(\.js)?$/, | ||
}), | ||
pluginVueJsx(), | ||
], | ||
server: { | ||
port: getRandomPort(), | ||
}, | ||
performance: { | ||
buildCache: false, | ||
}, | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import { defineComponent, ref } from 'vue'; | ||
|
||
const Default = defineComponent(() => { | ||
const count = ref(3); | ||
const inc = () => count.value++; | ||
|
||
return () => ( | ||
<button class="default-tsx" onClick={inc} type="button"> | ||
default tsx {count.value} | ||
</button> | ||
); | ||
}); | ||
|
||
export default Default; |
Oops, something went wrong.