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/.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..a01b2017d --- /dev/null +++ b/playgrounds/production/pnpm-workspace.yaml @@ -0,0 +1,27 @@ +# 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' + '@vitejs/devtools-oxc': 'file:.tarballs/vitejs-devtools-oxc.tgz' + +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 new file mode 100644 index 000000000..b6b25591d --- /dev/null +++ b/playgrounds/production/scripts/pack-local.mjs @@ -0,0 +1,78 @@ +// @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 process from 'node:process' +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' }, + { name: '@vitejs/devtools-oxc', dir: 'packages/oxc', out: 'vitejs-devtools-oxc.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) { + console.log(`\nPacking ${name}...`) + 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: {}, + }, + }, +})