From 03012b67bb76d78ad5ff70f63b23974fee5cdce3 Mon Sep 17 00:00:00 2001 From: "Anthony Fu (via agent)" Date: Wed, 15 Jul 2026 07:44:14 +0000 Subject: [PATCH 1/2] feat: add production playground for testing the real user install path Adds playgrounds/production, a standalone pnpm workspace that installs Vite DevTools from the local built dist tarballs instead of aliasing to source, so the tools can be exercised the way a real user consumes them. A pack-local script builds the monorepo and runs pnpm pack on the five published packages, resolving workspace:/catalog: protocols into concrete versions. pnpm-workspace.yaml overrides point every @vitejs/devtools-* package at those tarballs; all other dependencies resolve from the public registry. --- playgrounds/production/.gitignore | 5 ++ playgrounds/production/README.md | 60 +++++++++++++++ playgrounds/production/index.html | 12 +++ playgrounds/production/package.json | 23 ++++++ playgrounds/production/pnpm-workspace.yaml | 25 +++++++ playgrounds/production/scripts/pack-local.mjs | 75 +++++++++++++++++++ playgrounds/production/src/App.vue | 35 +++++++++ playgrounds/production/src/env.d.ts | 8 ++ playgrounds/production/src/main.ts | 5 ++ playgrounds/production/src/style.css | 2 + playgrounds/production/tsconfig.json | 17 +++++ playgrounds/production/vite.config.ts | 20 +++++ 12 files changed, 287 insertions(+) create mode 100644 playgrounds/production/.gitignore create mode 100644 playgrounds/production/README.md create mode 100644 playgrounds/production/index.html create mode 100644 playgrounds/production/package.json create mode 100644 playgrounds/production/pnpm-workspace.yaml create mode 100644 playgrounds/production/scripts/pack-local.mjs create mode 100644 playgrounds/production/src/App.vue create mode 100644 playgrounds/production/src/env.d.ts create mode 100644 playgrounds/production/src/main.ts create mode 100644 playgrounds/production/src/style.css create mode 100644 playgrounds/production/tsconfig.json create mode 100644 playgrounds/production/vite.config.ts diff --git a/playgrounds/production/.gitignore b/playgrounds/production/.gitignore new file mode 100644 index 000000000..0d856d583 --- /dev/null +++ b/playgrounds/production/.gitignore @@ -0,0 +1,5 @@ +node_modules +dist +.tarballs +pnpm-lock.yaml +*.local diff --git a/playgrounds/production/README.md b/playgrounds/production/README.md new file mode 100644 index 000000000..1221a8483 --- /dev/null +++ b/playgrounds/production/README.md @@ -0,0 +1,60 @@ +# Production Playground + +A **standalone pnpm workspace** that installs Vite DevTools from the **local +built dist**, so you can test the tools the way a real user consumes them — +from the packaged artifacts, with no monorepo aliases, `src` imports, or +`workspace:` links. + +The regular playground at `packages/core/playground` aliases everything to +source for fast iteration. This one does the opposite: it packs the published +packages into tarballs and installs them, exercising the real npm install path +and the `dist` output. + +## How it works + +`scripts/pack-local.mjs` builds the monorepo and runs `pnpm pack` on the five +published packages (`@vitejs/devtools`, `-kit`, `-rolldown`, `-vite`, +`-vitest`). `pnpm pack` rewrites each package's `workspace:*` and `catalog:*` +protocols into concrete versions, producing the exact tarballs npm would serve. +The tarballs land in `.tarballs/` under stable names; `pnpm-workspace.yaml` +points `@vitejs/devtools` and every inter-package dependency at them through +`overrides`. Everything else (devframe, `@devframes/*`, vite, vue) resolves +from the public registry — just like a real install. + +Its own `pnpm-workspace.yaml` keeps it isolated from the monorepo above, so a +`pnpm install` here builds an independent dependency tree with its own lockfile. + +## Usage + +From this directory: + +```sh +# Build the monorepo, pack the packages, and install them +pnpm run setup + +# Start the dev server (embedded DevTools panel) +pnpm dev + +# Or produce a production build (standalone DevTools output) +pnpm build +``` + +To re-pack after changing package source without rebuilding untouched packages, +`pnpm run setup` re-runs the turbo build (cached) and re-packs. If you already +have fresh `dist` output and only want to re-pack + reinstall: + +```sh +pnpm run setup:no-build +``` + +If pnpm doesn't pick up freshly re-packed tarballs, force it: + +```sh +pnpm install --no-frozen-lockfile --force +``` + +## Layout + +- `scripts/pack-local.mjs` — build + pack the published packages into `.tarballs/` +- `vite.config.ts` — a plain user config importing `DevTools` from `@vitejs/devtools` +- `src/` — a minimal Vue app so the panels have real build/module data diff --git a/playgrounds/production/index.html b/playgrounds/production/index.html new file mode 100644 index 000000000..03b51a551 --- /dev/null +++ b/playgrounds/production/index.html @@ -0,0 +1,12 @@ + + + + + + Vite DevTools — Production Playground + + +
+ + + diff --git a/playgrounds/production/package.json b/playgrounds/production/package.json new file mode 100644 index 000000000..03e0069bc --- /dev/null +++ b/playgrounds/production/package.json @@ -0,0 +1,23 @@ +{ + "name": "playground-production", + "type": "module", + "version": "0.0.0", + "private": true, + "description": "Standalone workspace that installs Vite DevTools from the local built dist, to test the real user install experience.", + "scripts": { + "setup": "node scripts/pack-local.mjs && pnpm install --no-frozen-lockfile", + "setup:no-build": "node scripts/pack-local.mjs --no-build && pnpm install --no-frozen-lockfile", + "pack:local": "node scripts/pack-local.mjs", + "dev": "vite --host", + "build": "vite build", + "preview": "vite preview --host" + }, + "dependencies": { + "@vitejs/devtools": "file:.tarballs/vitejs-devtools.tgz", + "vue": "^3.5.39" + }, + "devDependencies": { + "@vitejs/plugin-vue": "^6.0.7", + "vite": "^8.1.4" + } +} diff --git a/playgrounds/production/pnpm-workspace.yaml b/playgrounds/production/pnpm-workspace.yaml new file mode 100644 index 000000000..a2a7b2439 --- /dev/null +++ b/playgrounds/production/pnpm-workspace.yaml @@ -0,0 +1,25 @@ +# Standalone workspace root. +# +# This file exists so pnpm treats `playgrounds/production` as its own, +# self-contained project instead of a member of the monorepo above it. +# It resolves `@vitejs/devtools` (and friends) from the local built dist +# tarballs produced by `scripts/pack-local.mjs`, and every other dependency +# (devframe, @devframes/*, vite, vue, ...) from the public registry — exactly +# what a real user gets when they `pnpm add -D @vitejs/devtools`. +packages: [] + +# Resolve Vite DevTools and every inter-package dependency from the local built +# dist tarballs produced by `scripts/pack-local.mjs`. Everything else resolves +# from the public registry, exactly like a real user install. +overrides: + '@vitejs/devtools': 'file:.tarballs/vitejs-devtools.tgz' + '@vitejs/devtools-kit': 'file:.tarballs/vitejs-devtools-kit.tgz' + '@vitejs/devtools-rolldown': 'file:.tarballs/vitejs-devtools-rolldown.tgz' + '@vitejs/devtools-vite': 'file:.tarballs/vitejs-devtools-vite.tgz' + '@vitejs/devtools-vitest': 'file:.tarballs/vitejs-devtools-vitest.tgz' + +# Native deps that need their install scripts to run. +allowBuilds: + esbuild: true + rolldown: true + unrs-resolver: true diff --git a/playgrounds/production/scripts/pack-local.mjs b/playgrounds/production/scripts/pack-local.mjs new file mode 100644 index 000000000..376adcce3 --- /dev/null +++ b/playgrounds/production/scripts/pack-local.mjs @@ -0,0 +1,75 @@ +// @ts-check +/** + * Build the Vite DevTools packages and pack them into local tarballs that this + * standalone playground installs — the same artifacts that would be published + * to npm, so the playground exercises the real user install path. + * + * Usage: + * node scripts/pack-local.mjs # build the monorepo, then pack + * node scripts/pack-local.mjs --no-build # skip the build, just (re)pack dist + * + * `pnpm pack` resolves each package's `workspace:*` and `catalog:*` protocols + * into concrete versions, so the tarballs are exactly what end users receive. + * The playground's package.json then points `@vitejs/devtools` and every + * inter-package dependency at these tarballs via `pnpm.overrides`. + */ +import { execSync } from 'node:child_process' +import { mkdirSync, readdirSync, renameSync, rmSync } from 'node:fs' +import { dirname, join, resolve } from 'node:path' +import { fileURLToPath } from 'node:url' + +const scriptDir = dirname(fileURLToPath(import.meta.url)) +const playgroundDir = resolve(scriptDir, '..') +const repoRoot = resolve(playgroundDir, '../..') +const tarballDir = join(playgroundDir, '.tarballs') + +/** + * The set of packages published to npm as part of Vite DevTools. + * `@vitejs/devtools-ui` is private (bundled into the others at build time) and + * `@vitejs/devtools-oxc` is a separate opt-in package, so neither is packed. + * + * @type {Array<{ name: string, dir: string, out: string }>} + */ +const PACKAGES = [ + { name: '@vitejs/devtools', dir: 'packages/core', out: 'vitejs-devtools.tgz' }, + { name: '@vitejs/devtools-kit', dir: 'packages/kit', out: 'vitejs-devtools-kit.tgz' }, + { name: '@vitejs/devtools-rolldown', dir: 'packages/rolldown', out: 'vitejs-devtools-rolldown.tgz' }, + { name: '@vitejs/devtools-vite', dir: 'packages/vite', out: 'vitejs-devtools-vite.tgz' }, + { name: '@vitejs/devtools-vitest', dir: 'packages/vitest', out: 'vitejs-devtools-vitest.tgz' }, +] + +const skipBuild = process.argv.includes('--no-build') + +/** @param {string} cmd @param {string} cwd */ +function run(cmd, cwd) { + console.log(`\n$ ${cmd}\n (cwd: ${cwd})`) + execSync(cmd, { cwd, stdio: 'inherit' }) +} + +if (!skipBuild) { + run('pnpm build', repoRoot) +} + +rmSync(tarballDir, { recursive: true, force: true }) +mkdirSync(tarballDir, { recursive: true }) + +// Pack each package. `--ignore-scripts` skips the `prepack` rebuild since the +// monorepo build above already produced fresh dist output. +for (const { name, dir } of PACKAGES) { + run(`pnpm pack --config.ignore-scripts=true --pack-destination "${tarballDir}"`, join(repoRoot, dir)) +} + +// pnpm writes `-.tgz`; rename to the stable, version-agnostic +// names the playground's package.json / overrides reference. +const produced = readdirSync(tarballDir) +for (const { name, out } of PACKAGES) { + const base = name.replace('@', '').replace('/', '-') + const pattern = new RegExp(`^${base.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}-\\d[^/]*\\.tgz$`) + const match = produced.find(f => pattern.test(f)) + if (!match) + throw new Error(`Could not find packed tarball for ${name} (expected ${base}-.tgz)`) + renameSync(join(tarballDir, match), join(tarballDir, out)) + console.log(`✓ ${name} -> .tarballs/${out}`) +} + +console.log('\nDone. Now run: pnpm install --no-frozen-lockfile') diff --git a/playgrounds/production/src/App.vue b/playgrounds/production/src/App.vue new file mode 100644 index 000000000..e8f21d13d --- /dev/null +++ b/playgrounds/production/src/App.vue @@ -0,0 +1,35 @@ + + + + + diff --git a/playgrounds/production/src/env.d.ts b/playgrounds/production/src/env.d.ts new file mode 100644 index 000000000..f4556c763 --- /dev/null +++ b/playgrounds/production/src/env.d.ts @@ -0,0 +1,8 @@ +/// + +declare module '*.vue' { + import type { DefineComponent } from 'vue' + + const component: DefineComponent, Record, unknown> + export default component +} diff --git a/playgrounds/production/src/main.ts b/playgrounds/production/src/main.ts new file mode 100644 index 000000000..fe5bae398 --- /dev/null +++ b/playgrounds/production/src/main.ts @@ -0,0 +1,5 @@ +import { createApp } from 'vue' +import App from './App.vue' +import './style.css' + +createApp(App).mount('#app') diff --git a/playgrounds/production/src/style.css b/playgrounds/production/src/style.css new file mode 100644 index 000000000..7a8a4fbcf --- /dev/null +++ b/playgrounds/production/src/style.css @@ -0,0 +1,2 @@ +:root { color-scheme: light dark; } +body { margin: 0; } diff --git a/playgrounds/production/tsconfig.json b/playgrounds/production/tsconfig.json new file mode 100644 index 000000000..126e525d6 --- /dev/null +++ b/playgrounds/production/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "target": "ESNext", + "module": "ESNext", + "moduleResolution": "Bundler", + "strict": true, + "jsx": "preserve", + "resolveJsonModule": true, + "isolatedModules": true, + "esModuleInterop": true, + "lib": ["ESNext", "DOM", "DOM.Iterable"], + "skipLibCheck": true, + "noEmit": true, + "types": ["vite/client"] + }, + "include": ["src", "vite.config.ts", "env.d.ts"] +} diff --git a/playgrounds/production/vite.config.ts b/playgrounds/production/vite.config.ts new file mode 100644 index 000000000..545b29473 --- /dev/null +++ b/playgrounds/production/vite.config.ts @@ -0,0 +1,20 @@ +import { DevTools } from '@vitejs/devtools' +import Vue from '@vitejs/plugin-vue' +import { defineConfig } from 'vite' + +// This config is intentionally written the way a real user would write it: +// it imports `DevTools` from the published `@vitejs/devtools` package (resolved +// here from the local built dist), with no monorepo aliases or `src` imports. +export default defineConfig({ + plugins: [ + Vue(), + DevTools(), + ], + build: { + rolldownOptions: { + // Enable Rolldown's devtools build instrumentation so the Rolldown + // panels have real build data to show. + devtools: {}, + }, + }, +}) From 89055e5eed732a406d0407818479dbbeb283b50d Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Wed, 15 Jul 2026 16:52:31 +0900 Subject: [PATCH 2/2] chore: update --- packages/oxc/package.json | 1 + playgrounds/production/pnpm-workspace.yaml | 4 +++- playgrounds/production/scripts/pack-local.mjs | 3 +++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/oxc/package.json b/packages/oxc/package.json index 24be793de..4106f1562 100644 --- a/packages/oxc/package.json +++ b/packages/oxc/package.json @@ -29,6 +29,7 @@ "devtools-oxc": "./bin/devtools-oxc.mjs" }, "files": [ + "bin", "dist" ], "scripts": { diff --git a/playgrounds/production/pnpm-workspace.yaml b/playgrounds/production/pnpm-workspace.yaml index a2a7b2439..a01b2017d 100644 --- a/playgrounds/production/pnpm-workspace.yaml +++ b/playgrounds/production/pnpm-workspace.yaml @@ -17,9 +17,11 @@ overrides: '@vitejs/devtools-rolldown': 'file:.tarballs/vitejs-devtools-rolldown.tgz' '@vitejs/devtools-vite': 'file:.tarballs/vitejs-devtools-vite.tgz' '@vitejs/devtools-vitest': 'file:.tarballs/vitejs-devtools-vitest.tgz' + '@vitejs/devtools-oxc': 'file:.tarballs/vitejs-devtools-oxc.tgz' -# Native deps that need their install scripts to run. +verifyDepsBeforeRun: false allowBuilds: esbuild: true rolldown: true unrs-resolver: true +minimumReleaseAge: 0 diff --git a/playgrounds/production/scripts/pack-local.mjs b/playgrounds/production/scripts/pack-local.mjs index 376adcce3..b6b25591d 100644 --- a/playgrounds/production/scripts/pack-local.mjs +++ b/playgrounds/production/scripts/pack-local.mjs @@ -16,6 +16,7 @@ import { execSync } from 'node:child_process' import { mkdirSync, readdirSync, renameSync, rmSync } from 'node:fs' import { dirname, join, resolve } from 'node:path' +import process from 'node:process' import { fileURLToPath } from 'node:url' const scriptDir = dirname(fileURLToPath(import.meta.url)) @@ -36,6 +37,7 @@ const PACKAGES = [ { name: '@vitejs/devtools-rolldown', dir: 'packages/rolldown', out: 'vitejs-devtools-rolldown.tgz' }, { name: '@vitejs/devtools-vite', dir: 'packages/vite', out: 'vitejs-devtools-vite.tgz' }, { name: '@vitejs/devtools-vitest', dir: 'packages/vitest', out: 'vitejs-devtools-vitest.tgz' }, + { name: '@vitejs/devtools-oxc', dir: 'packages/oxc', out: 'vitejs-devtools-oxc.tgz' }, ] const skipBuild = process.argv.includes('--no-build') @@ -56,6 +58,7 @@ mkdirSync(tarballDir, { recursive: true }) // Pack each package. `--ignore-scripts` skips the `prepack` rebuild since the // monorepo build above already produced fresh dist output. for (const { name, dir } of PACKAGES) { + console.log(`\nPacking ${name}...`) run(`pnpm pack --config.ignore-scripts=true --pack-destination "${tarballDir}"`, join(repoRoot, dir)) }