Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/oxc/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"devtools-oxc": "./bin/devtools-oxc.mjs"
},
"files": [
"bin",
"dist"
],
"scripts": {
Expand Down
5 changes: 5 additions & 0 deletions playgrounds/production/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules
dist
.tarballs
pnpm-lock.yaml
*.local
60 changes: 60 additions & 0 deletions playgrounds/production/README.md
Original file line number Diff line number Diff line change
@@ -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
12 changes: 12 additions & 0 deletions playgrounds/production/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite DevTools — Production Playground</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
23 changes: 23 additions & 0 deletions playgrounds/production/package.json
Original file line number Diff line number Diff line change
@@ -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"

Check failure on line 17 in playgrounds/production/package.json

View workflow job for this annotation

GitHub Actions / lint

Expect to use catalog instead of plain specifier, got "^3.5.39" for package "vue"
},
"devDependencies": {
"@vitejs/plugin-vue": "^6.0.7",

Check failure on line 20 in playgrounds/production/package.json

View workflow job for this annotation

GitHub Actions / lint

Expect to use catalog instead of plain specifier, got "^6.0.7" for package "@vitejs/plugin-vue"
"vite": "^8.1.4"

Check failure on line 21 in playgrounds/production/package.json

View workflow job for this annotation

GitHub Actions / lint

Expect to use catalog instead of plain specifier, got "^8.1.4" for package "vite"
}
}
27 changes: 27 additions & 0 deletions playgrounds/production/pnpm-workspace.yaml
Original file line number Diff line number Diff line change
@@ -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
78 changes: 78 additions & 0 deletions playgrounds/production/scripts/pack-local.mjs
Original file line number Diff line number Diff line change
@@ -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 `<name>-<version>.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}-<version>.tgz)`)
renameSync(join(tarballDir, match), join(tarballDir, out))
console.log(`✓ ${name} -> .tarballs/${out}`)
}

console.log('\nDone. Now run: pnpm install --no-frozen-lockfile')
35 changes: 35 additions & 0 deletions playgrounds/production/src/App.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<script setup lang="ts">
import { ref } from 'vue'

const count = ref(0)
</script>

<template>
<main>
<h1>Vite DevTools — Production Playground</h1>
<p>
This app installs <code>@vitejs/devtools</code> from the local built dist,
inside a standalone pnpm workspace, to test the real user install
experience.
</p>
<button type="button" @click="count++">
count is {{ count }}
</button>
</main>
</template>

<style scoped>
main {
max-width: 42rem;
margin: 4rem auto;
padding: 0 1rem;
font-family: system-ui, sans-serif;
line-height: 1.6;
}
button {
padding: 0.5rem 1rem;
border-radius: 0.5rem;
border: 1px solid currentColor;
cursor: pointer;
}
</style>
8 changes: 8 additions & 0 deletions playgrounds/production/src/env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/// <reference types="vite/client" />

declare module '*.vue' {
import type { DefineComponent } from 'vue'

const component: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>
export default component
}
5 changes: 5 additions & 0 deletions playgrounds/production/src/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { createApp } from 'vue'
import App from './App.vue'
import './style.css'

createApp(App).mount('#app')
2 changes: 2 additions & 0 deletions playgrounds/production/src/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
:root { color-scheme: light dark; }
body { margin: 0; }
17 changes: 17 additions & 0 deletions playgrounds/production/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "Bundler",
"strict": true,

Check failure on line 6 in playgrounds/production/tsconfig.json

View workflow job for this annotation

GitHub Actions / lint

Expected object keys to be in specified order. 'strict' should be after 'resolveJsonModule'
"jsx": "preserve",

Check failure on line 7 in playgrounds/production/tsconfig.json

View workflow job for this annotation

GitHub Actions / lint

Expected object keys to be in specified order. 'jsx' should be before 'module'
"resolveJsonModule": true,
"isolatedModules": true,

Check failure on line 9 in playgrounds/production/tsconfig.json

View workflow job for this annotation

GitHub Actions / lint

Expected object keys to be in specified order. 'isolatedModules' should be after 'esModuleInterop'
"esModuleInterop": true,
"lib": ["ESNext", "DOM", "DOM.Iterable"],

Check failure on line 11 in playgrounds/production/tsconfig.json

View workflow job for this annotation

GitHub Actions / lint

Expected object keys to be in specified order. 'lib' should be before 'module'
"skipLibCheck": true,
"noEmit": true,

Check failure on line 13 in playgrounds/production/tsconfig.json

View workflow job for this annotation

GitHub Actions / lint

Expected object keys to be in specified order. 'noEmit' should be before 'esModuleInterop'
"types": ["vite/client"]

Check failure on line 14 in playgrounds/production/tsconfig.json

View workflow job for this annotation

GitHub Actions / lint

Expected object keys to be in specified order. 'types' should be before 'esModuleInterop'
},
"include": ["src", "vite.config.ts", "env.d.ts"]
}
20 changes: 20 additions & 0 deletions playgrounds/production/vite.config.ts
Original file line number Diff line number Diff line change
@@ -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: {},
},
},
})
Loading