diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts index dcbb3abd79..f531d60c2c 100644 --- a/docs/.vitepress/config.mts +++ b/docs/.vitepress/config.mts @@ -71,7 +71,7 @@ export default extendConfig( { text: 'Test', link: '/config/test' }, { text: 'Lint', link: '/config/lint' }, { text: 'Format', link: '/config/format' }, - { text: 'Task Runner', link: '/config/task' }, + { text: 'Task Runner', link: '/vite/guide/task/config' }, { text: 'Package Manager', link: '/config/package-manager' }, ], }, @@ -327,40 +327,20 @@ export default extendConfig( link: 'task/getting-started', }, { - text: 'Features', - link: '/guide/task/features', - }, - { - text: 'CLI', - link: '/guide/task/cli', - }, - { - text: 'Migration from Turborepo', - link: '/guide/format/migration-from-turborepo', - }, - { - text: 'Migration from Nx', - link: '/guide/format/migration-from-nx', - }, - { - text: 'Migration from Lerna', - link: '/guide/format/migration-from-lerna', + text: 'Running Tasks', + link: 'task/running-tasks', }, { - text: 'Migration from pnpm', - link: '/guide/format/migration-from-pnpm', + text: 'Caching', + link: 'task/caching', }, { - text: 'Migration from yarn', - link: '/guide/format/migration-from-yarn', - }, - { - text: 'Migration from npm', - link: '/guide/format/migration-from-npm', + text: 'CLI', + link: 'task/cli', }, { - text: 'Migration from bun', - link: '/guide/format/migration-from-bun', + text: 'Config', + link: 'task/config', }, ], }, @@ -604,6 +584,15 @@ export default extendConfig( }, ], }, + { + text: 'Task Runner', + items: [ + { + text: 'Configuring Task Runner', + link: '/vite/guide/task/config', + }, + ], + }, ], '/apis/': [ { diff --git a/docs/vite/guide/task/caching.md b/docs/vite/guide/task/caching.md new file mode 100644 index 0000000000..3f4d698ddc --- /dev/null +++ b/docs/vite/guide/task/caching.md @@ -0,0 +1,115 @@ +# Caching + +## How It Works {#how-caching-works} + +When a task runs successfully (exit code 0), its terminal output (stdout/stderr) is saved. On the next run, the task runner checks if anything changed: + +1. **Arguments** — did the [additional arguments](./cli#additional-arguments) passed to the task change? +2. **Environment variables** — did any [fingerprinted env vars](./config#envs) change? +3. **Input files** — did any file that the command reads change? + +If everything matches, the cached output is replayed instantly — the command never actually runs. + +::: info +Currently, only terminal output is cached and replayed. Output files (e.g., `dist/`) are not cached — if you delete them, use `--no-cache` to force a re-run. Output file caching is planned for a future release. +::: + +When a cache miss occurs, the task runner tells you exactly why: + +``` +$ vp lint ✗ cache miss: 'src/utils.ts' modified, executing +$ vp build ✗ cache miss: envs changed, executing +$ vp test ✗ cache miss: args changed, executing +``` + +## When Is Caching Enabled? {#when-is-caching-enabled} + +A command run by `vp run` is either a **task** (has an entry in `vite.config.ts`) or a **script** (only exists in `package.json` with no corresponding task entry). By default, **tasks are cached and scripts are not.** Three layers control whether caching is on: + +### 1. Per-task `cache: false` (highest priority, tasks only) + +A task can set [`cache: false`](./config#cache) to opt out. This cannot be overridden by `--cache` or `run.cache` — if a task says no caching, it means no caching. + +### 2. CLI flags + +`--no-cache` disables caching for everything. `--cache` enables caching for both tasks and scripts — equivalent to setting [`run.cache: true`](./config#run-cache) for that invocation. + +### 3. Workspace config + +The [`run.cache`](./config#run-cache) option in your root `vite.config.ts` controls the default for each category: + +| Setting | Default | Effect | +| --------------- | ------- | ------------------------------------- | +| `cache.tasks` | `true` | Cache commands that have a task entry | +| `cache.scripts` | `false` | Cache plain `package.json` scripts | + +Use `--cache` to quickly enable script caching, or set `run.cache.scripts: true` in config to enable it permanently. + +## Automatic File Tracking {#automatic-file-tracking} + +By default, the task runner tracks which files each command reads during execution. When `vp build` runs, it records which files the process opens — your `.ts` source files, `vite.config.ts`, `package.json`, etc. — and records their content hashes. On the next run, it re-checks those hashes to determine if anything changed. + +This means caching works out of the box for most commands without any configuration. The tracker also records: + +- **File non-existence** — if a command probes for a file that doesn't exist (e.g., `utils.ts` during module resolution), creating that file later correctly invalidates the cache. +- **Directory listings** — if a command scans a directory (e.g., a test runner looking for `*.test.ts`), adding or removing files in that directory invalidates the cache. + +### Over-fingerprinting {#over-fingerprinting} + +Automatic tracking can sometimes include more files than necessary, causing unnecessary cache misses: + +- **Tool cache files** — some tools maintain their own cache (e.g., TypeScript's `.tsbuildinfo`, Cargo's `target/`). These files may change between runs even when your source code hasn't, causing unnecessary cache invalidation. +- **Directory listings** — when a command scans a directory (e.g., globbing for `**/*.js`), the task runner sees the directory read but not the glob pattern. Any file added or removed in that directory — even unrelated ones — invalidates the cache. + +Use the [`inputs`](./config#inputs) option to exclude noisy files or replace automatic tracking with explicit file patterns: + +```ts +tasks: { + build: { + command: 'tsc', + inputs: [{ auto: true }, '!**/*.tsbuildinfo'], + }, +} +``` + +## Environment Variables {#environment-variables} + +By default, tasks run in a clean environment — only a small set of common variables (like `PATH`, `HOME`, `CI`) are passed through. Other environment variables are neither visible to the task nor included in the cache fingerprint. + +To make a variable affect caching, add it to [`envs`](./config#envs). Changing its value invalidates the cache: + +```ts +tasks: { + build: { + command: 'webpack --mode production', + envs: ['NODE_ENV'], + }, +} +``` + +To pass a variable to the task **without** affecting the cache, use [`passThroughEnvs`](./config#pass-through-envs). This is useful for variables like `CI` or `GITHUB_ACTIONS` that should be available but shouldn't trigger a rebuild when they change. + +See the [config reference](./config#envs) for details on wildcard patterns and the full list of automatically passed-through variables. + +## Cache Sharing {#cache-sharing} + +The cache is content-based — if two tasks run the same command with the same inputs, they share the cache entry. This happens naturally when multiple tasks include a common step, either as standalone tasks or as parts of [compound commands](./running-tasks#compound-commands): + +```json [package.json] +{ + "scripts": { + "check": "vp lint && vp build", + "release": "vp lint && deploy-script" + } +} +``` + +With caching enabled (e.g. `--cache` or [`run.cache.scripts: true`](./config#run-cache)), running `check` first means the `vp lint` step in `release` is an instant cache hit, since both run the same command against the same files. + +## Clearing the Cache {#clearing-the-cache} + +```bash +vp cache clean +``` + +This deletes the entire cache directory. Tasks will run fresh on the next invocation. diff --git a/docs/vite/guide/task/cli.md b/docs/vite/guide/task/cli.md new file mode 100644 index 0000000000..613db2eda7 --- /dev/null +++ b/docs/vite/guide/task/cli.md @@ -0,0 +1,73 @@ +# CLI Reference + +## `vp run` {#vp-run} + +Run tasks defined in `vite.config.ts` or `package.json` scripts. + +```bash +vp run [options] [task] [additional-args] +``` + +If `task` is omitted, an interactive selector is shown: + +``` +Select a task (↑/↓, Enter to run, Esc to clear): + + › build: vp build + lint: vp lint +``` + +### Task Argument {#task-argument} + +The `[task]` argument can be: + +- `build` — runs the `build` task in the current package +- `@my/app#build` — runs the `build` task in a specific package + +### Options {#options} + +| Flag | Short | Description | +| --------------------- | ----- | ---------------------------------------------------------- | +| `--recursive` | `-r` | Run in all workspace packages, in topological order | +| `--transitive` | `-t` | Run in the current package and its transitive dependencies | +| `--workspace-root` | `-w` | Run in the workspace root package | +| `--filter ` | `-F` | Select packages by name, directory, or glob (repeatable) | +| `--cache` | — | Enable caching for all tasks and scripts | +| `--no-cache` | — | Disable caching entirely | +| `--ignore-depends-on` | — | Skip explicit `dependsOn` dependencies | +| `--verbose` | `-v` | Show detailed execution summary | +| `--last-details` | — | Display the summary from the last run | + +### Additional Arguments {#additional-arguments} + +Arguments after the task name are passed through to the task command: + +```bash +vp run test --reporter verbose +``` + +### Filter Patterns {#filter-patterns} + +| Pattern | Description | +| ------------------ | ------------------------------------------ | +| `@my/app` | Exact package name | +| `@my/*` | Glob matching | +| `./packages/app` | By directory | +| `{./packages/app}` | By directory (braced form) | +| `@my/app...` | Package and its dependencies | +| `...@my/core` | Package and its dependents | +| `@my/app^...` | Dependencies only (exclude package itself) | +| `...^@my/core` | Dependents only (exclude package itself) | +| `!@my/utils` | Exclude a package | + +Multiple `--filter` flags are combined as a union. Exclusion filters (`!`) are applied after all inclusions. + +## `vp cache clean` {#vp-cache-clean} + +Delete all cached task results: + +```bash +vp cache clean +``` + +Tasks will run fresh on the next invocation. diff --git a/docs/vite/guide/task/config.md b/docs/vite/guide/task/config.md new file mode 100644 index 0000000000..02070916f7 --- /dev/null +++ b/docs/vite/guide/task/config.md @@ -0,0 +1,229 @@ +# Task Runner Config + +The task runner is configured under the `run` field in your `vite.config.ts`: + +```ts [vite.config.ts] +import { defineConfig } from 'vite-plus'; + +export default defineConfig({ + run: { + cache: { + /* ... */ + }, + tasks: { + /* ... */ + }, + }, +}); +``` + +## `run.cache` {#run-cache} + +- **Type:** `boolean | { scripts?: boolean, tasks?: boolean }` +- **Default:** `{ scripts: false, tasks: true }` + +Global cache settings. Controls whether task results are cached and replayed on subsequent runs. + +```ts [vite.config.ts] +export default defineConfig({ + run: { + cache: { + scripts: true, // Cache package.json scripts (default: false) + tasks: true, // Cache task definitions (default: true) + }, + }, +}); +``` + +Shorthands: `cache: true` enables both, `cache: false` disables both. + +Tasks defined in `vite.config.ts` are cached by default. Plain `package.json` scripts (without a matching task entry) are **not** cached by default. See [When Is Caching Enabled?](./caching#when-is-caching-enabled) for the full resolution order including CLI overrides. + +## `run.tasks` {#run-tasks} + +- **Type:** `Record` + +Defines named tasks. Each key is a task name that can be run with `vp run `. + +```ts [vite.config.ts] +export default defineConfig({ + run: { + tasks: { + build: { + command: 'vp build', + dependsOn: ['lint'], + }, + lint: { + command: 'vp lint', + }, + }, + }, +}); +``` + +If a task name matches a script in `package.json`, the script is used automatically when `command` is omitted. See [Getting Started](./getting-started#task-definitions) for details. + +### `command` {#command} + +- **Type:** `string` +- **Default:** matching `package.json` script + +Shell command to run. If omitted, uses the script with the same name from `package.json`. + +```ts +tasks: { + build: { + command: 'vp build', + }, +} +``` + +You cannot define a command in both `vite.config.ts` and `package.json` for the same task name — it's one or the other. + +Commands joined with `&&` are automatically split into independently cached sub-tasks. See [Compound Commands](./running-tasks#compound-commands). + +### `dependsOn` {#depends-on} + +- **Type:** `string[]` +- **Default:** `[]` + +Tasks that must complete successfully before this one starts. + +```ts +tasks: { + deploy: { + command: 'deploy-script --prod', + dependsOn: ['build', 'test'], + }, +} +``` + +Dependencies can reference tasks in other packages using the `package#task` format: + +```ts +dependsOn: ['@my/core#build', '@my/utils#lint']; +``` + +See [Task Dependencies](./getting-started#task-dependencies) for details on how explicit and topological dependencies interact. + +### `cache` {#cache} + +- **Type:** `boolean` +- **Default:** `true` + +Whether to cache this task's output. Set to `false` for tasks that should never be cached, like dev servers: + +```ts +tasks: { + dev: { + command: 'vp dev', + cache: false, + }, +} +``` + +### `envs` {#envs} + +- **Type:** `string[]` +- **Default:** `[]` + +Environment variables included in the cache fingerprint. When any listed variable's value changes, the cache is invalidated. + +```ts +tasks: { + build: { + command: 'vp build', + envs: ['NODE_ENV'], + }, +} +``` + +Wildcard patterns are supported: `VITE_*` matches all variables starting with `VITE_`. + +``` +$ NODE_ENV=development vp run build # first run +$ NODE_ENV=production vp run build # cache miss: envs changed +``` + +### `passThroughEnvs` {#pass-through-envs} + +- **Type:** `string[]` +- **Default:** see below + +Environment variables passed to the task process but **not** included in the cache fingerprint. Changing these values won't invalidate the cache. + +```ts +tasks: { + build: { + command: 'vp build', + passThroughEnvs: ['CI', 'GITHUB_ACTIONS'], + }, +} +``` + +A set of common environment variables are automatically passed through to all tasks: + +- **System:** `HOME`, `USER`, `PATH`, `SHELL`, `LANG`, `TZ` +- **Node.js:** `NODE_OPTIONS`, `COREPACK_HOME`, `PNPM_HOME` +- **CI/CD:** `CI`, `VERCEL_*`, `NEXT_*` +- **Terminal:** `TERM`, `COLORTERM`, `FORCE_COLOR`, `NO_COLOR` + +### `inputs` {#inputs} + +- **Type:** `Array` +- **Default:** `[{ auto: true }]` (auto-inferred) + +Files to track for cache invalidation. By default, the task runner automatically detects which files a command reads. See [Automatic File Tracking](./caching#automatic-file-tracking) for how this works. + +**Exclude files** from automatic tracking: + +```ts +tasks: { + build: { + command: 'vp build', + inputs: [{ auto: true }, '!**/*.tsbuildinfo', '!dist/**'], + }, +} +``` + +**Specify explicit files** only (disables automatic tracking): + +```ts +tasks: { + build: { + command: 'vp build', + inputs: ['src/**/*.ts', 'vite.config.ts'], + }, +} +``` + +**Disable file tracking** entirely (cache only on command/env changes): + +```ts +tasks: { + greet: { + command: 'node greet.mjs', + inputs: [], + }, +} +``` + +::: tip +Glob patterns are resolved relative to the package directory, not the task's `cwd`. +::: + +### `cwd` {#cwd} + +- **Type:** `string` +- **Default:** package root + +Working directory for the task, relative to the package root. + +```ts +tasks: { + 'test-e2e': { + command: 'vp test', + cwd: 'tests/e2e', + }, +} +``` diff --git a/docs/vite/guide/task/getting-started.md b/docs/vite/guide/task/getting-started.md index e69de29bb2..53de9ee2e7 100644 --- a/docs/vite/guide/task/getting-started.md +++ b/docs/vite/guide/task/getting-started.md @@ -0,0 +1,141 @@ +# Getting Started + +## Overview + +`vp run` works like `pnpm run` — it runs the scripts in your `package.json` — but adds caching, dependency ordering, and monorepo-aware execution on top. It works in both single-package projects and monorepos. + +You can add task definitions in `vite.config.ts` when you need more control over dependencies and caching. + +## Running Scripts + +If your project already has scripts in `package.json`, you can run them with `vp run` right away — no configuration needed: + +```json [package.json] +{ + "scripts": { + "build": "vp build", + "test": "vp test" + } +} +``` + +```bash +vp run build +``` + +``` +$ vp build +vite v8.0.0 building for production... +✓ 4 modules transformed. +dist/index.html 0.12 kB │ gzip: 0.12 kB +dist/assets/index-FvSqcG4U.js 0.69 kB │ gzip: 0.39 kB + +✓ built in 28ms +``` + +## Caching + +Plain `package.json` scripts are not cached by default. Pass `--cache` to try it out: + +```bash +vp run --cache build +``` + +``` +$ vp build +✓ built in 28ms +``` + +Run it again — the output is replayed instantly from cache: + +``` +$ vp build ✓ cache hit, replaying +✓ built in 28ms + +--- +[vp run] cache hit, 468ms saved. +``` + +Edit a source file and run again — the task runner detects the change and re-runs: + +``` +$ vp build ✗ cache miss: 'src/index.ts' modified, executing +``` + +The task runner automatically tracks which files your command reads. No configuration needed. + +The `--cache` flag is a quick way to try caching, but the default behavior may not suit every task — you may need to control which files or environment variables affect the cache. To configure caching properly and enable it permanently, define the task in `vite.config.ts`. See [Caching](./caching) for how it works and [Config Reference](./config) for all task options. + +## Task Definitions {#task-definitions} + +Task definitions in `vite.config.ts` enable caching by default and give you more control — dependencies, environment variables, and custom inputs: + +```ts [vite.config.ts] +import { defineConfig } from 'vite-plus'; + +export default defineConfig({ + run: { + tasks: { + build: { + // Uses the "build" script from package.json + dependsOn: ['lint'], + envs: ['NODE_ENV'], + }, + deploy: { + command: 'deploy-script --prod', + cache: false, + dependsOn: ['build', 'test'], + }, + }, + }, +}); +``` + +A task definition can either reference a `package.json` script (by omitting `command`) or specify its own command. You cannot define a command in both places. + +::: info +Tasks defined in `vite.config.ts` are cached by default. Plain `package.json` scripts (without a matching task entry) are **not** cached by default. See [When Is Caching Enabled?](./caching#when-is-caching-enabled) for details. +::: + +See [Config Reference](./config) for all available task options. + +## Task Dependencies + +Use [`dependsOn`](./config#depends-on) to ensure tasks run in the right order. Running `vp run deploy` with the config above runs `build` and `test` first: + +``` + ┌─────────┐ ┌────────┐ + │ build │ │ test │ + └────┬────┘ └───┬────┘ + │ │ + └─────┬──────┘ + │ + ┌─────▼─────┐ + │ deploy │ + └───────────┘ +``` + +Dependencies can reference tasks in other packages using the `package#task` format: + +```ts +dependsOn: ['@my/core#build', '@my/utils#lint']; +``` + +## Running Across Packages + +In a monorepo, use `-r` (recursive) to run a task across all packages: + +```bash +vp run -r build +``` + +The task runner automatically orders packages by their `package.json` dependency graph — if `@my/app` depends on `@my/utils` which depends on `@my/core`, they build in that order. Each package's result is cached independently. + +See [Running Tasks](./running-tasks) for package selection with `--filter`, `--transitive`, and other options. + +## What's Next? + +- [Running Tasks](./running-tasks) — package selection, compound commands, and concurrency +- [Caching](./caching) — how caching works, file tracking, and cache sharing +- [CLI Reference](./cli) — all flags and options +- [Config Reference](./config) — all task configuration options diff --git a/docs/vite/guide/task/running-tasks.md b/docs/vite/guide/task/running-tasks.md new file mode 100644 index 0000000000..4645453010 --- /dev/null +++ b/docs/vite/guide/task/running-tasks.md @@ -0,0 +1,181 @@ +# Running Tasks + +## Package Selection {#package-selection} + +With no flags, `vp run` runs the task in the package containing your current directory: + +```bash +cd packages/app +vp run build # runs build in @my/app only +``` + +Use `package#task` to target a specific package from anywhere: + +```bash +vp run @my/app#build +``` + +### Recursive (`-r`) {#recursive} + +Run the task across **all** packages in the workspace: + +```bash +vp run -r build # builds every package, dependencies first +``` + +### Transitive (`-t`) {#transitive} + +Run the task in a package **and all its dependencies**: + +```bash +vp run -t @my/app#build +``` + +If `@my/app` depends on `@my/utils` which depends on `@my/core`, this builds all three in dependency order. You can also use `--filter "@my/app..."` for the same result. + +### Filter (`--filter`) {#filter} + +Select packages by name, directory, or glob pattern. The syntax is compatible with pnpm's `--filter`: + +```bash +# By name +vp run --filter @my/app build + +# By glob +vp run --filter "@my/*" build + +# By directory +vp run --filter ./packages/app build + +# With dependencies +vp run --filter "@my/app..." build # app + all its dependencies + +# With dependents +vp run --filter "...@my/core" build # core + everything that depends on it + +# Exclude packages +vp run --filter "@my/*" --filter "!@my/utils" build +``` + +Multiple `--filter` flags produce a union of the selected packages. + +### Workspace Root (`-w`) {#workspace-root} + +Explicitly select the workspace root package: + +```bash +vp run -w build +``` + +## Compound Commands {#compound-commands} + +Commands joined with `&&` are split into independent sub-tasks, each cached separately when [caching is enabled](./caching#when-is-caching-enabled). This applies to both `vite.config.ts` tasks and `package.json` scripts, where compound commands are common: + +```json [package.json] +{ + "scripts": { + "check": "vp lint && vp build" + } +} +``` + +``` +$ vp lint +Found 0 warnings and 0 errors. + +$ vp build +✓ built in 28ms + +--- +[vp run] 0/2 cache hit (0%). +``` + +Each sub-task has its own cache entry. On the next run, if only `.ts` files changed but lint passes, only `vp build` re-runs: + +``` +$ vp lint ✓ cache hit, replaying +$ vp build ✗ cache miss: 'src/index.ts' modified, executing +✓ built in 30ms + +--- +[vp run] 1/2 cache hit (50%), 120ms saved. +``` + +### Nested `vp run` {#nested-vp-run} + +When a command contains `vp run`, the task runner **inlines it as separate tasks** rather than spawning a nested process. Each sub-task is cached independently and output is shown flat: + +```json [package.json] +{ + "scripts": { + "ci": "vp run lint && vp run test && vp run build" + } +} +``` + +Running `vp run ci` expands into three separate tasks, each with its own cache entry: + +``` +┌────────┐ +│ lint │ +└───┬────┘ + │ +┌───▼────┐ +│ test │ +└───┬────┘ + │ +┌───▼────┐ +│ build │ +└────────┘ +``` + +Flags work inside nested scripts too. For example, `vp run -r build` inside a script expands into individual build tasks for every package. + +::: details Self-Referencing Scripts +A common monorepo pattern is a root script that runs a task recursively: + +```json [package.json (root)] +{ + "scripts": { + "build": "vp run -r build" + } +} +``` + +This creates a potential recursion: root's `build` → `vp run -r build` → includes root's `build` → ... The task runner detects this and prunes the self-reference automatically, so other packages' builds run normally without infinite loops. +::: + +## Execution Summary {#execution-summary} + +Use `-v` to see a detailed execution summary: + +```bash +vp run -r -v build +``` + +``` +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + Vite+ Task Runner • Execution Summary +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +Statistics: 3 tasks • 3 cache hits • 0 cache misses +Performance: 100% cache hit rate, 468ms saved in total + +Task Details: +──────────────────────────────────────────────── + [1] @my/core#build: ~/packages/core$ vp build ✓ + → Cache hit - output replayed - 200ms saved + ······················································· + [2] @my/utils#build: ~/packages/utils$ vp build ✓ + → Cache hit - output replayed - 150ms saved + ······················································· + [3] @my/app#build: ~/packages/app$ vp build ✓ + → Cache hit - output replayed - 118ms saved +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +``` + +Use `--last-details` to recall the summary from the last run without re-executing: + +```bash +vp run --last-details +```