From: Evan You Date: Sat, 8 Feb 2025 12:42:34 +0000 (+0800) Subject: test(vapor): e2e interop test for vapor X-Git-Tag: v3.6.0-alpha.1~16^2~82 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=cd93dad4d97971d30e89924387c2378e8bc43c70;p=thirdparty%2Fvuejs%2Fcore.git test(vapor): e2e interop test for vapor --- diff --git a/eslint.config.js b/eslint.config.js index 384074d4c3..1f5128ec72 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -154,6 +154,7 @@ export default tseslint.config( 'packages/*/*.js', 'packages/vue/*/*.js', 'packages-private/benchmark/*', + 'packages-private/e2e-utils/*', ], rules: { 'no-restricted-globals': 'off', diff --git a/package.json b/package.json index 80a86145a1..2967aa4d4d 100644 --- a/package.json +++ b/package.json @@ -17,8 +17,10 @@ "format": "prettier --write --cache .", "format-check": "prettier --check --cache .", "test": "vitest", - "test-unit": "vitest --project unit", + "test-unit": "vitest --project unit --project unit-jsdom", "test-e2e": "node scripts/build.js vue -f global -d && vitest --project e2e", + "test-e2e-vapor": "pnpm run prepare-e2e-vapor && vitest --project e2e-vapor", + "prepare-e2e-vapor": "node scripts/build.js -f cjs+esm-bundler+esm-bundler-runtime && pnpm run -C packages-private/vapor-e2e-test build", "test-dts": "run-s build-dts test-dts-only", "test-dts-only": "tsc -p packages-private/dts-built-test/tsconfig.json && tsc -p ./packages-private/dts-test/tsconfig.test.json", "test-coverage": "vitest run --project unit --coverage", @@ -29,18 +31,17 @@ "release": "node scripts/release.js", "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s", "dev-esm": "node scripts/dev.js -if esm-bundler-runtime", - "dev-prepare-cjs": "node scripts/prepare-cjs.js || npm run build-all-cjs", + "dev-prepare-cjs": "node scripts/prepare-cjs.js || node scripts/build.js -f cjs", "dev-compiler": "run-p \"dev template-explorer\" serve open", "dev-sfc": "run-s dev-prepare-cjs dev-sfc-run", "dev-sfc-serve": "vite packages-private/sfc-playground", - "dev-sfc-run": "run-p \"dev compiler-sfc -f esm-browser\" \"dev vue -if vapor\" \"dev vue -ipf vapor\" \"dev server-renderer -if esm-bundler\" dev-sfc-serve", - "dev-vapor": "pnpm -C playground run dev", + "dev-sfc-run": "run-p \"dev compiler-sfc -f esm-browser\" \"dev vue -if esm-browser-vapor\" \"dev vue -ipf esm-browser-vapor\" \"dev server-renderer -if esm-bundler\" dev-sfc-serve", + "dev-vapor": "pnpm -C packages-private/local-playground run dev", "serve": "serve", "open": "open http://localhost:3000/packages-private/template-explorer/local.html", - "build-sfc-playground": "run-s build-all-cjs build-all-esm build-sfc-playground-self", - "build-all-cjs": "node scripts/build.js vue runtime compiler reactivity shared -af cjs", - "build-all-esm": "node scripts/build.js runtime reactivity shared -af esm-bundler && node scripts/build.js vue -f esm-bundler+esm-browser+esm-bundler-runtime+esm-browser-runtime+vapor && node scripts/build.js compiler-sfc server-renderer -f esm-browser", - "build-sfc-playground-self": "cd packages-private/sfc-playground && npm run build", + "build-sfc-playground": "run-s build-sfc-deps build-sfc-playground-self", + "build-sfc-deps": "node scripts/build.js -f ~global+global-runtime", + "build-sfc-playground-self": "pnpm run -C packages-private/sfc-playground build", "preinstall": "npx only-allow pnpm", "postinstall": "simple-git-hooks" }, diff --git a/packages-private/benchmark/index.js b/packages-private/benchmark/index.js index 7841b0b299..86a7336874 100644 --- a/packages-private/benchmark/index.js +++ b/packages-private/benchmark/index.js @@ -121,7 +121,7 @@ async function buildLib() { ), exec( 'pnpm', - `run --silent build vue ${buildOptions} vapor`.split(' '), + `run --silent build vue ${buildOptions} esm-browser-vapor`.split(' '), options, ), ]) @@ -146,9 +146,7 @@ async function buildApp(isVapor) { const runtimePath = path.resolve( import.meta.dirname, - (isVapor - ? '../../packages/vue/dist/vue.runtime-with-vapor.esm-browser' - : '../../packages/vue/dist/vue.runtime.esm-browser') + prodSuffix, + '../../packages/vue/dist/vue.runtime-with-vapor.esm-browser' + prodSuffix, ) const mode = isVapor ? 'vapor' : 'vdom' @@ -159,7 +157,7 @@ async function buildApp(isVapor) { 'import.meta.env.IS_VAPOR': String(isVapor), }, build: { - minify: !devBuild && 'terser', + minify: !devBuild, outDir: path.resolve('./client/dist', mode), rollupOptions: { onwarn(log, handler) { diff --git a/packages-private/benchmark/package.json b/packages-private/benchmark/package.json index b087cfca4b..61dab94161 100644 --- a/packages-private/benchmark/package.json +++ b/packages-private/benchmark/package.json @@ -5,7 +5,7 @@ "license": "MIT", "type": "module", "scripts": { - "dev": "pnpm start --devBuild --noHeadless --skipBench --vdom", + "dev": "pnpm start --devBuild --skipBench --vdom", "start": "node index.js" }, "dependencies": { @@ -15,7 +15,6 @@ "vite": "catalog:" }, "devDependencies": { - "@types/connect": "^3.4.38", - "terser": "^5.33.0" + "@types/connect": "^3.4.38" } } diff --git a/packages-private/local-playground/package.json b/packages-private/local-playground/package.json index 23903a2ae2..37c9818a70 100644 --- a/packages-private/local-playground/package.json +++ b/packages-private/local-playground/package.json @@ -13,7 +13,7 @@ "vue": "workspace:*" }, "devDependencies": { - "@vitejs/plugin-vue": "https://pkg.pr.new/@vitejs/plugin-vue@c156992", + "@vitejs/plugin-vue": "catalog:", "@vue/compiler-sfc": "workspace:*", "vite": "catalog:", "vite-hyper-config": "^0.4.0", diff --git a/packages-private/tsconfig.json b/packages-private/tsconfig.json index 1c287a7500..37a38f53fc 100644 --- a/packages-private/tsconfig.json +++ b/packages-private/tsconfig.json @@ -3,5 +3,5 @@ "compilerOptions": { "isolatedDeclarations": false }, - "include": ["."] + "include": [".", "../packages/vue/__tests__/e2e/e2eUtils.ts"] } diff --git a/packages-private/vapor-e2e-test/__tests__/e2eUtils.ts b/packages-private/vapor-e2e-test/__tests__/e2eUtils.ts new file mode 100644 index 0000000000..2ffebeb595 --- /dev/null +++ b/packages-private/vapor-e2e-test/__tests__/e2eUtils.ts @@ -0,0 +1,223 @@ +import puppeteer, { + type Browser, + type ClickOptions, + type LaunchOptions, + type Page, +} from 'puppeteer' + +export const E2E_TIMEOUT: number = 30 * 1000 + +const puppeteerOptions: LaunchOptions = { + args: process.env.CI ? ['--no-sandbox', '--disable-setuid-sandbox'] : [], + headless: true, +} + +const maxTries = 30 +export const timeout = (n: number): Promise => + new Promise(r => setTimeout(r, n)) + +export async function expectByPolling( + poll: () => Promise, + expected: string, +): Promise { + for (let tries = 0; tries < maxTries; tries++) { + const actual = (await poll()) || '' + if (actual.indexOf(expected) > -1 || tries === maxTries - 1) { + expect(actual).toMatch(expected) + break + } else { + await timeout(50) + } + } +} + +interface PuppeteerUtils { + page: () => Page + click(selector: string, options?: ClickOptions): Promise + count(selector: string): Promise + text(selector: string): Promise + value(selector: string): Promise + html(selector: string): Promise + classList(selector: string): Promise + style(selector: string, property: keyof CSSStyleDeclaration): Promise + children(selector: string): Promise + isVisible(selector: string): Promise + isChecked(selector: string): Promise + isFocused(selector: string): Promise + setValue(selector: string, value: string): Promise + typeValue(selector: string, value: string): Promise + enterValue(selector: string, value: string): Promise + clearValue(selector: string): Promise + timeout(time: number): Promise + nextFrame(): Promise +} + +export function setupPuppeteer(args?: string[]): PuppeteerUtils { + let browser: Browser + let page: Page + + const resolvedOptions = args + ? { + ...puppeteerOptions, + args: [...puppeteerOptions.args!, ...args], + } + : puppeteerOptions + + beforeAll(async () => { + browser = await puppeteer.launch(resolvedOptions) + }, 20000) + + beforeEach(async () => { + page = await browser.newPage() + + await page.evaluateOnNewDocument(() => { + localStorage.clear() + }) + + page.on('console', e => { + if (e.type() === 'error') { + console.error(`Error from Puppeteer-loaded page:\n`, e.text()) + } + }) + }) + + afterEach(async () => { + await page.close() + }) + + afterAll(async () => { + await browser.close() + }) + + async function click( + selector: string, + options?: ClickOptions, + ): Promise { + await page.click(selector, options) + } + + async function count(selector: string): Promise { + return (await page.$$(selector)).length + } + + async function text(selector: string): Promise { + return page.$eval(selector, node => node.textContent) + } + + async function value(selector: string): Promise { + return page.$eval(selector, node => (node as HTMLInputElement).value) + } + + async function html(selector: string): Promise { + return page.$eval(selector, node => node.innerHTML) + } + + async function classList(selector: string): Promise { + return page.$eval(selector, (node: any) => [...node.classList]) + } + + async function children(selector: string): Promise { + return page.$eval(selector, (node: any) => [...node.children]) + } + + async function style( + selector: string, + property: keyof CSSStyleDeclaration, + ): Promise { + return await page.$eval( + selector, + (node, property) => { + return window.getComputedStyle(node)[property] + }, + property, + ) + } + + async function isVisible(selector: string): Promise { + const display = await page.$eval(selector, node => { + return window.getComputedStyle(node).display + }) + return display !== 'none' + } + + async function isChecked(selector: string) { + return await page.$eval( + selector, + node => (node as HTMLInputElement).checked, + ) + } + + async function isFocused(selector: string) { + return await page.$eval(selector, node => node === document.activeElement) + } + + async function setValue(selector: string, value: string) { + await page.$eval( + selector, + (node, value) => { + ;(node as HTMLInputElement).value = value as string + node.dispatchEvent(new Event('input')) + }, + value, + ) + } + + async function typeValue(selector: string, value: string) { + const el = (await page.$(selector))! + await el.evaluate(node => ((node as HTMLInputElement).value = '')) + await el.type(value) + } + + async function enterValue(selector: string, value: string) { + const el = (await page.$(selector))! + await el.evaluate(node => ((node as HTMLInputElement).value = '')) + await el.type(value) + await el.press('Enter') + } + + async function clearValue(selector: string) { + return await page.$eval( + selector, + node => ((node as HTMLInputElement).value = ''), + ) + } + + function timeout(time: number) { + return page.evaluate(time => { + return new Promise(r => { + setTimeout(r, time) + }) + }, time) + } + + function nextFrame() { + return page.evaluate(() => { + return new Promise(resolve => { + requestAnimationFrame(() => { + requestAnimationFrame(resolve) + }) + }) + }) + } + + return { + page: () => page, + click, + count, + text, + value, + html, + classList, + style, + children, + isVisible, + isChecked, + isFocused, + setValue, + typeValue, + enterValue, + clearValue, + timeout, + nextFrame, + } +} diff --git a/packages-private/vapor-e2e-test/__tests__/todomvc.spec.ts b/packages-private/vapor-e2e-test/__tests__/todomvc.spec.ts new file mode 100644 index 0000000000..23f9e18e6d --- /dev/null +++ b/packages-private/vapor-e2e-test/__tests__/todomvc.spec.ts @@ -0,0 +1 @@ +test('bar', () => {}) diff --git a/packages-private/vapor-e2e-test/__tests__/vdomInterop.spec.ts b/packages-private/vapor-e2e-test/__tests__/vdomInterop.spec.ts new file mode 100644 index 0000000000..9a60a26ebc --- /dev/null +++ b/packages-private/vapor-e2e-test/__tests__/vdomInterop.spec.ts @@ -0,0 +1,84 @@ +import path from 'node:path' +import { + E2E_TIMEOUT, + setupPuppeteer, +} from '../../../packages/vue/__tests__/e2e/e2eUtils' +import connect from 'connect' +import sirv from 'sirv' + +describe('vdom / vapor interop', () => { + const { page, click, text, enterValue } = setupPuppeteer() + + let server: any + const port = '8193' + beforeAll(() => { + server = connect() + .use(sirv(path.resolve(import.meta.dirname, '../dist'))) + .listen(port) + process.on('SIGTERM', () => server && server.close()) + }) + + afterAll(() => { + server.close() + }) + + test( + 'should work', + async () => { + const baseUrl = `http://localhost:${port}/interop` + await page().goto(baseUrl) + + expect(await text('.vapor > h2')).toContain('Vapor component in VDOM') + + expect(await text('.vapor-prop')).toContain('hello') + + const t = await text('.vdom-slot-in-vapor-default') + expect(t).toContain('slot prop: slot prop') + expect(t).toContain('component prop: hello') + + await click('.change-vdom-slot-in-vapor-prop') + expect(await text('.vdom-slot-in-vapor-default')).toContain( + 'slot prop: changed', + ) + + expect(await text('.vdom-slot-in-vapor-test')).toContain('A test slot') + + await click('.toggle-vdom-slot-in-vapor') + expect(await text('.vdom-slot-in-vapor-test')).toContain( + 'fallback content', + ) + + await click('.toggle-vdom-slot-in-vapor') + expect(await text('.vdom-slot-in-vapor-test')).toContain('A test slot') + + expect(await text('.vdom > h2')).toContain('VDOM component in Vapor') + + expect(await text('.vdom-prop')).toContain('hello') + + const tt = await text('.vapor-slot-in-vdom-default') + expect(tt).toContain('slot prop: slot prop') + expect(tt).toContain('component prop: hello') + + await click('.change-vapor-slot-in-vdom-prop') + expect(await text('.vapor-slot-in-vdom-default')).toContain( + 'slot prop: changed', + ) + + expect(await text('.vapor-slot-in-vdom-test')).toContain('fallback') + + await click('.toggle-vapor-slot-in-vdom-default') + expect(await text('.vapor-slot-in-vdom-default')).toContain( + 'default slot fallback', + ) + + await click('.toggle-vapor-slot-in-vdom-default') + + await enterValue('input', 'bye') + expect(await text('.vapor-prop')).toContain('bye') + expect(await text('.vdom-slot-in-vapor-default')).toContain('bye') + expect(await text('.vdom-prop')).toContain('bye') + expect(await text('.vapor-slot-in-vdom-default')).toContain('bye') + }, + E2E_TIMEOUT, + ) +}) diff --git a/packages-private/vapor-e2e-test/index.html b/packages-private/vapor-e2e-test/index.html new file mode 100644 index 0000000000..7dc205e5ab --- /dev/null +++ b/packages-private/vapor-e2e-test/index.html @@ -0,0 +1,2 @@ +VDOM / Vapor interop +Vapor TodoMVC diff --git a/packages-private/vapor-e2e-test/interop/App.vue b/packages-private/vapor-e2e-test/interop/App.vue new file mode 100644 index 0000000000..772a6989dd --- /dev/null +++ b/packages-private/vapor-e2e-test/interop/App.vue @@ -0,0 +1,22 @@ + + + diff --git a/packages-private/vapor-e2e-test/interop/VaporComp.vue b/packages-private/vapor-e2e-test/interop/VaporComp.vue new file mode 100644 index 0000000000..88a60c782c --- /dev/null +++ b/packages-private/vapor-e2e-test/interop/VaporComp.vue @@ -0,0 +1,50 @@ + + + diff --git a/packages-private/vapor-e2e-test/interop/VdomComp.vue b/packages-private/vapor-e2e-test/interop/VdomComp.vue new file mode 100644 index 0000000000..30ec1b2eeb --- /dev/null +++ b/packages-private/vapor-e2e-test/interop/VdomComp.vue @@ -0,0 +1,28 @@ + + + diff --git a/packages-private/vapor-e2e-test/interop/index.html b/packages-private/vapor-e2e-test/interop/index.html new file mode 100644 index 0000000000..79052a023b --- /dev/null +++ b/packages-private/vapor-e2e-test/interop/index.html @@ -0,0 +1,2 @@ + +
diff --git a/packages-private/vapor-e2e-test/interop/main.ts b/packages-private/vapor-e2e-test/interop/main.ts new file mode 100644 index 0000000000..d5d6d7dcf8 --- /dev/null +++ b/packages-private/vapor-e2e-test/interop/main.ts @@ -0,0 +1,4 @@ +import { createApp, vaporInteropPlugin } from 'vue' +import App from './App.vue' + +createApp(App).use(vaporInteropPlugin).mount('#app') diff --git a/packages-private/vapor-e2e-test/package.json b/packages-private/vapor-e2e-test/package.json new file mode 100644 index 0000000000..66ea0457ec --- /dev/null +++ b/packages-private/vapor-e2e-test/package.json @@ -0,0 +1,18 @@ +{ + "name": "vapor-e2e-test", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite dev", + "build": "vite build" + }, + "devDependencies": { + "@types/connect": "^3.4.38", + "@vitejs/plugin-vue": "catalog:", + "connect": "^3.7.0", + "sirv": "^2.0.4", + "vite": "catalog:", + "vue": "workspace:*" + } +} diff --git a/packages-private/vapor-e2e-test/todomvc/index.html b/packages-private/vapor-e2e-test/todomvc/index.html new file mode 100644 index 0000000000..689a5a8edf --- /dev/null +++ b/packages-private/vapor-e2e-test/todomvc/index.html @@ -0,0 +1 @@ + diff --git a/packages-private/vapor-e2e-test/todomvc/main.ts b/packages-private/vapor-e2e-test/todomvc/main.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages-private/vapor-e2e-test/vite.config.ts b/packages-private/vapor-e2e-test/vite.config.ts new file mode 100644 index 0000000000..1e29a4dbd1 --- /dev/null +++ b/packages-private/vapor-e2e-test/vite.config.ts @@ -0,0 +1,20 @@ +import { defineConfig } from 'vite' +import Vue from '@vitejs/plugin-vue' +import * as CompilerSFC from 'vue/compiler-sfc' +import { resolve } from 'node:path' + +export default defineConfig({ + plugins: [ + Vue({ + compiler: CompilerSFC, + }), + ], + build: { + rollupOptions: { + input: { + interop: resolve(import.meta.dirname, 'interop/index.html'), + todomvc: resolve(import.meta.dirname, 'todomvc/index.html'), + }, + }, + }, +}) diff --git a/packages/vue/__tests__/e2e/e2eUtils.ts b/packages/vue/__tests__/e2e/e2eUtils.ts index 1ed5322d1f..2ffebeb595 100644 --- a/packages/vue/__tests__/e2e/e2eUtils.ts +++ b/packages/vue/__tests__/e2e/e2eUtils.ts @@ -76,8 +76,7 @@ export function setupPuppeteer(args?: string[]): PuppeteerUtils { page.on('console', e => { if (e.type() === 'error') { - const err = e.args()[0] - console.error(`Error from Puppeteer-loaded page:\n`, err.remoteObject()) + console.error(`Error from Puppeteer-loaded page:\n`, e.text()) } }) }) diff --git a/packages/vue/package.json b/packages/vue/package.json index b434379d01..afaceec96c 100644 --- a/packages/vue/package.json +++ b/packages/vue/package.json @@ -79,7 +79,7 @@ "global-runtime", "esm-browser", "esm-browser-runtime", - "vapor" + "esm-browser-vapor" ] }, "repository": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0f5e574ff0..05fb94ef2a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,7 +13,7 @@ catalogs: specifier: ^7.25.2 version: 7.26.0 '@vitejs/plugin-vue': - specifier: ^5.2.1 + specifier: https://pkg.pr.new/@vitejs/plugin-vue@c156992 version: 5.2.1 estree-walker: specifier: ^2.0.2 @@ -201,9 +201,6 @@ importers: '@types/connect': specifier: ^3.4.38 version: 3.4.38 - terser: - specifier: ^5.33.0 - version: 5.33.0 packages-private/dts-built-test: dependencies: @@ -226,6 +223,8 @@ importers: specifier: workspace:* version: link:../../packages/vue + packages-private/e2e-utils: {} + packages-private/local-playground: dependencies: '@vueuse/core': @@ -236,7 +235,7 @@ importers: version: link:../../packages/vue devDependencies: '@vitejs/plugin-vue': - specifier: https://pkg.pr.new/@vitejs/plugin-vue@c156992 + specifier: 'catalog:' version: https://pkg.pr.new/@vitejs/plugin-vue@c156992(vite@6.1.0(@types/node@22.10.7)(sass@1.83.4)(terser@5.33.0)(yaml@2.6.1))(vue@packages+vue) '@vue/compiler-sfc': specifier: workspace:* @@ -268,7 +267,7 @@ importers: devDependencies: '@vitejs/plugin-vue': specifier: 'catalog:' - version: 5.2.1(vite@6.1.0(@types/node@22.10.7)(sass@1.83.4)(terser@5.33.0)(yaml@2.6.1))(vue@packages+vue) + version: https://pkg.pr.new/@vitejs/plugin-vue@c156992(vite@6.1.0(@types/node@22.10.7)(sass@1.83.4)(terser@5.33.0)(yaml@2.6.1))(vue@packages+vue) vite: specifier: 'catalog:' version: 6.1.0(@types/node@22.10.7)(sass@1.83.4)(terser@5.33.0)(yaml@2.6.1) @@ -285,11 +284,32 @@ importers: specifier: ^1.2.1 version: 1.2.1 + packages-private/vapor-e2e-test: + devDependencies: + '@types/connect': + specifier: ^3.4.38 + version: 3.4.38 + '@vitejs/plugin-vue': + specifier: 'catalog:' + version: https://pkg.pr.new/@vitejs/plugin-vue@c156992(vite@6.1.0(@types/node@22.10.7)(sass@1.83.4)(terser@5.33.0)(yaml@2.6.1))(vue@packages+vue) + connect: + specifier: ^3.7.0 + version: 3.7.0 + sirv: + specifier: ^2.0.4 + version: 2.0.4 + vite: + specifier: 'catalog:' + version: 6.1.0(@types/node@22.10.7)(sass@1.83.4)(terser@5.33.0)(yaml@2.6.1) + vue: + specifier: workspace:* + version: link:../../packages/vue + packages-private/vite-debug: devDependencies: '@vitejs/plugin-vue': specifier: 'catalog:' - version: 5.2.1(vite@6.1.0(@types/node@22.10.7)(sass@1.83.4)(terser@5.33.0)(yaml@2.6.1))(vue@packages+vue) + version: https://pkg.pr.new/@vitejs/plugin-vue@c156992(vite@6.1.0(@types/node@22.10.7)(sass@1.83.4)(terser@5.33.0)(yaml@2.6.1))(vue@packages+vue) vite: specifier: 'catalog:' version: 6.1.0(@types/node@22.10.7)(sass@1.83.4)(terser@5.33.0)(yaml@2.6.1) @@ -1427,13 +1447,6 @@ packages: resolution: {integrity: sha512-v/BpkeeYAsPkKCkR8BDwcno0llhzWVqPOamQrAEMdpZav2Y9OVjd9dwJyBLJWwf335B5DmlifECIkZRJCaGaHA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@vitejs/plugin-vue@5.2.1': - resolution: {integrity: sha512-cxh314tzaWwOLqVes2gnnCtvBDcM1UMdn+iFR+UjAn411dPT3tOmqrJjbMd7koZpMAmBM/GqeV4n9ge7JSiJJQ==} - engines: {node: ^18.0.0 || >=20.0.0} - peerDependencies: - vite: ^5.0.0 || ^6.0.0 - vue: ^3.2.25 - '@vitejs/plugin-vue@https://pkg.pr.new/@vitejs/plugin-vue@c156992': resolution: {tarball: https://pkg.pr.new/@vitejs/plugin-vue@c156992} version: 5.2.1 @@ -4196,6 +4209,7 @@ snapshots: dependencies: '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 + optional: true '@jridgewell/sourcemap-codec@1.5.0': {} @@ -4608,11 +4622,6 @@ snapshots: '@typescript-eslint/types': 8.20.0 eslint-visitor-keys: 4.2.0 - '@vitejs/plugin-vue@5.2.1(vite@6.1.0(@types/node@22.10.7)(sass@1.83.4)(terser@5.33.0)(yaml@2.6.1))(vue@packages+vue)': - dependencies: - vite: 6.1.0(@types/node@22.10.7)(sass@1.83.4)(terser@5.33.0)(yaml@2.6.1) - vue: link:packages/vue - '@vitejs/plugin-vue@https://pkg.pr.new/@vitejs/plugin-vue@c156992(vite@6.1.0(@types/node@22.10.7)(sass@1.83.4)(terser@5.33.0)(yaml@2.6.1))(vue@3.5.13(typescript@5.6.2))': dependencies: vite: 6.1.0(@types/node@22.10.7)(sass@1.83.4)(terser@5.33.0)(yaml@2.6.1) @@ -4925,7 +4934,8 @@ snapshots: buffer-crc32@0.2.13: {} - buffer-from@1.1.2: {} + buffer-from@1.1.2: + optional: true buffer@5.7.1: dependencies: @@ -5046,7 +5056,8 @@ snapshots: commander@12.1.0: {} - commander@2.20.3: {} + commander@2.20.3: + optional: true commondir@1.0.1: {} @@ -6747,6 +6758,7 @@ snapshots: dependencies: buffer-from: 1.1.2 source-map: 0.6.1 + optional: true source-map@0.6.1: {} @@ -6864,6 +6876,7 @@ snapshots: acorn: 8.14.0 commander: 2.20.3 source-map-support: 0.5.21 + optional: true test-exclude@7.0.1: dependencies: diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index c33fbb43b7..9754a377ae 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -9,4 +9,4 @@ catalog: 'magic-string': ^0.30.11 'source-map-js': ^1.2.0 'vite': ^6.1.0 - '@vitejs/plugin-vue': ^5.2.1 + '@vitejs/plugin-vue': https://pkg.pr.new/@vitejs/plugin-vue@c156992 diff --git a/rollup.config.js b/rollup.config.js index b97d6593c5..7f2ecb8c86 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -22,7 +22,7 @@ import { trimVaporExportsPlugin } from './scripts/trim-vapor-exports.js' * @template {keyof T} K * @typedef { Omit & Required> } MarkRequired */ -/** @typedef {'cjs' | 'esm-bundler' | 'global' | 'global-runtime' | 'esm-browser' | 'esm-bundler-runtime' | 'esm-browser-runtime' | 'vapor'} PackageFormat */ +/** @typedef {'cjs' | 'esm-bundler' | 'global' | 'global-runtime' | 'esm-browser' | 'esm-bundler-runtime' | 'esm-browser-runtime' | 'esm-browser-vapor'} PackageFormat */ /** @typedef {MarkRequired} OutputOptions */ if (!process.env.TARGET) { @@ -88,7 +88,7 @@ const outputConfigs = { }, // The vapor format is a esm-browser + runtime only build that is meant for // the SFC playground only. - vapor: { + 'esm-browser-vapor': { file: resolve(`dist/${name}.runtime-with-vapor.esm-browser.js`), format: 'es', }, @@ -114,7 +114,10 @@ if (process.env.NODE_ENV === 'production') { if (format === 'cjs') { packageConfigs.push(createProductionConfig(format)) } - if (format === 'vapor' || /^(global|esm-browser)(-runtime)?/.test(format)) { + if ( + format === 'esm-browser-vapor' || + /^(global|esm-browser)(-runtime)?/.test(format) + ) { packageConfigs.push(createMinifiedConfig(format)) } }) @@ -138,7 +141,7 @@ function createConfig(format, output, plugins = []) { const isProductionBuild = process.env.__DEV__ === 'false' || /\.prod\.js$/.test(output.file) const isBundlerESMBuild = /esm-bundler/.test(format) - const isBrowserESMBuild = /esm-browser/.test(format) || format === 'vapor' + const isBrowserESMBuild = /esm-browser/.test(format) const isServerRenderer = name === 'server-renderer' const isCJSBuild = format === 'cjs' const isGlobalBuild = /global/.test(format) @@ -164,13 +167,16 @@ function createConfig(format, output, plugins = []) { output.name = packageOptions.name } - let entryFile = - pkg.name === 'vue' && - (format === 'vapor' || format.startsWith('esm-bundler')) - ? 'runtime-with-vapor.ts' - : /\bruntime\b/.test(format) - ? `runtime.ts` - : `index.ts` + let entryFile = 'index.ts' + if (pkg.name === 'vue') { + if (format === 'esm-browser-vapor' || format === 'esm-bundler-runtime') { + entryFile = 'runtime-with-vapor.ts' + } else if (format === 'esm-bundler') { + entryFile = 'index-with-vapor.ts' + } else if (format.includes('runtime')) { + entryFile = 'runtime.ts' + } + } // the compat build needs both default AND named exports. This will cause // Rollup to complain for non-ESM targets, so we use separate entries for diff --git a/scripts/build.js b/scripts/build.js index 01d1cba52e..76e6612d5c 100644 --- a/scripts/build.js +++ b/scripts/build.js @@ -173,11 +173,17 @@ async function build(target) { return } + let resolvedFormats if (formats) { - let resolvedFormats = formats.split('+') + const isNegation = formats.startsWith('~') + resolvedFormats = (isNegation ? formats.slice(1) : formats).split('+') const pkgFormats = pkg.buildOptions?.formats if (pkgFormats) { - resolvedFormats = resolvedFormats.filter(f => pkgFormats.includes(f)) + if (isNegation) { + resolvedFormats = pkgFormats.filter(f => !resolvedFormats.includes(f)) + } else { + resolvedFormats = resolvedFormats.filter(f => pkgFormats.includes(f)) + } } if (!resolvedFormats.length) { return @@ -202,7 +208,7 @@ async function build(target) { `COMMIT:${commit}`, `NODE_ENV:${env}`, `TARGET:${target}`, - formats ? `FORMATS:${formats}` : ``, + resolvedFormats ? `FORMATS:${resolvedFormats.join('+')}` : ``, prodOnly ? `PROD_ONLY:true` : ``, sourceMap ? `SOURCE_MAP:true` : ``, ] @@ -219,7 +225,10 @@ async function build(target) { * @returns {Promise} */ async function checkAllSizes(targets) { - if (devOnly || (formats && !formats.includes('global'))) { + if ( + devOnly || + (formats && (formats.startsWith('~') || !formats.includes('global'))) + ) { return } console.log() diff --git a/scripts/dev.js b/scripts/dev.js index 06bf7de93e..f869074922 100644 --- a/scripts/dev.js +++ b/scripts/dev.js @@ -50,7 +50,7 @@ const outputFormat = format.startsWith('global') : 'esm' const postfix = - format === 'vapor' + format === 'esm-browser-vapor' ? 'runtime-with-vapor.esm-browser' : format.endsWith('-runtime') ? `runtime.${format.replace(/-runtime$/, '')}` @@ -131,7 +131,7 @@ for (const target of targets) { } const entry = - format === 'vapor' + format === 'esm-browser-vapor' ? 'runtime-with-vapor.ts' : format.endsWith('-runtime') ? 'runtime.ts' diff --git a/scripts/trim-vapor-exports.js b/scripts/trim-vapor-exports.js index 672192fc6c..313a1a9b8e 100644 --- a/scripts/trim-vapor-exports.js +++ b/scripts/trim-vapor-exports.js @@ -12,7 +12,7 @@ */ export function trimVaporExportsPlugin(format, pkgName) { if ( - format === 'vapor' || + format.includes('vapor') || format.startsWith('esm-bundler') || pkgName === '@vue/runtime-vapor' ) { diff --git a/vitest.config.ts b/vitest.config.ts index 425b509ed9..8daa34f7ed 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -1,4 +1,4 @@ -import { defineConfig } from 'vitest/config' +import { configDefaults, defineConfig } from 'vitest/config' import { entries } from './scripts/aliases.js' export default defineConfig({ @@ -31,9 +31,6 @@ export default defineConfig({ }, }, setupFiles: 'scripts/setup-vitest.ts', - environmentMatchGlobs: [ - ['packages/{vue,vue-compat,runtime-dom,runtime-vapor}/**', 'jsdom'], - ], sequence: { hooks: 'list', }, @@ -55,5 +52,54 @@ export default defineConfig({ 'packages/runtime-dom/src/components/Transition*', ], }, + workspace: [ + { + extends: true, + test: { + name: 'unit', + exclude: [ + ...configDefaults.exclude, + '**/e2e/**', + '**/vapor-e2e-test/**', + 'packages/{vue,vue-compat,runtime-dom,runtime-vapor}/**', + ], + }, + }, + { + extends: true, + test: { + name: 'unit-jsdom', + environment: 'jsdom', + include: [ + 'packages/{vue,vue-compat,runtime-dom,runtime-vapor}/**/*.spec.ts', + ], + exclude: [...configDefaults.exclude, '**/e2e/**'], + }, + }, + { + extends: true, + test: { + name: 'e2e', + poolOptions: { + threads: { + singleThread: !!process.env.CI, + }, + }, + include: ['packages/vue/__tests__/e2e/*.spec.ts'], + }, + }, + { + extends: true, + test: { + name: 'e2e-vapor', + poolOptions: { + threads: { + singleThread: !!process.env.CI, + }, + }, + include: ['packages-private/vapor-e2e-test/__tests__/*.spec.ts'], + }, + }, + ], }, }) diff --git a/vitest.e2e.config.ts b/vitest.e2e.config.ts deleted file mode 100644 index 622bda0bd5..0000000000 --- a/vitest.e2e.config.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { mergeConfig } from 'vitest/config' -import config from './vitest.config' - -export default mergeConfig(config, { - test: { - name: 'e2e', - poolOptions: { - threads: { - singleThread: !!process.env.CI, - }, - }, - include: ['packages/vue/__tests__/e2e/*.spec.ts'], - }, -}) diff --git a/vitest.unit.config.ts b/vitest.unit.config.ts deleted file mode 100644 index 0082997e0d..0000000000 --- a/vitest.unit.config.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { configDefaults, mergeConfig } from 'vitest/config' -import config from './vitest.config' - -export default mergeConfig(config, { - test: { - name: 'unit', - exclude: [...configDefaults.exclude, '**/e2e/**'], - }, -}) diff --git a/vitest.workspace.ts b/vitest.workspace.ts deleted file mode 100644 index a20586e7cf..0000000000 --- a/vitest.workspace.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { defineWorkspace } from 'vitest/config' - -export default defineWorkspace([ - './vitest.unit.config.ts', - './vitest.e2e.config.ts', -])