From 2185faffb5e5234b150e9ec4fb1723826593677f Mon Sep 17 00:00:00 2001 From: Markus Dulghier Date: Fri, 1 May 2026 08:00:05 +0200 Subject: [PATCH] Add configurable Vite runner selection --- README.md | 26 +++++---- package.json | 10 +++- pnpm-lock.yaml | 73 +++++++++++++++----------- skills/devtree-set-up-devtree/SKILL.md | 11 +++- src/cli.ts | 33 ++++++++++-- src/command-builder.test.ts | 14 ++++- src/command-builder.ts | 24 ++++++++- src/config-command.test.ts | 13 +++++ src/config.ts | 3 ++ src/vite.ts | 4 +- 10 files changed, 159 insertions(+), 52 deletions(-) diff --git a/README.md b/README.md index a38cf4c..4159ac9 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Devtree -Run the same Vite+ app in multiple git worktrees without local-dev collisions. +Run the same Vite app in multiple git worktrees without local-dev collisions. Devtree gives each worktree its own public URL, managed env block, scoped dependency names, setup hooks, and garbage collection for orphaned local resources. @@ -8,37 +8,37 @@ Devtree gives each worktree its own public URL, managed env block, scoped depend ### 1. Install -Devtree assumes your app already uses `vite-plus`. It is a required peer dependency, but this README does not install it for you. +Devtree can launch either `vite-plus` or plain `vite`. It defaults to `vite-plus` for compatibility with existing projects. Install Devtree itself: ```bash -vp add -D devtree +pnpm add -D devtree ``` Dependencies you may also need: -- `vite-plus` - required. Your app should already have it installed and be using it. +- `vite-plus` or `vite` - required. Devtree runs `vp dev` by default, or `vite dev` when `dev_server.runner` is `"vite"`. - `portless` - required unless you disable it with `portless.enabled: false` or `PORTLESS=0`. The `portless` command must be available on `PATH`. - `tailscale` - optional, only needed when `tailscale.enabled` is `true`. - `varlock` and `@varlock/vite-integration` - required only when `env.provider` is set to `"varlock"`. -Install `portless` in the repo so `vp devtree ...` can find it: +Install `portless` in the repo so `devtree` can find it: ```bash -vp add -D portless +pnpm add -D portless ``` If you want `portless` available outside pnpm-managed scripts too, install it globally: ```bash -vp add -g portless +pnpm add -g portless ``` If you use `varlock`, install both pieces together: ```bash -vp add -D varlock @varlock/vite-integration +pnpm add -D varlock @varlock/vite-integration ``` That gives you the `varlock` CLI plus the Vite integration Devtree expects. @@ -55,6 +55,9 @@ import { define_devtree_config } from "devtree"; export default define_devtree_config({ app_name: "my-app", + dev_server: { + runner: "vite-plus", + }, tailscale: { enabled: true, }, @@ -78,12 +81,16 @@ export default define_devtree_config({ By default Devtree manages a block inside `.env.local`. Set `env.file_path` if you want a different file. +Set `dev_server.runner` to `"vite"` if the app uses plain Vite and should launch with `vite dev`. + If you enable `tailscale`, Devtree checks for the `tailscale` CLI, reads the machine's MagicDNS hostname, starts Vite on `0.0.0.0`, and adds that hostname to Vite's allowed hosts so the dev server can be reached over Tailscale. ### 3. Register the Vite plugin +Use your app's existing config helper. Plain Vite apps import from `vite`; VitePlus apps can keep importing from `vite-plus`. + ```ts -import { defineConfig } from "vite-plus"; +import { defineConfig } from "vite"; import { devtree_vite_plugins } from "devtree/vite"; import devtree_config from "./devtree.config.ts"; @@ -135,6 +142,7 @@ Examples: ```bash pnpm devtree config tailscale.enabled true +pnpm devtree config dev_server.runner vite pnpm devtree config portless.https "inherit" pnpm devtree config namespace personal-dev pnpm devtree config tailscale.enabled diff --git a/package.json b/package.json index 03250bb..acc5c5d 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@mdulghier/devtree", "version": "0.1.6", - "description": "Worktree-aware multi-instance dev orchestration for Vite+ apps.", + "description": "Worktree-aware multi-instance dev orchestration for Vite apps.", "keywords": [ "devtree", "portless", @@ -60,10 +60,12 @@ "@types/node": "^24.5.2", "@tanstack/intent": "^0.0.23", "typescript": "^5.7.2", + "vite": "8.0.1", "vite-plus": "latest" }, "peerDependencies": { "@varlock/vite-integration": "*", + "vite": "*", "varlock": "*", "vite-plus": "*" }, @@ -71,8 +73,14 @@ "@varlock/vite-integration": { "optional": true }, + "vite": { + "optional": true + }, "varlock": { "optional": true + }, + "vite-plus": { + "optional": true } }, "engines": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9bc3345..d895d49 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,7 +10,7 @@ importers: dependencies: '@varlock/vite-integration': specifier: '*' - version: 0.2.6(varlock@0.6.1)(vite@8.0.1(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@24.12.0)(tsx@4.21.0)(yaml@2.8.3)) + version: 0.2.6(varlock@0.6.1)(vite@8.0.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@24.12.0)(tsx@4.21.0)(yaml@2.8.3)) dotenv: specifier: ^17.3.1 version: 17.3.1 @@ -30,20 +30,23 @@ importers: typescript: specifier: ^5.7.2 version: 5.9.3 + vite: + specifier: 8.0.1 + version: 8.0.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@24.12.0)(tsx@4.21.0)(yaml@2.8.3) vite-plus: specifier: latest - version: 0.1.16(@types/node@24.12.0)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.1(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@24.12.0)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) + version: 0.1.16(@types/node@24.12.0)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@24.12.0)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) packages: - '@emnapi/core@1.9.1': - resolution: {integrity: sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA==} + '@emnapi/core@1.10.0': + resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} - '@emnapi/runtime@1.9.1': - resolution: {integrity: sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA==} + '@emnapi/runtime@1.10.0': + resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} - '@emnapi/wasi-threads@1.2.0': - resolution: {integrity: sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==} + '@emnapi/wasi-threads@1.2.1': + resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} '@esbuild/aix-ppc64@0.27.4': resolution: {integrity: sha512-cQPwL2mp2nSmHHJlCyoXgHGhbEPMrEEU5xhkcy3Hs/O7nGZqEpZ2sUtLaL9MORLtDfRvVl2/3PAuEkYZH0Ty8Q==} @@ -201,8 +204,8 @@ packages: cpu: [x64] os: [win32] - '@napi-rs/wasm-runtime@1.1.3': - resolution: {integrity: sha512-xK9sGVbJWYb08+mTJt3/YV24WxvxpXcXtP6B172paPZ+Ts69Re9dAr7lKwJoeIx8OoeuimEiRZ7umkiUVClmmQ==} + '@napi-rs/wasm-runtime@1.1.4': + resolution: {integrity: sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==} peerDependencies: '@emnapi/core': ^1.7.1 '@emnapi/runtime': ^1.7.1 @@ -916,6 +919,10 @@ packages: resolution: {integrity: sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==} engines: {node: '>=14.19.0'} + postcss@8.5.13: + resolution: {integrity: sha512-qif0+jGGZoLWdHey3UFHHWP0H7Gbmsk8T5VEqyYFbWqPr1XqvLGBbk/sl8V5exGmcYJklJOhOQq1pV9IcsiFag==} + engines: {node: ^10 || ^12 || >=14} + postcss@8.5.9: resolution: {integrity: sha512-7a70Nsot+EMX9fFU3064K/kdHWZqGVY+BADLyXc8Dfv+mTLLVl6JzJpPaCZ2kQL9gIJvKXSLMHhqdRRjwQeFtw==} engines: {node: ^10 || ^12 || >=14} @@ -1046,18 +1053,18 @@ packages: snapshots: - '@emnapi/core@1.9.1': + '@emnapi/core@1.10.0': dependencies: - '@emnapi/wasi-threads': 1.2.0 + '@emnapi/wasi-threads': 1.2.1 tslib: 2.8.1 optional: true - '@emnapi/runtime@1.9.1': + '@emnapi/runtime@1.10.0': dependencies: tslib: 2.8.1 optional: true - '@emnapi/wasi-threads@1.2.0': + '@emnapi/wasi-threads@1.2.1': dependencies: tslib: 2.8.1 optional: true @@ -1140,10 +1147,10 @@ snapshots: '@esbuild/win32-x64@0.27.4': optional: true - '@napi-rs/wasm-runtime@1.1.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)': + '@napi-rs/wasm-runtime@1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': dependencies: - '@emnapi/core': 1.9.1 - '@emnapi/runtime': 1.9.1 + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 '@tybys/wasm-util': 0.10.1 optional: true @@ -1323,9 +1330,9 @@ snapshots: '@rolldown/binding-openharmony-arm64@1.0.0-rc.10': optional: true - '@rolldown/binding-wasm32-wasi@1.0.0-rc.10(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)': + '@rolldown/binding-wasm32-wasi@1.0.0-rc.10(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': dependencies: - '@napi-rs/wasm-runtime': 1.1.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1) + '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) transitivePeerDependencies: - '@emnapi/core' - '@emnapi/runtime' @@ -1362,10 +1369,10 @@ snapshots: dependencies: undici-types: 7.16.0 - '@varlock/vite-integration@0.2.6(varlock@0.6.1)(vite@8.0.1(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@24.12.0)(tsx@4.21.0)(yaml@2.8.3))': + '@varlock/vite-integration@0.2.6(varlock@0.6.1)(vite@8.0.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@24.12.0)(tsx@4.21.0)(yaml@2.8.3))': dependencies: varlock: 0.6.1 - vite: 8.0.1(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@24.12.0)(tsx@4.21.0)(yaml@2.8.3) + vite: 8.0.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@24.12.0)(tsx@4.21.0)(yaml@2.8.3) '@voidzero-dev/vite-plus-core@0.1.16(@types/node@24.12.0)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)': dependencies: @@ -1398,7 +1405,7 @@ snapshots: '@voidzero-dev/vite-plus-linux-x64-musl@0.1.16': optional: true - '@voidzero-dev/vite-plus-test@0.1.16(@types/node@24.12.0)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.1(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@24.12.0)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3)': + '@voidzero-dev/vite-plus-test@0.1.16(@types/node@24.12.0)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@24.12.0)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3)': dependencies: '@standard-schema/spec': 1.1.0 '@types/chai': 5.2.3 @@ -1412,7 +1419,7 @@ snapshots: tinybench: 2.9.0 tinyexec: 1.1.1 tinyglobby: 0.2.16 - vite: 8.0.1(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@24.12.0)(tsx@4.21.0)(yaml@2.8.3) + vite: 8.0.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@24.12.0)(tsx@4.21.0)(yaml@2.8.3) ws: 8.20.0 optionalDependencies: '@types/node': 24.12.0 @@ -1614,6 +1621,12 @@ snapshots: pngjs@7.0.0: {} + postcss@8.5.13: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + postcss@8.5.9: dependencies: nanoid: 3.3.11 @@ -1622,7 +1635,7 @@ snapshots: resolve-pkg-maps@1.0.0: {} - rolldown@1.0.0-rc.10(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1): + rolldown@1.0.0-rc.10(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0): dependencies: '@oxc-project/types': 0.120.0 '@rolldown/pluginutils': 1.0.0-rc.10 @@ -1639,7 +1652,7 @@ snapshots: '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.10 '@rolldown/binding-linux-x64-musl': 1.0.0-rc.10 '@rolldown/binding-openharmony-arm64': 1.0.0-rc.10 - '@rolldown/binding-wasm32-wasi': 1.0.0-rc.10(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1) + '@rolldown/binding-wasm32-wasi': 1.0.0-rc.10(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.10 '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.10 transitivePeerDependencies: @@ -1685,11 +1698,11 @@ snapshots: varlock@0.6.1: {} - vite-plus@0.1.16(@types/node@24.12.0)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.1(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@24.12.0)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3): + vite-plus@0.1.16(@types/node@24.12.0)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@24.12.0)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3): dependencies: '@oxc-project/types': 0.123.0 '@voidzero-dev/vite-plus-core': 0.1.16(@types/node@24.12.0)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) - '@voidzero-dev/vite-plus-test': 0.1.16(@types/node@24.12.0)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.1(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@24.12.0)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) + '@voidzero-dev/vite-plus-test': 0.1.16(@types/node@24.12.0)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@24.12.0)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) oxfmt: 0.43.0 oxlint: 1.58.0(oxlint-tsgolint@0.20.0) oxlint-tsgolint: 0.20.0 @@ -1730,12 +1743,12 @@ snapshots: - vite - yaml - vite@8.0.1(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@24.12.0)(tsx@4.21.0)(yaml@2.8.3): + vite@8.0.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@24.12.0)(tsx@4.21.0)(yaml@2.8.3): dependencies: lightningcss: 1.32.0 picomatch: 4.0.4 - postcss: 8.5.9 - rolldown: 1.0.0-rc.10(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1) + postcss: 8.5.13 + rolldown: 1.0.0-rc.10(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) tinyglobby: 0.2.16 optionalDependencies: '@types/node': 24.12.0 diff --git a/skills/devtree-set-up-devtree/SKILL.md b/skills/devtree-set-up-devtree/SKILL.md index c926724..f0b278e 100644 --- a/skills/devtree-set-up-devtree/SKILL.md +++ b/skills/devtree-set-up-devtree/SKILL.md @@ -1,7 +1,7 @@ --- name: devtree-set-up-devtree description: > - Set up devtree in a Vite+ repository: install `devtree`, create + Set up devtree in a Vite repository: install `devtree`, create `devtree.config.ts`, define `env.entries`, choose `dotenv` or `varlock`, register `devtree_vite_plugins`, and configure optional `dependencies` and `hooks`. Load this when an agent needs to bootstrap worktree-aware @@ -22,17 +22,22 @@ sources: ## Setup -Install `devtree` and register both the config file and the Vite plugin. +Install `devtree` and register both the config file and the Vite plugin. Devtree defaults to `vite-plus`; set `dev_server.runner` to `vite` for plain Vite apps. ```bash pnpm add -D devtree vite-plus ``` +For plain Vite apps, install `vite` instead and set `dev_server.runner` to `'vite'`. + ```ts import { define_devtree_config } from 'devtree' export default define_devtree_config({ app_name: 'my-app', + dev_server: { + runner: 'vite-plus', + }, env: { provider: 'dotenv', entries: ({ instance }) => [ @@ -62,6 +67,8 @@ export default defineConfig({ }) ``` +Plain Vite apps can import `defineConfig` from `vite` instead. + ```json { "scripts": { diff --git a/src/cli.ts b/src/cli.ts index 6e25a16..4d80252 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -10,7 +10,11 @@ import type { } from "./config.ts"; import { load_devtree_config } from "./config.ts"; import { format_config_value, get_config_value, set_config_value } from "./config-command.ts"; -import { build_development_command } from "./command-builder.ts"; +import { + build_development_command, + get_dev_server_command, + type Dev_server_runner, +} from "./command-builder.ts"; import { ensure_env_file, get_env_file_status_message } from "./env-file.ts"; import { run_gc } from "./gc.ts"; import { create_devtree_instance, type Devtree_instance } from "./instance.ts"; @@ -320,7 +324,7 @@ function ensure_portless_ready(loaded_config: Loaded_devtree_config, should_fix if (list_result.status !== 0) { throw new Error( - "Portless is installed, but the proxy is not reachable. Run `vp run devtree doctor --fix`.", + "Portless is installed, but the proxy is not reachable. Run `pnpm devtree doctor --fix`.", ); } @@ -334,10 +338,22 @@ function resolve_require_from_root(repo_root: string) { return createRequire(resolve(repo_root, "package.json")); } +function get_dev_server_runner(loaded_config: Loaded_devtree_config): Dev_server_runner { + const runner = loaded_config.config.dev_server?.runner as string | undefined; + + if (runner === undefined || runner === "vite-plus" || runner === "vite") { + return runner ?? "vite-plus"; + } + + throw new Error('dev_server.runner must be "vite-plus" or "vite".'); +} + function run_doctor(loaded_config: Loaded_devtree_config, fix = false) { const issues: string[] = []; const compose_dependencies = get_compose_dependencies(loaded_config); const tailscale = resolve_tailscale(loaded_config.config); + const dev_server_runner = get_dev_server_runner(loaded_config); + const dev_server_command = get_dev_server_command(dev_server_runner); console.log(`[pass] config ${loaded_config.config_path}`); @@ -347,6 +363,12 @@ function run_doctor(loaded_config: Loaded_devtree_config, fix = false) { issues.push("git is not available on PATH"); } + if (command_exists(dev_server_command)) { + console.log(`[pass] dev server runner ${dev_server_command} available`); + } else { + issues.push(`dev server runner ${dev_server_command} is not available on PATH`); + } + if (loaded_config.config.portless?.enabled === false || process.env.PORTLESS === "0") { console.log("[skip] portless disabled"); } else if (!command_exists("portless")) { @@ -501,7 +523,7 @@ async function main() { return; } - throw new Error("Usage: vp run devtree env "); + throw new Error("Usage: devtree env "); } if (command_name === "gc") { @@ -534,7 +556,7 @@ async function main() { if (runtime_state.tailscale.host) { console.log(`Tailscale hostname available to Vite: ${runtime_state.tailscale.host}`); } - console.log("Run `vp run devtree dev` to launch the worktree-scoped dev server."); + console.log("Run `pnpm devtree dev` to launch the worktree-scoped dev server."); return; } @@ -542,7 +564,7 @@ async function main() { const deps_subcommand = argv[1]; if (deps_subcommand !== "start" && deps_subcommand !== "stop" && deps_subcommand !== "logs") { - throw new Error("Usage: vp run devtree deps "); + throw new Error("Usage: devtree deps "); } for (const dependency of loaded_config.config.dependencies ?? []) { @@ -583,6 +605,7 @@ async function main() { app_name: runtime_state.instance.app_name, extra_args, portless_enabled: runtime_state.instance.portless_enabled, + runner: get_dev_server_runner(loaded_config), vite_host: runtime_state.tailscale.host ? "0.0.0.0" : undefined, use_varlock: loaded_config.config.env.provider === "varlock", }); diff --git a/src/command-builder.test.ts b/src/command-builder.test.ts index d58308f..8311a26 100644 --- a/src/command-builder.test.ts +++ b/src/command-builder.test.ts @@ -3,7 +3,7 @@ import { describe, expect, test } from "vite-plus/test"; import { build_development_command } from "./command-builder.ts"; describe("build_development_command", () => { - test("wraps vite with portless by default", () => { + test("wraps vite-plus with portless by default", () => { expect( build_development_command({ app_name: "demo-app", @@ -50,4 +50,16 @@ describe("build_development_command", () => { }), ).toEqual(["vp", "dev", "--host", "0.0.0.0", "--clearScreen", "false"]); }); + + test("uses vite when the vite runner is selected", () => { + expect( + build_development_command({ + app_name: "demo-app", + extra_args: [], + portless_enabled: false, + runner: "vite", + use_varlock: false, + }), + ).toEqual(["vite", "dev", "--host", "127.0.0.1", "--clearScreen", "false"]); + }); }); diff --git a/src/command-builder.ts b/src/command-builder.ts index 90240ec..b385bb0 100644 --- a/src/command-builder.ts +++ b/src/command-builder.ts @@ -2,8 +2,26 @@ export function strip_passthrough_delimiter(args: string[]) { return args[0] === "--" ? args.slice(1) : args; } -export function build_vite_dev_command(extra_args: string[], host = "127.0.0.1") { - return ["vp", "dev", "--host", host, "--clearScreen", "false", ...extra_args]; +export type Dev_server_runner = "vite-plus" | "vite"; + +export function get_dev_server_command(runner: Dev_server_runner) { + return runner === "vite" ? "vite" : "vp"; +} + +export function build_vite_dev_command( + extra_args: string[], + host = "127.0.0.1", + runner: Dev_server_runner = "vite-plus", +) { + return [ + get_dev_server_command(runner), + "dev", + "--host", + host, + "--clearScreen", + "false", + ...extra_args, + ]; } export function build_portless_command(app_name: string, command_parts: string[]) { @@ -18,12 +36,14 @@ export function build_development_command(options: { app_name: string; extra_args: string[]; portless_enabled: boolean; + runner?: Dev_server_runner; vite_host?: string; use_varlock: boolean; }) { let command_parts = build_vite_dev_command( strip_passthrough_delimiter(options.extra_args), options.vite_host, + options.runner, ); if (options.portless_enabled) { diff --git a/src/config-command.test.ts b/src/config-command.test.ts index bcf44a5..c771e75 100644 --- a/src/config-command.test.ts +++ b/src/config-command.test.ts @@ -35,6 +35,12 @@ describe("update_config_text", () => { 'namespace: "personal dev"', ); }); + + test("creates the dev server runner config", () => { + expect(update_config_text(config_file_text, "dev_server.runner", "vite")).toContain( + 'dev_server: {\n runner: "vite"\n }', + ); + }); }); describe("get_config_value", () => { @@ -43,6 +49,9 @@ describe("get_config_value", () => { tailscale: { enabled: true, }, + dev_server: { + runner: "vite", + }, env: { provider: "dotenv", entries: () => [], @@ -56,6 +65,10 @@ describe("get_config_value", () => { test("returns undefined when a key is missing", () => { expect(get_config_value(config, "portless.enabled")).toBeUndefined(); }); + + test("reads the dev server runner", () => { + expect(get_config_value(config, "dev_server.runner")).toBe("vite"); + }); }); describe("format_config_value", () => { diff --git a/src/config.ts b/src/config.ts index aedfd0c..e6147a6 100644 --- a/src/config.ts +++ b/src/config.ts @@ -64,6 +64,9 @@ export type Devtree_config = { https?: boolean | "inherit"; bootstrap?: "best-effort" | "manual"; }; + dev_server?: { + runner?: "vite-plus" | "vite"; + }; env: { provider: "dotenv" | "varlock"; file_path?: string; diff --git a/src/vite.ts b/src/vite.ts index cce6782..491de36 100644 --- a/src/vite.ts +++ b/src/vite.ts @@ -1,4 +1,4 @@ -import type { Plugin, UserConfig } from "vite-plus"; +import type { Plugin, UserConfig } from "vite"; import type { Devtree_config } from "./config.ts"; @@ -50,7 +50,7 @@ function create_core_devtree_plugin(): Plugin { return; } - console.warn("[devtree] Run `vp run devtree dev` for isolated multi-instance development."); + console.warn("[devtree] Run `pnpm devtree dev` for isolated multi-instance development."); }, }; }