@10up/wp-vite-plugins 1.0.0-alpha.2 → 1.0.0-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -12,6 +12,10 @@ npm install --save-dev @10up/wp-vite-plugins
12
12
 
13
13
  Requires Node ≥ 20.11 and Vite ^8 (Rolldown-powered).
14
14
 
15
+ ### Coming from `10up-toolkit`?
16
+
17
+ [Migrating a wp-scaffold project from `10up-toolkit`](./docs/migrating-from-toolkit.md) is a step-by-step playbook for converting an existing project — either as a bundler-only swap, or as a full toolchain replacement with Vite+.
18
+
15
19
  ### Vite+ / Rolldown compatibility
16
20
 
17
21
  The plugins use only Rolldown-implemented plugin APIs, so they work unchanged with [Vite+](https://viteplus.dev) — `vp dev`, `vp build`, and `vp build --mode modules` read the same `vite.config.ts` and produce identical output to plain `vite` commands. The test suite runs under `vp test` (Vitest) as well.
@@ -45,6 +49,7 @@ That single call wires up:
45
49
  - **`wpScriptDedupe`** _(auto, script mode)_ — gives every script-mode entry a private copy of the modules it imports, so no entry has to `import` a shared chunk (a classic script can't).
46
50
  - **`wpScriptIife`** _(auto)_ — wraps script-mode entries in an IIFE so they enqueue cleanly as classic `<script>` tags, defines `import.meta` away, and fails the build on output that isn't valid as a classic script.
47
51
  - **`wpCleanCssChunks`** _(auto)_ — deletes the empty JS shims Vite leaves next to CSS-only entries.
52
+ - **`wpCssAssetInfo`** _(auto)_ — emits an `.asset.php` sidecar for CSS-only entries, which `wpExternals` can't write for them (there's no JS chunk to walk).
48
53
 
49
54
  ## Wrapper options
50
55
 
@@ -100,6 +105,7 @@ Or let the bundled CLI drive both passes, one command per task — it cleans `di
100
105
  ```jsonc
101
106
  {
102
107
  "scripts": {
108
+ "dev": "wp-vite dev", // one dev server, both passes; see below
103
109
  "build": "wp-vite build", // script pass, then module pass; fails fast
104
110
  "watch": "wp-vite watch" // both passes watched in a single process
105
111
  }
@@ -108,6 +114,36 @@ Or let the bundled CLI drive both passes, one command per task — it cleans `di
108
114
 
109
115
  → [Full documentation](./docs/cli.md)
110
116
 
117
+ ## Dev server
118
+
119
+ `wp-vite dev` starts a real Vite dev server for a WordPress install — instant transforms, native ESM in the browser, HMR — and writes the one file PHP needs to know about it:
120
+
121
+ ```sh
122
+ wp-vite dev
123
+ ```
124
+
125
+ ```
126
+ dist/.wp-vite-dev.json { "origin": "http://localhost:5173", "base": "/", "plugins": [] }
127
+ ```
128
+
129
+ Present means hot; absent means serve the built files. Alongside it, [`wpDevServer`](./docs/wp-dev-server.md) writes dev `.asset.php` sidecars for every entry a build writes one for — blocks, block styles, admin pages and your own `rollupOptions.input` entries — with the same keys a build writes plus `'source'`, mapping each asset back to the file the server serves. It also writes the `block.json` / `blocks-manifest.php` tree `register_block_type()` reads off disk, and keeps all of it in step as blocks are added and removed mid-session.
130
+
131
+ Wiring it into WordPress is one line, next to your other `dist/` requires:
132
+
133
+ ```php
134
+ if ( file_exists( __DIR__ . '/dist/dev-server.php' ) ) {
135
+ require_once __DIR__ . '/dist/dev-server.php';
136
+ }
137
+ ```
138
+
139
+ `dev-server.php` is generated by every build (and by the dev server on start). Cold, it costs one `file_exists()`. Hot, it repoints every classic script (`script_loader_src` + a `type="module"` stamp), every Script Module (`script_module_loader_src`, WP 6.5+) and every stylesheet enqueued out of `dist/` at the running server, and enqueues Vite's HMR client. **No other PHP changes** — your registration code doesn't know the difference.
140
+
141
+ One server handles both passes: a classic entry gets the `window.wp.*` rewrite, a Script Module entry keeps its bare `@wordpress/*` specifiers for WordPress's runtime import map. The plugin is included by `wp()` by default, is `apply: 'serve'`, and costs a build nothing.
142
+
143
+ `@vitejs/plugin-react` gets React Fast Refresh for free — no extra config. When the hot file reports the plugin, `dev-server.php` attaches its preamble to the Vite client handle, ahead of every component module.
144
+
145
+ → [Full documentation](./docs/wp-dev-server.md)
146
+
111
147
  ## Using plugins individually
112
148
 
113
149
  The wrapper is just sugar. Every plugin is exported on its own for finer control:
@@ -135,7 +171,10 @@ export default defineConfig({
135
171
  wpAdminPages({ adminPagesDir: './assets/js/admin-pages', buildType: 'module' }),
136
172
  wpExternals({ buildType: 'script' }),
137
173
  // Script mode only, and in this order: dedupe partitions the graph, the
138
- // IIFE wrapper vets the result.
174
+ // IIFE wrapper vets the result. Composed by hand, wpScriptIife gets no
175
+ // `globals` map, so Rolldown's runtime `require()` of an external has
176
+ // nothing to resolve against — pass wpExternals' `globalsSink` through
177
+ // both if any dependency reaches an external from CommonJS.
139
178
  wpScriptDedupe(),
140
179
  wpScriptIife(),
141
180
  wpCleanCssChunks(),
@@ -154,6 +193,12 @@ Two runnable consumer projects live under [`examples/`](./examples/README.md), e
154
193
 
155
194
  The sections below are the quick reference. Each plugin also has an in-depth page under [`docs/`](./docs/README.md) covering internals, output formats, and caveats.
156
195
 
196
+ ### `wpDevServer(options)`
197
+
198
+ → [Full documentation](./docs/wp-dev-server.md)
199
+
200
+ Serve-only (`apply: 'serve'`), included by `wp()` by default. Writes `dist/.wp-vite-dev.json` on `listening` and deletes it on exit; writes dev `.asset.php` sidecars and the blocks metadata tree; keeps Script Module entries' bare specifiers intact for WordPress's import map; refreshes everything on watcher events. Its build-side twin `wpDevServerPhp` emits `dist/dev-server.php`, the PHP bridge, into every build. Disable both with `wp({ devServer: false })`.
201
+
157
202
  ### `wpBlocks(options)`
158
203
 
159
204
  → [Full documentation](./docs/wp-blocks.md)
@@ -206,6 +251,7 @@ For non-`@wordpress/*` packages, a hardcoded vendor map covers `react`, `react-d
206
251
  | `moduleEntryMatchers` | `string[]` | `[]` | File path substrings that should be treated as module-mode regardless of `buildType`. |
207
252
  | `wpBuildAssetMatchers` | `string[]` | `[]` | Entry source-path substrings whose `.asset.php` uses the `@wordpress/build` shape. |
208
253
  | `scriptModuleNamespaces` | `string[]` | `[]` | Plugin-local Script Module namespaces (exact or `prefix-*` glob). |
254
+ | `globalsSink` | `Map<string, string>` | — | Out-param, filled with specifier → window global so `wpScriptIife` can shim `require()` for CJS deps. Wired automatically by `wp()`. |
209
255
 
210
256
  ### `wpAdminPages(options)`
211
257
 
@@ -271,11 +317,15 @@ Copies static assets (images, fonts, SVG) from `copyAssetsDir` to `dist/`, prese
271
317
 
272
318
  Duplicates every statically shared module into each script-mode entry (webpack's behavior), so Rolldown never leaves an entry importing a shared chunk — invalid in a classic `<script>`. Also inlines Rolldown's CJS interop runtime and wpExternals' CJS global shims, which are injected too late to partition. Script mode + `vite build` only. No options.
273
319
 
274
- ### `wpScriptIife()`
320
+ ### `wpScriptIife(options?)`
275
321
 
276
322
  → [Full documentation](./docs/wp-script-iife.md)
277
323
 
278
- Wraps each script-mode entry chunk in an IIFE in `writeBundle`. Avoids global-scope leaks when WP enqueues bundles as classic `<script>` tags. Injects the `import.meta.url` / `import.meta.resolve` `define` script mode needs, and fails the build if a chunk still holds a live `import`/`export` statement or an `import.meta` reference. No options.
324
+ Wraps each script-mode entry chunk in an IIFE in `writeBundle`. Avoids global-scope leaks when WP enqueues bundles as classic `<script>` tags. Injects the `import.meta.url` / `import.meta.resolve` `define` script mode needs, and fails the build — for the whole pass, before anything is written — if a chunk still holds a live `import`/`export` statement or an `import.meta` reference.
325
+
326
+ | Option | Type | Default | Notes |
327
+ | --- | --- | --- | --- |
328
+ | `globals` | `Map<string, string>` | `new Map()` | Specifier → window global, used to shim `require()` for CJS deps Rolldown resolves at runtime. Wired automatically by `wp()`. |
279
329
 
280
330
  ### `wpCleanCssChunks()`
281
331
 
package/dist/build.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { R as RunnerOptions } from './runner-WUYCS-nx.js';
2
- export { B as BIN_CANDIDATES, D as DEFAULT_BUILD_ARGS, a as DEFAULT_WATCH_ARGS, b as DetectModulePassOptions, L as LinePrefixer, M as ModulePassDetection, O as OutputSink, P as ParsedCliArgs, c as PassName, d as ResolvedBin, e as RunnerName, f as RunnerSignal, g as cleanOutDir, h as createLinePrefixer, i as detectModulePass, p as parseCliArgs, r as resolveViteBin } from './runner-WUYCS-nx.js';
1
+ import { R as RunnerOptions } from './runner-jUVlAHlZ.js';
2
+ export { B as BIN_CANDIDATES, D as DEFAULT_BUILD_ARGS, a as DEFAULT_WATCH_ARGS, b as DetectModulePassOptions, L as LinePrefixer, M as ModulePassDetection, O as OutputSink, P as ParsedCliArgs, c as PassName, d as ResolvedBin, e as RunnerName, f as RunnerSignal, g as cleanOutDir, h as createLinePrefixer, i as detectModulePass, p as parseCliArgs, r as resolveViteBin } from './runner-jUVlAHlZ.js';
3
3
 
4
4
  /** Options for `build()`. Identical to `watch()`'s — see `RunnerOptions`. */
5
5
  type BuildOptions = RunnerOptions;
package/dist/build.js CHANGED
@@ -20,10 +20,27 @@ function spawnPass(options) {
20
20
  // `emptyOutDir: !isModulePass && !process.env.WP_VITE_UNIFIED_WATCH`.
21
21
  ...options.runner === "watch" ? { WP_VITE_UNIFIED_WATCH: "1" } : {}
22
22
  },
23
- stdio: ["ignore", "pipe", "pipe"],
23
+ stdio: options.inherit ? "inherit" : ["ignore", "pipe", "pipe"],
24
24
  // .cmd shims are not directly executable on Windows.
25
25
  shell: process.platform === "win32"
26
26
  });
27
+ if (options.inherit) {
28
+ const result2 = new Promise((settle) => {
29
+ let settled = false;
30
+ const finish = (passResult) => {
31
+ if (settled) return;
32
+ settled = true;
33
+ settle(passResult);
34
+ };
35
+ child.on("error", (error) => {
36
+ stderr.write(`[wp-vite] the ${pass} pass failed to start: ${error.message}
37
+ `);
38
+ finish({ pass, code: null, signal: null, error });
39
+ });
40
+ child.on("close", (code, signal) => finish({ pass, code, signal }));
41
+ });
42
+ return { pass, child, result: result2 };
43
+ }
27
44
  const outPrefixer = createLinePrefixer(`[${pass}] `, (text) => stdout.write(text));
28
45
  const errPrefixer = createLinePrefixer(`[${pass}] `, (text) => stderr.write(text));
29
46
  child.stdout?.setEncoding("utf8");
package/dist/build.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/runner.ts","../src/build.ts"],"names":["parsePath"],"mappings":"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","file":"build.js","sourcesContent":["/**\n * Shared internals for the `wp-vite` commands.\n *\n * `wp-vite build` and `wp-vite watch` are the same idea run two ways: take a\n * dual-pass project (`vite build` for classic scripts, `vite build --mode\n * modules` for Script Modules), clean the out dir once, then drive both passes\n * — sequentially for a build, concurrently for a watch — as a single process\n * with prefixed output and signal-clean shutdown.\n *\n * Everything they have in common lives here: out-dir cleaning, module-pass\n * detection, Vite binary resolution, child spawning with line prefixing,\n * signal forwarding, and argv parsing. The commands themselves are in\n * `./build` and `./watch`.\n *\n * No Vite internals are used — the commands only shell out to the consuming\n * package's own `vite` (or `vp`) binary.\n */\nimport { spawn, type ChildProcess } from 'node:child_process';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { rm } from 'node:fs/promises';\nimport { dirname, isAbsolute, join, parse as parsePath, resolve, sep } from 'node:path';\n\n/** The two Vite passes the commands can drive. */\nexport type PassName = 'script' | 'modules';\n\n/** Which command is driving the passes. Exposed to children as `WP_VITE_RUNNER`. */\nexport type RunnerName = 'build' | 'watch';\n\n/**\n * Signals the commands forward. Spelled out rather than pulled from the\n * ambient Node signal type, which this repo's ESLint config reports as an\n * undefined global.\n */\nexport type RunnerSignal = 'SIGINT' | 'SIGTERM';\n\n/** Sink for prefixed child output. `process.stdout` satisfies it. */\nexport interface OutputSink {\n\twrite(text: string): unknown;\n}\n\n/** Options shared by `build()` and `watch()`. */\nexport interface RunnerOptions {\n\t/** Package directory the passes run in. Default: `process.cwd()`. */\n\tcwd?: string;\n\t/**\n\t * Directory cleaned once at startup. Must match `build.outDir` of the\n\t * Vite config. Default: `'dist'`.\n\t */\n\toutDir?: string;\n\t/**\n\t * Force the module pass on/off. When omitted, `detectModulePass` decides.\n\t */\n\tmodules?: boolean;\n\t/** `--mode` value for the module pass. Default: `'modules'`. */\n\tmodulesMode?: string;\n\t/**\n\t * Binary to run. A bare name (`'vite'`, `'vp'`) is looked up in the\n\t * nearest `node_modules/.bin`; a path is used as-is. When omitted, `vite`\n\t * is preferred over `vp` (see `resolveViteBin`).\n\t */\n\tbin?: string;\n\t/** Extra arguments appended to both passes. */\n\targs?: string[];\n\t/** Skip the startup clean. Default: `false` (it cleans). */\n\tclean?: boolean;\n\t/** Install SIGINT/SIGTERM handlers on `process`. Default: `true`. */\n\thandleSignals?: boolean;\n\t/** Extra environment for the children. */\n\tenv?: Record<string, string | undefined>;\n\t/** Output sinks. Default: `process.stdout` / `process.stderr`. */\n\tstdout?: OutputSink;\n\tstderr?: OutputSink;\n\t/**\n\t * Replaces the built-in argv (`DEFAULT_BUILD_ARGS` / `DEFAULT_WATCH_ARGS`)\n\t * for every pass. Escape hatch for tests — it lets a stand-in child stand\n\t * in for a real Vite invocation.\n\t */\n\tbuildArgs?: string[];\n}\n\n/**\n * Arguments every `wp-vite build` pass gets, before the pass-specific\n * `--mode`.\n *\n * `--no-emptyOutDir` makes the runner's own one-time clean the single source\n * of truth, so no pass can delete another's output no matter how the config\n * sets `emptyOutDir`. `--no-clearScreen` keeps the second pass from erasing\n * the first pass' summary.\n */\nexport const DEFAULT_BUILD_ARGS = ['build', '--no-emptyOutDir', '--no-clearScreen'];\n\n/**\n * Arguments every `wp-vite watch` pass gets, before the pass-specific\n * `--mode`.\n *\n * `--no-emptyOutDir` is what stops the script pass from wiping the module\n * pass' chunks out of dist/ on every rebuild; it overrides `emptyOutDir: true`\n * from the config file (verified on Vite 8). `--no-clearScreen` stops two\n * watchers sharing one terminal from clearing each other's output.\n */\nexport const DEFAULT_WATCH_ARGS = ['build', '--watch', '--no-emptyOutDir', '--no-clearScreen'];\n\n/** Binary names tried, in order, when `bin` is not given. */\nexport const BIN_CANDIDATES = ['vite', 'vp'] as const;\n\n/** How a pass ended. */\nexport interface PassResult {\n\tpass: PassName;\n\tcode: number | null;\n\tsignal: string | null;\n\t/** Set when the binary could not be spawned at all. */\n\terror?: Error;\n}\n\nexport interface SpawnPassOptions {\n\tpass: PassName;\n\t/** Which command is driving — surfaced to the child as `WP_VITE_RUNNER`. */\n\trunner: RunnerName;\n\tbin: string;\n\targv: string[];\n\tcwd: string;\n\tenv?: Record<string, string | undefined>;\n\tstdout: OutputSink;\n\tstderr: OutputSink;\n}\n\nexport interface SpawnedPass {\n\tpass: PassName;\n\tchild: ChildProcess;\n\t/** Resolves once the child is gone *and* its output has been flushed. */\n\tresult: Promise<PassResult>;\n}\n\n/**\n * Spawn one pass with its output prefixed (`[script] ` / `[modules] `).\n *\n * The child gets `WP_VITE_RUNNER` and `WP_VITE_PASS` so a Vite config can tell\n * it is being driven by `wp-vite`, plus `WP_VITE_UNIFIED_WATCH=1` for the\n * watch command specifically (the documented `emptyOutDir` guard).\n */\nexport function spawnPass(options: SpawnPassOptions): SpawnedPass {\n\tconst { pass, stdout, stderr } = options;\n\n\tconst child = spawn(options.bin, options.argv, {\n\t\tcwd: options.cwd,\n\t\tenv: {\n\t\t\t...process.env,\n\t\t\t...options.env,\n\t\t\tWP_VITE_RUNNER: options.runner,\n\t\t\tWP_VITE_PASS: pass,\n\t\t\t// Kept for the documented watch-only guard:\n\t\t\t// `emptyOutDir: !isModulePass && !process.env.WP_VITE_UNIFIED_WATCH`.\n\t\t\t...(options.runner === 'watch' ? { WP_VITE_UNIFIED_WATCH: '1' } : {}),\n\t\t},\n\t\tstdio: ['ignore', 'pipe', 'pipe'],\n\t\t// .cmd shims are not directly executable on Windows.\n\t\tshell: process.platform === 'win32',\n\t});\n\n\tconst outPrefixer = createLinePrefixer(`[${pass}] `, (text) => stdout.write(text));\n\tconst errPrefixer = createLinePrefixer(`[${pass}] `, (text) => stderr.write(text));\n\tchild.stdout?.setEncoding('utf8');\n\tchild.stdout?.on('data', (chunk: string) => outPrefixer.write(chunk));\n\tchild.stderr?.setEncoding('utf8');\n\tchild.stderr?.on('data', (chunk: string) => errPrefixer.write(chunk));\n\n\tconst result = new Promise<PassResult>((settle) => {\n\t\tlet settled = false;\n\t\tconst finish = (passResult: PassResult) => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\toutPrefixer.flush();\n\t\t\terrPrefixer.flush();\n\t\t\tsettle(passResult);\n\t\t};\n\t\tchild.on('error', (error: Error) => {\n\t\t\tstderr.write(`[wp-vite] the ${pass} pass failed to start: ${error.message}\\n`);\n\t\t\tfinish({ pass, code: null, signal: null, error });\n\t\t});\n\t\tchild.on('close', (code, signal) => finish({ pass, code, signal }));\n\t});\n\n\treturn { pass, child, result };\n}\n\n/** Full argv for a pass: base args, then `--mode` for the module pass, then passthrough. */\nexport function passArgs(\n\tbase: readonly string[],\n\tpass: PassName,\n\tmodulesMode: string,\n\textra: readonly string[] = [],\n): string[] {\n\treturn [...base, ...(pass === 'modules' ? ['--mode', modulesMode] : []), ...extra];\n}\n\n/**\n * Register SIGINT/SIGTERM handlers that call `handler` with the signal that\n * fired. Returns a disposer.\n *\n * One bound handler per signal: the forwarded signal comes from the binding,\n * not from the event argument (which is absent when a test or a wrapper emits\n * the event by hand).\n */\nexport function forwardSignals(handler: (signal: RunnerSignal) => void): () => void {\n\tconst bound: Array<[RunnerSignal, () => void]> = (['SIGINT', 'SIGTERM'] as RunnerSignal[]).map(\n\t\t(signal) => [signal, () => handler(signal)],\n\t);\n\tfor (const [signal, listener] of bound) process.on(signal, listener);\n\treturn () => {\n\t\tfor (const [signal, listener] of bound) process.off(signal, listener);\n\t};\n}\n\n/** Human-readable cause of a child exit. */\nexport function describeExit(code: number | null, signal: string | null): string {\n\tif (signal) return `signal ${signal}`;\n\tif (code === null) return 'unknown cause';\n\treturn `exit code ${code}`;\n}\n\n/** Shell convention: a process killed by signal N reports `128 + N`. */\nconst SIGNAL_EXIT_CODES: Record<string, number> = {\n\tSIGINT: 130,\n\tSIGTERM: 143,\n\tSIGHUP: 129,\n\tSIGQUIT: 131,\n};\n\n/** Exit code for a signalled death: `128 + signo`, or `1` for anything unmapped. */\nexport function signalExitCode(signal: string | null): number {\n\tif (!signal) return 1;\n\treturn SIGNAL_EXIT_CODES[signal] ?? 1;\n}\n\n/** The exit code a pass result should produce. `0` only for a clean exit. */\nexport function passExitCode(result: PassResult): number {\n\tif (result.error) return 1;\n\tif (result.code !== null) return result.code;\n\treturn signalExitCode(result.signal);\n}\n\nexport interface ModulePassDetection {\n\tmodules: boolean;\n\t/** Why — surfaced in the startup log so the heuristic is never a mystery. */\n\treason: string;\n}\n\nexport interface DetectModulePassOptions {\n\tcwd?: string;\n\tmodulesMode?: string;\n\t/** Explicit override; wins over every heuristic. */\n\tmodules?: boolean;\n}\n\n/** Config file names probed for the module mode string, nearest-first. */\nconst VITE_CONFIG_FILES = [\n\t'vite.config.ts',\n\t'vite.config.mts',\n\t'vite.config.cts',\n\t'vite.config.js',\n\t'vite.config.mjs',\n\t'vite.config.cjs',\n];\n\n/**\n * Decide whether this package has a module pass.\n *\n * The commands deliberately do not import the user's Vite config (top-level\n * side effects) and cannot discover Script Module entries themselves — that\n * needs `blocksDir` / `adminPagesDir`, which only the config knows. So they\n * use a cheap, predictable, read-only heuristic:\n *\n * 1. an explicit `modules` option (`--modules` / `--no-modules`) wins;\n * 2. a `package.json` script whose command contains `--mode <modulesMode>`;\n * 3. a Vite config file whose source text contains the mode as a string\n * literal (`mode === 'modules'`, `'modules'` in a map, …).\n *\n * Everything else means \"script pass only\".\n */\nexport function detectModulePass(options: DetectModulePassOptions = {}): ModulePassDetection {\n\tif (typeof options.modules === 'boolean') {\n\t\treturn {\n\t\t\tmodules: options.modules,\n\t\t\treason: `explicit --${options.modules ? 'modules' : 'no-modules'} flag`,\n\t\t};\n\t}\n\n\tconst cwd = resolve(options.cwd ?? process.cwd());\n\tconst modulesMode = options.modulesMode ?? 'modules';\n\tconst escapedMode = escapeRegExp(modulesMode);\n\n\tconst scriptMatch = new RegExp(`(?:--mode[=\\\\s]+|(?:^|\\\\s)-m\\\\s+)${escapedMode}(?![\\\\w-])`);\n\tconst packageJson = readJson(join(cwd, 'package.json'));\n\tconst scripts = packageJson?.scripts;\n\tif (scripts && typeof scripts === 'object') {\n\t\tfor (const [name, command] of Object.entries(scripts as Record<string, unknown>)) {\n\t\t\tif (typeof command === 'string' && scriptMatch.test(command)) {\n\t\t\t\treturn {\n\t\t\t\t\tmodules: true,\n\t\t\t\t\treason: `package.json script \"${name}\" runs --mode ${modulesMode}`,\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t}\n\n\tconst configMatch = new RegExp(`(['\"\\`])${escapedMode}\\\\1`);\n\tfor (const fileName of VITE_CONFIG_FILES) {\n\t\tconst filePath = join(cwd, fileName);\n\t\tconst source = readFileIfExists(filePath);\n\t\tif (source === null) continue;\n\t\tif (configMatch.test(source)) {\n\t\t\treturn { modules: true, reason: `${fileName} mentions the \"${modulesMode}\" mode` };\n\t\t}\n\t\t// The nearest config wins — don't keep probing alternate extensions.\n\t\treturn {\n\t\t\tmodules: false,\n\t\t\treason: `${fileName} never mentions the \"${modulesMode}\" mode`,\n\t\t};\n\t}\n\n\treturn {\n\t\tmodules: false,\n\t\treason: `no package.json script or Vite config mentions the \"${modulesMode}\" mode`,\n\t};\n}\n\nexport interface ResolvedBin {\n\t/** Binary name, or the raw value when an explicit path was given. */\n\tname: string;\n\t/** What gets handed to `spawn`. */\n\tpath: string;\n}\n\n/**\n * Find the Vite CLI the consuming package would use.\n *\n * Walks `node_modules/.bin` from `cwd` upwards, so workspace packages find a\n * hoisted binary at the monorepo root. `vite` is preferred over `vp`: plain\n * Vite is present in every setup (Vite+ installs it too) and `vp build`'s\n * extra orchestration buys these commands nothing. Packages that need `vp` —\n * for its caching or remote-cache layer — pass `--bin vp`.\n */\nexport function resolveViteBin(\n\tcwd: string = process.cwd(),\n\tcandidates: readonly string[] = BIN_CANDIDATES,\n): ResolvedBin {\n\tconst searched: string[] = [];\n\tfor (const binDir of nodeModulesBinDirs(cwd)) {\n\t\tfor (const name of candidates) {\n\t\t\tfor (const fileName of binFileNames(name)) {\n\t\t\t\tconst candidatePath = join(binDir, fileName);\n\t\t\t\tsearched.push(candidatePath);\n\t\t\t\tif (existsSync(candidatePath)) return { name, path: candidatePath };\n\t\t\t}\n\t\t}\n\t}\n\tthrow new Error(\n\t\t`[wp-vite] could not find a Vite binary (${candidates.join(' or ')}) in any ` +\n\t\t\t`node_modules/.bin above ${cwd}. Install vite in the package, or pass --bin <name|path>. ` +\n\t\t\t`Looked at:\\n ${searched.join('\\n ')}`,\n\t);\n}\n\n/** Resolve the `bin` option: a path is used as-is, a bare name is looked up. */\nexport function resolveBin(bin: string | undefined, cwd: string): string {\n\tif (!bin) return resolveViteBin(cwd).path;\n\tif (isAbsolute(bin) || bin.includes('/') || bin.includes('\\\\')) return bin;\n\ttry {\n\t\treturn resolveViteBin(cwd, [bin]).path;\n\t} catch {\n\t\t// Not in node_modules/.bin — let the OS resolve it from PATH.\n\t\treturn bin;\n\t}\n}\n\n/** Every `node_modules/.bin` from `from` up to the filesystem root. */\nfunction nodeModulesBinDirs(from: string): string[] {\n\tconst dirs: string[] = [];\n\tlet current = resolve(from);\n\tconst { root } = parsePath(current);\n\twhile (true) {\n\t\tdirs.push(join(current, 'node_modules', '.bin'));\n\t\tif (current === root) break;\n\t\tconst parent = dirname(current);\n\t\tif (parent === current) break;\n\t\tcurrent = parent;\n\t}\n\treturn dirs;\n}\n\n/** Windows shims first, then the POSIX name. */\nfunction binFileNames(name: string): string[] {\n\treturn process.platform === 'win32' ? [`${name}.cmd`, name] : [name];\n}\n\n/**\n * Remove `outDir` — once, before any pass runs. Returns the absolute path that\n * was cleaned.\n */\nexport async function cleanOutDir(outDir = 'dist', cwd: string = process.cwd()): Promise<string> {\n\tconst base = resolve(cwd);\n\tconst target = isAbsolute(outDir) ? resolve(outDir) : resolve(base, outDir);\n\t// Never let a stray `--out-dir ..` or `--out-dir /` delete the world.\n\tif (target === parsePath(target).root || target === base || !target.startsWith(base + sep)) {\n\t\tthrow new Error(\n\t\t\t`[wp-vite] refusing to clean ${target}: the out dir must be inside ${base}`,\n\t\t);\n\t}\n\tawait rm(target, { recursive: true, force: true });\n\treturn target;\n}\n\nexport interface LinePrefixer {\n\t/** Feed a (possibly partial) chunk of child output. */\n\twrite(chunk: string): void;\n\t/** Emit a trailing line that never got its newline. */\n\tflush(): void;\n}\n\n/** Leading erase-line/erase-display sequences left over from CR redraws. */\nconst ESCAPE = String.fromCharCode(27);\nconst ERASE_SEQUENCE = new RegExp(`^(?:${ESCAPE}\\\\[[0-2]?[KJ])+`);\n\n/**\n * Prefix child output line by line. Chunks arrive on arbitrary boundaries, so\n * a partial trailing line is buffered until its newline shows up.\n *\n * Two cosmetic rules keep interleaved passes readable: blank lines pass\n * through unprefixed (Vite prints plenty, and `[script] ` alone is noise), and\n * a line redrawn with carriage returns is reduced to what a terminal would\n * actually show — the text after the last CR, minus the erase codes.\n */\nexport function createLinePrefixer(prefix: string, write: (text: string) => void): LinePrefixer {\n\tlet buffer = '';\n\tconst emit = (line: string) => {\n\t\t// A trailing CR is just CRLF; earlier CRs are redraws of the same line.\n\t\tconst withoutCrlf = line.endsWith('\\r') ? line.slice(0, -1) : line;\n\t\tconst rendered = withoutCrlf.split('\\r').pop() ?? '';\n\t\tconst content = rendered.replace(ERASE_SEQUENCE, '');\n\t\twrite(content.length === 0 ? '\\n' : `${prefix}${content}\\n`);\n\t};\n\treturn {\n\t\twrite(chunk: string) {\n\t\t\tbuffer += chunk;\n\t\t\tconst lines = buffer.split('\\n');\n\t\t\tbuffer = lines.pop() ?? '';\n\t\t\tfor (const line of lines) emit(line);\n\t\t},\n\t\tflush() {\n\t\t\tif (buffer.length === 0) return;\n\t\t\tconst pending = buffer;\n\t\t\tbuffer = '';\n\t\t\temit(pending);\n\t\t},\n\t};\n}\n\nexport interface ParsedCliArgs {\n\tcommand: string | undefined;\n\toptions: RunnerOptions;\n\thelp: boolean;\n\tversion: boolean;\n\t/** Flags that are not recognised — the CLI reports these and exits 1. */\n\tunknown: string[];\n}\n\n/**\n * Hand-rolled argv parser (no dependency). Supports:\n *\n * wp-vite <build|watch> [--out-dir dist] [--modules|--no-modules]\n * [--modules-mode modules] [--bin vite|vp|<path>]\n * [--no-clean] [--cwd <dir>] [-- <extra vite args>]\n *\n * `--flag=value` and `--flag value` are both accepted. Everything after a\n * bare `--` is forwarded verbatim to both Vite passes.\n */\nexport function parseCliArgs(argv: readonly string[]): ParsedCliArgs {\n\tconst parsed: ParsedCliArgs = {\n\t\tcommand: undefined,\n\t\toptions: {},\n\t\thelp: false,\n\t\tversion: false,\n\t\tunknown: [],\n\t};\n\tconst passthrough: string[] = [];\n\tlet index = 0;\n\n\tfor (; index < argv.length; index += 1) {\n\t\tconst arg = argv[index];\n\n\t\tif (arg === '--') {\n\t\t\tpassthrough.push(...argv.slice(index + 1));\n\t\t\tbreak;\n\t\t}\n\n\t\tif (!arg.startsWith('-')) {\n\t\t\tif (parsed.command === undefined) parsed.command = arg;\n\t\t\telse parsed.unknown.push(arg);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst equalsAt = arg.indexOf('=');\n\t\tconst flag = equalsAt === -1 ? arg : arg.slice(0, equalsAt);\n\t\tconst inlineValue = equalsAt === -1 ? undefined : arg.slice(equalsAt + 1);\n\t\tconst takeValue = (): string | undefined => {\n\t\t\tif (inlineValue !== undefined) return inlineValue;\n\t\t\tconst next = argv[index + 1];\n\t\t\tif (next === undefined || next.startsWith('-')) return undefined;\n\t\t\tindex += 1;\n\t\t\treturn next;\n\t\t};\n\n\t\tswitch (flag) {\n\t\t\tcase '-h':\n\t\t\tcase '--help':\n\t\t\t\tparsed.help = true;\n\t\t\t\tbreak;\n\t\t\tcase '-v':\n\t\t\tcase '--version':\n\t\t\t\tparsed.version = true;\n\t\t\t\tbreak;\n\t\t\tcase '--out-dir':\n\t\t\tcase '--outDir': {\n\t\t\t\tconst value = takeValue();\n\t\t\t\tif (value === undefined) parsed.unknown.push(`${flag} (missing value)`);\n\t\t\t\telse parsed.options.outDir = value;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase '--modules-mode':\n\t\t\tcase '--modulesMode': {\n\t\t\t\tconst value = takeValue();\n\t\t\t\tif (value === undefined) parsed.unknown.push(`${flag} (missing value)`);\n\t\t\t\telse parsed.options.modulesMode = value;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase '--bin': {\n\t\t\t\tconst value = takeValue();\n\t\t\t\tif (value === undefined) parsed.unknown.push(`${flag} (missing value)`);\n\t\t\t\telse parsed.options.bin = value;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase '--cwd': {\n\t\t\t\tconst value = takeValue();\n\t\t\t\tif (value === undefined) parsed.unknown.push(`${flag} (missing value)`);\n\t\t\t\telse parsed.options.cwd = value;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase '--modules':\n\t\t\t\tparsed.options.modules = true;\n\t\t\t\tbreak;\n\t\t\tcase '--no-modules':\n\t\t\t\tparsed.options.modules = false;\n\t\t\t\tbreak;\n\t\t\tcase '--clean':\n\t\t\t\tparsed.options.clean = true;\n\t\t\t\tbreak;\n\t\t\tcase '--no-clean':\n\t\t\t\tparsed.options.clean = false;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tparsed.unknown.push(flag);\n\t\t}\n\t}\n\n\tif (passthrough.length > 0) parsed.options.args = passthrough;\n\treturn parsed;\n}\n\n/**\n * Shared preamble: resolve the binary, decide on the module pass, clean the\n * out dir once, and log both decisions.\n */\nexport async function prepareRun(\n\toptions: RunnerOptions,\n\trunner: RunnerName,\n): Promise<{\n\tcwd: string;\n\tbin: string;\n\tmodulesMode: string;\n\tpasses: PassName[];\n\tstdout: OutputSink;\n\tstderr: OutputSink;\n}> {\n\tconst cwd = resolve(options.cwd ?? process.cwd());\n\tconst outDir = options.outDir ?? 'dist';\n\tconst modulesMode = options.modulesMode ?? 'modules';\n\tconst stdout = options.stdout ?? process.stdout;\n\tconst stderr = options.stderr ?? process.stderr;\n\n\tconst bin = resolveBin(options.bin, cwd);\n\tconst detection = detectModulePass({ cwd, modulesMode, modules: options.modules });\n\tconst passes: PassName[] = detection.modules ? ['script', 'modules'] : ['script'];\n\n\t// Cleaning here, once, is what lets every pass run with `--no-emptyOutDir`\n\t// and still start from an empty dist/.\n\tif (options.clean !== false) {\n\t\tconst cleaned = await cleanOutDir(outDir, cwd);\n\t\tstdout.write(`[wp-vite] cleaned ${cleaned}\\n`);\n\t}\n\n\tstdout.write(\n\t\t`[wp-vite] module pass ${detection.modules ? 'enabled' : 'disabled'} — ${detection.reason}; ` +\n\t\t\t`${runner === 'watch' ? 'watching' : 'building'} ${passes.join(runner === 'watch' ? ' + ' : ' then ')} via ${bin}\\n`,\n\t);\n\n\treturn { cwd, bin, modulesMode, passes, stdout, stderr };\n}\n\nfunction escapeRegExp(value: string): string {\n\treturn value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nfunction readFileIfExists(filePath: string): string | null {\n\ttry {\n\t\treturn readFileSync(filePath, 'utf8');\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction readJson(filePath: string): Record<string, unknown> | null {\n\tconst source = readFileIfExists(filePath);\n\tif (source === null) return null;\n\ttry {\n\t\treturn JSON.parse(source) as Record<string, unknown>;\n\t} catch {\n\t\treturn null;\n\t}\n}\n","/**\n * `wp-vite build` — one command that runs both passes of a dual-pass build.\n *\n * The documented shape is `vite build && vite build --mode modules`: two\n * invocations, chained, because both write into the same `dist/` and the\n * second pass is purely additive. That works, but every package has to spell\n * it out, remember the mode name, and get the `emptyOutDir` split right.\n *\n * This command:\n * 1. cleans the out dir once, itself;\n * 2. runs `<bin> build --no-emptyOutDir --no-clearScreen` to completion;\n * 3. then, iff the package has a module pass (see `detectModulePass`), runs\n * the same command with `--mode modules`;\n * 4. prefixes every child line with `[script] ` / `[modules] `;\n * 5. forwards SIGINT/SIGTERM to whichever pass is running;\n * 6. fails fast — a non-zero script pass skips the module pass and exits\n * with that code (the `&&` semantics, preserved).\n *\n * Sequential, not concurrent: both passes write into the same directory, and\n * `wpBlocks` / `wpCopyAssets` gate their file copying on the script pass, so\n * the module pass must observe a finished script pass.\n *\n * The watch counterpart is `watch()` in `./watch`; the machinery both share\n * lives in `./runner`.\n */\nimport type { ChildProcess } from 'node:child_process';\nimport {\n\tDEFAULT_BUILD_ARGS,\n\tdescribeExit,\n\tforwardSignals,\n\tpassArgs,\n\tpassExitCode,\n\tprepareRun,\n\tsignalExitCode,\n\tspawnPass,\n\ttype RunnerOptions,\n} from './runner';\n\n/**\n * The shared surface both commands expose, so a consumer can reach the\n * helpers from either subpath. The spawning/sequencing plumbing in `./runner`\n * stays internal.\n */\nexport {\n\tBIN_CANDIDATES,\n\tDEFAULT_BUILD_ARGS,\n\tDEFAULT_WATCH_ARGS,\n\tcleanOutDir,\n\tcreateLinePrefixer,\n\tdetectModulePass,\n\tparseCliArgs,\n\tresolveViteBin,\n} from './runner';\nexport type {\n\tDetectModulePassOptions,\n\tLinePrefixer,\n\tModulePassDetection,\n\tOutputSink,\n\tParsedCliArgs,\n\tPassName,\n\tResolvedBin,\n\tRunnerName,\n\tRunnerOptions,\n\tRunnerSignal,\n} from './runner';\n\n/** Options for `build()`. Identical to `watch()`'s — see `RunnerOptions`. */\nexport type BuildOptions = RunnerOptions;\n\n/**\n * Run both passes in order. Resolves with the process exit code: `0` when\n * every pass succeeded, the failing pass' code when one didn't, `128 + signo`\n * (`130` for SIGINT) when interrupted.\n */\nexport async function build(options: BuildOptions = {}): Promise<number> {\n\tconst { cwd, bin, modulesMode, passes, stdout, stderr } = await prepareRun(options, 'build');\n\n\tlet current: ChildProcess | undefined;\n\tlet interrupted = false;\n\tlet interruptCode = 0;\n\n\tconst disposeSignals =\n\t\toptions.handleSignals === false\n\t\t\t? () => {}\n\t\t\t: forwardSignals((signal) => {\n\t\t\t\t\tif (interrupted) return;\n\t\t\t\t\tinterrupted = true;\n\t\t\t\t\tinterruptCode = signalExitCode(signal);\n\t\t\t\t\tif (current && current.exitCode === null && current.signalCode === null) {\n\t\t\t\t\t\tcurrent.kill(signal);\n\t\t\t\t\t}\n\t\t\t\t});\n\n\ttry {\n\t\tfor (const [index, pass] of passes.entries()) {\n\t\t\tif (interrupted) {\n\t\t\t\tstderr.write(`[wp-vite] interrupted — skipping the ${pass} pass\\n`);\n\t\t\t\treturn interruptCode;\n\t\t\t}\n\n\t\t\tconst spawned = spawnPass({\n\t\t\t\tpass,\n\t\t\t\trunner: 'build',\n\t\t\t\tbin,\n\t\t\t\tcwd,\n\t\t\t\targv: passArgs(\n\t\t\t\t\toptions.buildArgs ?? DEFAULT_BUILD_ARGS,\n\t\t\t\t\tpass,\n\t\t\t\t\tmodulesMode,\n\t\t\t\t\toptions.args ?? [],\n\t\t\t\t),\n\t\t\t\tenv: options.env,\n\t\t\t\tstdout,\n\t\t\t\tstderr,\n\t\t\t});\n\t\t\tcurrent = spawned.child;\n\t\t\tconst result = await spawned.result;\n\t\t\tcurrent = undefined;\n\n\t\t\tconst code = passExitCode(result);\n\t\t\tif (code === 0) continue;\n\n\t\t\t// Fail fast: `&&` semantics. Name what got skipped so a CI log\n\t\t\t// doesn't look like the module pass silently vanished.\n\t\t\tconst skipped = passes.slice(index + 1);\n\t\t\tstderr.write(\n\t\t\t\t`[wp-vite] the ${pass} pass failed (${describeExit(result.code, result.signal)})` +\n\t\t\t\t\t(skipped.length > 0 ? ` — skipping the ${skipped.join(' and ')} pass` : '') +\n\t\t\t\t\t'\\n',\n\t\t\t);\n\t\t\treturn code;\n\t\t}\n\n\t\tstdout.write(\n\t\t\tpasses.length > 1\n\t\t\t\t? `[wp-vite] built ${passes.join(' + ')} into one dist\\n`\n\t\t\t\t: `[wp-vite] built the ${passes[0]} pass\\n`,\n\t\t);\n\t\treturn 0;\n\t} finally {\n\t\tdisposeSignals();\n\t}\n}\n"]}
1
+ {"version":3,"sources":["../src/runner.ts","../src/build.ts"],"names":["result","parsePath"],"mappings":"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","file":"build.js","sourcesContent":["/**\n * Shared internals for the `wp-vite` commands.\n *\n * `wp-vite build` and `wp-vite watch` are the same idea run two ways: take a\n * dual-pass project (`vite build` for classic scripts, `vite build --mode\n * modules` for Script Modules), clean the out dir once, then drive both passes\n * — sequentially for a build, concurrently for a watch — as a single process\n * with prefixed output and signal-clean shutdown.\n *\n * Everything they have in common lives here: out-dir cleaning, module-pass\n * detection, Vite binary resolution, child spawning with line prefixing,\n * signal forwarding, and argv parsing. The commands themselves are in\n * `./build` and `./watch`.\n *\n * No Vite internals are used — the commands only shell out to the consuming\n * package's own `vite` (or `vp`) binary.\n */\nimport { spawn, type ChildProcess } from 'node:child_process';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { rm } from 'node:fs/promises';\nimport { dirname, isAbsolute, join, parse as parsePath, resolve, sep } from 'node:path';\n\n/**\n * The Vite invocations the commands can drive. `script` / `modules` are the\n * two build passes; `dev` is the single serve-mode server `wp-vite dev` runs\n * (there is no second pass in dev — one server handles both, see\n * `wpDevServer`).\n */\nexport type PassName = 'script' | 'modules' | 'dev';\n\n/** Which command is driving the passes. Exposed to children as `WP_VITE_RUNNER`. */\nexport type RunnerName = 'build' | 'watch' | 'dev';\n\n/**\n * Signals the commands forward. Spelled out rather than pulled from the\n * ambient Node signal type, which this repo's ESLint config reports as an\n * undefined global.\n */\nexport type RunnerSignal = 'SIGINT' | 'SIGTERM';\n\n/** Sink for prefixed child output. `process.stdout` satisfies it. */\nexport interface OutputSink {\n\twrite(text: string): unknown;\n}\n\n/** Options shared by `build()` and `watch()`. */\nexport interface RunnerOptions {\n\t/** Package directory the passes run in. Default: `process.cwd()`. */\n\tcwd?: string;\n\t/**\n\t * Directory cleaned once at startup. Must match `build.outDir` of the\n\t * Vite config. Default: `'dist'`.\n\t */\n\toutDir?: string;\n\t/**\n\t * Force the module pass on/off. When omitted, `detectModulePass` decides.\n\t */\n\tmodules?: boolean;\n\t/** `--mode` value for the module pass. Default: `'modules'`. */\n\tmodulesMode?: string;\n\t/**\n\t * Binary to run. A bare name (`'vite'`, `'vp'`) is looked up in the\n\t * nearest `node_modules/.bin`; a path is used as-is. When omitted, `vite`\n\t * is preferred over `vp` (see `resolveViteBin`).\n\t */\n\tbin?: string;\n\t/** Extra arguments appended to both passes. */\n\targs?: string[];\n\t/** Skip the startup clean. Default: `false` (it cleans). */\n\tclean?: boolean;\n\t/** Install SIGINT/SIGTERM handlers on `process`. Default: `true`. */\n\thandleSignals?: boolean;\n\t/** Extra environment for the children. */\n\tenv?: Record<string, string | undefined>;\n\t/** Output sinks. Default: `process.stdout` / `process.stderr`. */\n\tstdout?: OutputSink;\n\tstderr?: OutputSink;\n\t/**\n\t * Replaces the built-in argv (`DEFAULT_BUILD_ARGS` / `DEFAULT_WATCH_ARGS`)\n\t * for every pass. Escape hatch for tests — it lets a stand-in child stand\n\t * in for a real Vite invocation.\n\t */\n\tbuildArgs?: string[];\n}\n\n/**\n * Arguments every `wp-vite build` pass gets, before the pass-specific\n * `--mode`.\n *\n * `--no-emptyOutDir` makes the runner's own one-time clean the single source\n * of truth, so no pass can delete another's output no matter how the config\n * sets `emptyOutDir`. `--no-clearScreen` keeps the second pass from erasing\n * the first pass' summary.\n */\nexport const DEFAULT_BUILD_ARGS = ['build', '--no-emptyOutDir', '--no-clearScreen'];\n\n/**\n * Arguments every `wp-vite watch` pass gets, before the pass-specific\n * `--mode`.\n *\n * `--no-emptyOutDir` is what stops the script pass from wiping the module\n * pass' chunks out of dist/ on every rebuild; it overrides `emptyOutDir: true`\n * from the config file (verified on Vite 8). `--no-clearScreen` stops two\n * watchers sharing one terminal from clearing each other's output.\n */\nexport const DEFAULT_WATCH_ARGS = ['build', '--watch', '--no-emptyOutDir', '--no-clearScreen'];\n\n/** Binary names tried, in order, when `bin` is not given. */\nexport const BIN_CANDIDATES = ['vite', 'vp'] as const;\n\n/** How a pass ended. */\nexport interface PassResult {\n\tpass: PassName;\n\tcode: number | null;\n\tsignal: string | null;\n\t/** Set when the binary could not be spawned at all. */\n\terror?: Error;\n}\n\nexport interface SpawnPassOptions {\n\tpass: PassName;\n\t/** Which command is driving — surfaced to the child as `WP_VITE_RUNNER`. */\n\trunner: RunnerName;\n\tbin: string;\n\targv: string[];\n\tcwd: string;\n\tenv?: Record<string, string | undefined>;\n\tstdout: OutputSink;\n\tstderr: OutputSink;\n\t/**\n\t * Hand the child this process' stdio instead of piping and prefixing it.\n\t * Prefixing exists to keep two concurrent passes apart; a dev server is on\n\t * its own, and piping would cost it the things that make it usable —\n\t * a TTY for the `r`/`u`/`q` shortcuts, colour, and the clickable\n\t * \"Local:\" URL. Ignored for the build/watch passes.\n\t */\n\tinherit?: boolean;\n}\n\nexport interface SpawnedPass {\n\tpass: PassName;\n\tchild: ChildProcess;\n\t/** Resolves once the child is gone *and* its output has been flushed. */\n\tresult: Promise<PassResult>;\n}\n\n/**\n * Spawn one pass with its output prefixed (`[script] ` / `[modules] `).\n *\n * The child gets `WP_VITE_RUNNER` and `WP_VITE_PASS` so a Vite config can tell\n * it is being driven by `wp-vite`, plus `WP_VITE_UNIFIED_WATCH=1` for the\n * watch command specifically (the documented `emptyOutDir` guard).\n */\nexport function spawnPass(options: SpawnPassOptions): SpawnedPass {\n\tconst { pass, stdout, stderr } = options;\n\n\tconst child = spawn(options.bin, options.argv, {\n\t\tcwd: options.cwd,\n\t\tenv: {\n\t\t\t...process.env,\n\t\t\t...options.env,\n\t\t\tWP_VITE_RUNNER: options.runner,\n\t\t\tWP_VITE_PASS: pass,\n\t\t\t// Kept for the documented watch-only guard:\n\t\t\t// `emptyOutDir: !isModulePass && !process.env.WP_VITE_UNIFIED_WATCH`.\n\t\t\t...(options.runner === 'watch' ? { WP_VITE_UNIFIED_WATCH: '1' } : {}),\n\t\t},\n\t\tstdio: options.inherit ? 'inherit' : ['ignore', 'pipe', 'pipe'],\n\t\t// .cmd shims are not directly executable on Windows.\n\t\tshell: process.platform === 'win32',\n\t});\n\n\tif (options.inherit) {\n\t\tconst result = new Promise<PassResult>((settle) => {\n\t\t\tlet settled = false;\n\t\t\tconst finish = (passResult: PassResult) => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tsettle(passResult);\n\t\t\t};\n\t\t\tchild.on('error', (error: Error) => {\n\t\t\t\tstderr.write(`[wp-vite] the ${pass} pass failed to start: ${error.message}\\n`);\n\t\t\t\tfinish({ pass, code: null, signal: null, error });\n\t\t\t});\n\t\t\tchild.on('close', (code, signal) => finish({ pass, code, signal }));\n\t\t});\n\t\treturn { pass, child, result };\n\t}\n\n\tconst outPrefixer = createLinePrefixer(`[${pass}] `, (text) => stdout.write(text));\n\tconst errPrefixer = createLinePrefixer(`[${pass}] `, (text) => stderr.write(text));\n\tchild.stdout?.setEncoding('utf8');\n\tchild.stdout?.on('data', (chunk: string) => outPrefixer.write(chunk));\n\tchild.stderr?.setEncoding('utf8');\n\tchild.stderr?.on('data', (chunk: string) => errPrefixer.write(chunk));\n\n\tconst result = new Promise<PassResult>((settle) => {\n\t\tlet settled = false;\n\t\tconst finish = (passResult: PassResult) => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\toutPrefixer.flush();\n\t\t\terrPrefixer.flush();\n\t\t\tsettle(passResult);\n\t\t};\n\t\tchild.on('error', (error: Error) => {\n\t\t\tstderr.write(`[wp-vite] the ${pass} pass failed to start: ${error.message}\\n`);\n\t\t\tfinish({ pass, code: null, signal: null, error });\n\t\t});\n\t\tchild.on('close', (code, signal) => finish({ pass, code, signal }));\n\t});\n\n\treturn { pass, child, result };\n}\n\n/** Full argv for a pass: base args, then `--mode` for the module pass, then passthrough. */\nexport function passArgs(\n\tbase: readonly string[],\n\tpass: PassName,\n\tmodulesMode: string,\n\textra: readonly string[] = [],\n): string[] {\n\treturn [...base, ...(pass === 'modules' ? ['--mode', modulesMode] : []), ...extra];\n}\n\n/**\n * Register SIGINT/SIGTERM handlers that call `handler` with the signal that\n * fired. Returns a disposer.\n *\n * One bound handler per signal: the forwarded signal comes from the binding,\n * not from the event argument (which is absent when a test or a wrapper emits\n * the event by hand).\n */\nexport function forwardSignals(handler: (signal: RunnerSignal) => void): () => void {\n\tconst bound: Array<[RunnerSignal, () => void]> = (['SIGINT', 'SIGTERM'] as RunnerSignal[]).map(\n\t\t(signal) => [signal, () => handler(signal)],\n\t);\n\tfor (const [signal, listener] of bound) process.on(signal, listener);\n\treturn () => {\n\t\tfor (const [signal, listener] of bound) process.off(signal, listener);\n\t};\n}\n\n/** Human-readable cause of a child exit. */\nexport function describeExit(code: number | null, signal: string | null): string {\n\tif (signal) return `signal ${signal}`;\n\tif (code === null) return 'unknown cause';\n\treturn `exit code ${code}`;\n}\n\n/** Shell convention: a process killed by signal N reports `128 + N`. */\nconst SIGNAL_EXIT_CODES: Record<string, number> = {\n\tSIGINT: 130,\n\tSIGTERM: 143,\n\tSIGHUP: 129,\n\tSIGQUIT: 131,\n};\n\n/** Exit code for a signalled death: `128 + signo`, or `1` for anything unmapped. */\nexport function signalExitCode(signal: string | null): number {\n\tif (!signal) return 1;\n\treturn SIGNAL_EXIT_CODES[signal] ?? 1;\n}\n\n/** The exit code a pass result should produce. `0` only for a clean exit. */\nexport function passExitCode(result: PassResult): number {\n\tif (result.error) return 1;\n\tif (result.code !== null) return result.code;\n\treturn signalExitCode(result.signal);\n}\n\nexport interface ModulePassDetection {\n\tmodules: boolean;\n\t/** Why — surfaced in the startup log so the heuristic is never a mystery. */\n\treason: string;\n}\n\nexport interface DetectModulePassOptions {\n\tcwd?: string;\n\tmodulesMode?: string;\n\t/** Explicit override; wins over every heuristic. */\n\tmodules?: boolean;\n}\n\n/** Config file names probed for the module mode string, nearest-first. */\nconst VITE_CONFIG_FILES = [\n\t'vite.config.ts',\n\t'vite.config.mts',\n\t'vite.config.cts',\n\t'vite.config.js',\n\t'vite.config.mjs',\n\t'vite.config.cjs',\n];\n\n/**\n * Decide whether this package has a module pass.\n *\n * The commands deliberately do not import the user's Vite config (top-level\n * side effects) and cannot discover Script Module entries themselves — that\n * needs `blocksDir` / `adminPagesDir`, which only the config knows. So they\n * use a cheap, predictable, read-only heuristic:\n *\n * 1. an explicit `modules` option (`--modules` / `--no-modules`) wins;\n * 2. a `package.json` script whose command contains `--mode <modulesMode>`;\n * 3. a Vite config file whose source text contains the mode as a string\n * literal (`mode === 'modules'`, `'modules'` in a map, …).\n *\n * Everything else means \"script pass only\".\n */\nexport function detectModulePass(options: DetectModulePassOptions = {}): ModulePassDetection {\n\tif (typeof options.modules === 'boolean') {\n\t\treturn {\n\t\t\tmodules: options.modules,\n\t\t\treason: `explicit --${options.modules ? 'modules' : 'no-modules'} flag`,\n\t\t};\n\t}\n\n\tconst cwd = resolve(options.cwd ?? process.cwd());\n\tconst modulesMode = options.modulesMode ?? 'modules';\n\tconst escapedMode = escapeRegExp(modulesMode);\n\n\tconst scriptMatch = new RegExp(`(?:--mode[=\\\\s]+|(?:^|\\\\s)-m\\\\s+)${escapedMode}(?![\\\\w-])`);\n\tconst packageJson = readJson(join(cwd, 'package.json'));\n\tconst scripts = packageJson?.scripts;\n\tif (scripts && typeof scripts === 'object') {\n\t\tfor (const [name, command] of Object.entries(scripts as Record<string, unknown>)) {\n\t\t\tif (typeof command === 'string' && scriptMatch.test(command)) {\n\t\t\t\treturn {\n\t\t\t\t\tmodules: true,\n\t\t\t\t\treason: `package.json script \"${name}\" runs --mode ${modulesMode}`,\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t}\n\n\tconst configMatch = new RegExp(`(['\"\\`])${escapedMode}\\\\1`);\n\tfor (const fileName of VITE_CONFIG_FILES) {\n\t\tconst filePath = join(cwd, fileName);\n\t\tconst source = readFileIfExists(filePath);\n\t\tif (source === null) continue;\n\t\tif (configMatch.test(source)) {\n\t\t\treturn { modules: true, reason: `${fileName} mentions the \"${modulesMode}\" mode` };\n\t\t}\n\t\t// The nearest config wins — don't keep probing alternate extensions.\n\t\treturn {\n\t\t\tmodules: false,\n\t\t\treason: `${fileName} never mentions the \"${modulesMode}\" mode`,\n\t\t};\n\t}\n\n\treturn {\n\t\tmodules: false,\n\t\treason: `no package.json script or Vite config mentions the \"${modulesMode}\" mode`,\n\t};\n}\n\nexport interface ResolvedBin {\n\t/** Binary name, or the raw value when an explicit path was given. */\n\tname: string;\n\t/** What gets handed to `spawn`. */\n\tpath: string;\n}\n\n/**\n * Find the Vite CLI the consuming package would use.\n *\n * Walks `node_modules/.bin` from `cwd` upwards, so workspace packages find a\n * hoisted binary at the monorepo root. `vite` is preferred over `vp`: plain\n * Vite is present in every setup (Vite+ installs it too) and `vp build`'s\n * extra orchestration buys these commands nothing. Packages that need `vp` —\n * for its caching or remote-cache layer — pass `--bin vp`.\n */\nexport function resolveViteBin(\n\tcwd: string = process.cwd(),\n\tcandidates: readonly string[] = BIN_CANDIDATES,\n): ResolvedBin {\n\tconst searched: string[] = [];\n\tfor (const binDir of nodeModulesBinDirs(cwd)) {\n\t\tfor (const name of candidates) {\n\t\t\tfor (const fileName of binFileNames(name)) {\n\t\t\t\tconst candidatePath = join(binDir, fileName);\n\t\t\t\tsearched.push(candidatePath);\n\t\t\t\tif (existsSync(candidatePath)) return { name, path: candidatePath };\n\t\t\t}\n\t\t}\n\t}\n\tthrow new Error(\n\t\t`[wp-vite] could not find a Vite binary (${candidates.join(' or ')}) in any ` +\n\t\t\t`node_modules/.bin above ${cwd}. Install vite in the package, or pass --bin <name|path>. ` +\n\t\t\t`Looked at:\\n ${searched.join('\\n ')}`,\n\t);\n}\n\n/** Resolve the `bin` option: a path is used as-is, a bare name is looked up. */\nexport function resolveBin(bin: string | undefined, cwd: string): string {\n\tif (!bin) return resolveViteBin(cwd).path;\n\tif (isAbsolute(bin) || bin.includes('/') || bin.includes('\\\\')) return bin;\n\ttry {\n\t\treturn resolveViteBin(cwd, [bin]).path;\n\t} catch {\n\t\t// Not in node_modules/.bin — let the OS resolve it from PATH.\n\t\treturn bin;\n\t}\n}\n\n/** Every `node_modules/.bin` from `from` up to the filesystem root. */\nfunction nodeModulesBinDirs(from: string): string[] {\n\tconst dirs: string[] = [];\n\tlet current = resolve(from);\n\tconst { root } = parsePath(current);\n\twhile (true) {\n\t\tdirs.push(join(current, 'node_modules', '.bin'));\n\t\tif (current === root) break;\n\t\tconst parent = dirname(current);\n\t\tif (parent === current) break;\n\t\tcurrent = parent;\n\t}\n\treturn dirs;\n}\n\n/** Windows shims first, then the POSIX name. */\nfunction binFileNames(name: string): string[] {\n\treturn process.platform === 'win32' ? [`${name}.cmd`, name] : [name];\n}\n\n/**\n * Remove `outDir` — once, before any pass runs. Returns the absolute path that\n * was cleaned.\n */\nexport async function cleanOutDir(outDir = 'dist', cwd: string = process.cwd()): Promise<string> {\n\tconst base = resolve(cwd);\n\tconst target = isAbsolute(outDir) ? resolve(outDir) : resolve(base, outDir);\n\t// Never let a stray `--out-dir ..` or `--out-dir /` delete the world.\n\tif (target === parsePath(target).root || target === base || !target.startsWith(base + sep)) {\n\t\tthrow new Error(\n\t\t\t`[wp-vite] refusing to clean ${target}: the out dir must be inside ${base}`,\n\t\t);\n\t}\n\tawait rm(target, { recursive: true, force: true });\n\treturn target;\n}\n\nexport interface LinePrefixer {\n\t/** Feed a (possibly partial) chunk of child output. */\n\twrite(chunk: string): void;\n\t/** Emit a trailing line that never got its newline. */\n\tflush(): void;\n}\n\n/** Leading erase-line/erase-display sequences left over from CR redraws. */\nconst ESCAPE = String.fromCharCode(27);\nconst ERASE_SEQUENCE = new RegExp(`^(?:${ESCAPE}\\\\[[0-2]?[KJ])+`);\n\n/**\n * Prefix child output line by line. Chunks arrive on arbitrary boundaries, so\n * a partial trailing line is buffered until its newline shows up.\n *\n * Two cosmetic rules keep interleaved passes readable: blank lines pass\n * through unprefixed (Vite prints plenty, and `[script] ` alone is noise), and\n * a line redrawn with carriage returns is reduced to what a terminal would\n * actually show — the text after the last CR, minus the erase codes.\n */\nexport function createLinePrefixer(prefix: string, write: (text: string) => void): LinePrefixer {\n\tlet buffer = '';\n\tconst emit = (line: string) => {\n\t\t// A trailing CR is just CRLF; earlier CRs are redraws of the same line.\n\t\tconst withoutCrlf = line.endsWith('\\r') ? line.slice(0, -1) : line;\n\t\tconst rendered = withoutCrlf.split('\\r').pop() ?? '';\n\t\tconst content = rendered.replace(ERASE_SEQUENCE, '');\n\t\twrite(content.length === 0 ? '\\n' : `${prefix}${content}\\n`);\n\t};\n\treturn {\n\t\twrite(chunk: string) {\n\t\t\tbuffer += chunk;\n\t\t\tconst lines = buffer.split('\\n');\n\t\t\tbuffer = lines.pop() ?? '';\n\t\t\tfor (const line of lines) emit(line);\n\t\t},\n\t\tflush() {\n\t\t\tif (buffer.length === 0) return;\n\t\t\tconst pending = buffer;\n\t\t\tbuffer = '';\n\t\t\temit(pending);\n\t\t},\n\t};\n}\n\nexport interface ParsedCliArgs {\n\tcommand: string | undefined;\n\toptions: RunnerOptions;\n\thelp: boolean;\n\tversion: boolean;\n\t/** Flags that are not recognised — the CLI reports these and exits 1. */\n\tunknown: string[];\n}\n\n/**\n * Hand-rolled argv parser (no dependency). Supports:\n *\n * wp-vite <build|watch> [--out-dir dist] [--modules|--no-modules]\n * [--modules-mode modules] [--bin vite|vp|<path>]\n * [--no-clean] [--cwd <dir>] [-- <extra vite args>]\n *\n * `--flag=value` and `--flag value` are both accepted. Everything after a\n * bare `--` is forwarded verbatim to both Vite passes.\n */\nexport function parseCliArgs(argv: readonly string[]): ParsedCliArgs {\n\tconst parsed: ParsedCliArgs = {\n\t\tcommand: undefined,\n\t\toptions: {},\n\t\thelp: false,\n\t\tversion: false,\n\t\tunknown: [],\n\t};\n\tconst passthrough: string[] = [];\n\tlet index = 0;\n\n\tfor (; index < argv.length; index += 1) {\n\t\tconst arg = argv[index];\n\n\t\tif (arg === '--') {\n\t\t\tpassthrough.push(...argv.slice(index + 1));\n\t\t\tbreak;\n\t\t}\n\n\t\tif (!arg.startsWith('-')) {\n\t\t\tif (parsed.command === undefined) parsed.command = arg;\n\t\t\telse parsed.unknown.push(arg);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst equalsAt = arg.indexOf('=');\n\t\tconst flag = equalsAt === -1 ? arg : arg.slice(0, equalsAt);\n\t\tconst inlineValue = equalsAt === -1 ? undefined : arg.slice(equalsAt + 1);\n\t\tconst takeValue = (): string | undefined => {\n\t\t\tif (inlineValue !== undefined) return inlineValue;\n\t\t\tconst next = argv[index + 1];\n\t\t\tif (next === undefined || next.startsWith('-')) return undefined;\n\t\t\tindex += 1;\n\t\t\treturn next;\n\t\t};\n\n\t\tswitch (flag) {\n\t\t\tcase '-h':\n\t\t\tcase '--help':\n\t\t\t\tparsed.help = true;\n\t\t\t\tbreak;\n\t\t\tcase '-v':\n\t\t\tcase '--version':\n\t\t\t\tparsed.version = true;\n\t\t\t\tbreak;\n\t\t\tcase '--out-dir':\n\t\t\tcase '--outDir': {\n\t\t\t\tconst value = takeValue();\n\t\t\t\tif (value === undefined) parsed.unknown.push(`${flag} (missing value)`);\n\t\t\t\telse parsed.options.outDir = value;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase '--modules-mode':\n\t\t\tcase '--modulesMode': {\n\t\t\t\tconst value = takeValue();\n\t\t\t\tif (value === undefined) parsed.unknown.push(`${flag} (missing value)`);\n\t\t\t\telse parsed.options.modulesMode = value;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase '--bin': {\n\t\t\t\tconst value = takeValue();\n\t\t\t\tif (value === undefined) parsed.unknown.push(`${flag} (missing value)`);\n\t\t\t\telse parsed.options.bin = value;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase '--cwd': {\n\t\t\t\tconst value = takeValue();\n\t\t\t\tif (value === undefined) parsed.unknown.push(`${flag} (missing value)`);\n\t\t\t\telse parsed.options.cwd = value;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase '--modules':\n\t\t\t\tparsed.options.modules = true;\n\t\t\t\tbreak;\n\t\t\tcase '--no-modules':\n\t\t\t\tparsed.options.modules = false;\n\t\t\t\tbreak;\n\t\t\tcase '--clean':\n\t\t\t\tparsed.options.clean = true;\n\t\t\t\tbreak;\n\t\t\tcase '--no-clean':\n\t\t\t\tparsed.options.clean = false;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tparsed.unknown.push(flag);\n\t\t}\n\t}\n\n\tif (passthrough.length > 0) parsed.options.args = passthrough;\n\treturn parsed;\n}\n\n/**\n * Shared preamble: resolve the binary, decide on the module pass, clean the\n * out dir once, and log both decisions.\n */\nexport async function prepareRun(\n\toptions: RunnerOptions,\n\trunner: RunnerName,\n): Promise<{\n\tcwd: string;\n\tbin: string;\n\tmodulesMode: string;\n\tpasses: PassName[];\n\tstdout: OutputSink;\n\tstderr: OutputSink;\n}> {\n\tconst cwd = resolve(options.cwd ?? process.cwd());\n\tconst outDir = options.outDir ?? 'dist';\n\tconst modulesMode = options.modulesMode ?? 'modules';\n\tconst stdout = options.stdout ?? process.stdout;\n\tconst stderr = options.stderr ?? process.stderr;\n\n\tconst bin = resolveBin(options.bin, cwd);\n\tconst detection = detectModulePass({ cwd, modulesMode, modules: options.modules });\n\tconst passes: PassName[] = detection.modules ? ['script', 'modules'] : ['script'];\n\n\t// Cleaning here, once, is what lets every pass run with `--no-emptyOutDir`\n\t// and still start from an empty dist/.\n\tif (options.clean !== false) {\n\t\tconst cleaned = await cleanOutDir(outDir, cwd);\n\t\tstdout.write(`[wp-vite] cleaned ${cleaned}\\n`);\n\t}\n\n\tstdout.write(\n\t\t`[wp-vite] module pass ${detection.modules ? 'enabled' : 'disabled'} — ${detection.reason}; ` +\n\t\t\t`${runner === 'watch' ? 'watching' : 'building'} ${passes.join(runner === 'watch' ? ' + ' : ' then ')} via ${bin}\\n`,\n\t);\n\n\treturn { cwd, bin, modulesMode, passes, stdout, stderr };\n}\n\nfunction escapeRegExp(value: string): string {\n\treturn value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nfunction readFileIfExists(filePath: string): string | null {\n\ttry {\n\t\treturn readFileSync(filePath, 'utf8');\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction readJson(filePath: string): Record<string, unknown> | null {\n\tconst source = readFileIfExists(filePath);\n\tif (source === null) return null;\n\ttry {\n\t\treturn JSON.parse(source) as Record<string, unknown>;\n\t} catch {\n\t\treturn null;\n\t}\n}\n","/**\n * `wp-vite build` — one command that runs both passes of a dual-pass build.\n *\n * The documented shape is `vite build && vite build --mode modules`: two\n * invocations, chained, because both write into the same `dist/` and the\n * second pass is purely additive. That works, but every package has to spell\n * it out, remember the mode name, and get the `emptyOutDir` split right.\n *\n * This command:\n * 1. cleans the out dir once, itself;\n * 2. runs `<bin> build --no-emptyOutDir --no-clearScreen` to completion;\n * 3. then, iff the package has a module pass (see `detectModulePass`), runs\n * the same command with `--mode modules`;\n * 4. prefixes every child line with `[script] ` / `[modules] `;\n * 5. forwards SIGINT/SIGTERM to whichever pass is running;\n * 6. fails fast — a non-zero script pass skips the module pass and exits\n * with that code (the `&&` semantics, preserved).\n *\n * Sequential, not concurrent: both passes write into the same directory, and\n * `wpBlocks` / `wpCopyAssets` gate their file copying on the script pass, so\n * the module pass must observe a finished script pass.\n *\n * The watch counterpart is `watch()` in `./watch`; the machinery both share\n * lives in `./runner`.\n */\nimport type { ChildProcess } from 'node:child_process';\nimport {\n\tDEFAULT_BUILD_ARGS,\n\tdescribeExit,\n\tforwardSignals,\n\tpassArgs,\n\tpassExitCode,\n\tprepareRun,\n\tsignalExitCode,\n\tspawnPass,\n\ttype RunnerOptions,\n} from './runner';\n\n/**\n * The shared surface both commands expose, so a consumer can reach the\n * helpers from either subpath. The spawning/sequencing plumbing in `./runner`\n * stays internal.\n */\nexport {\n\tBIN_CANDIDATES,\n\tDEFAULT_BUILD_ARGS,\n\tDEFAULT_WATCH_ARGS,\n\tcleanOutDir,\n\tcreateLinePrefixer,\n\tdetectModulePass,\n\tparseCliArgs,\n\tresolveViteBin,\n} from './runner';\nexport type {\n\tDetectModulePassOptions,\n\tLinePrefixer,\n\tModulePassDetection,\n\tOutputSink,\n\tParsedCliArgs,\n\tPassName,\n\tResolvedBin,\n\tRunnerName,\n\tRunnerOptions,\n\tRunnerSignal,\n} from './runner';\n\n/** Options for `build()`. Identical to `watch()`'s — see `RunnerOptions`. */\nexport type BuildOptions = RunnerOptions;\n\n/**\n * Run both passes in order. Resolves with the process exit code: `0` when\n * every pass succeeded, the failing pass' code when one didn't, `128 + signo`\n * (`130` for SIGINT) when interrupted.\n */\nexport async function build(options: BuildOptions = {}): Promise<number> {\n\tconst { cwd, bin, modulesMode, passes, stdout, stderr } = await prepareRun(options, 'build');\n\n\tlet current: ChildProcess | undefined;\n\tlet interrupted = false;\n\tlet interruptCode = 0;\n\n\tconst disposeSignals =\n\t\toptions.handleSignals === false\n\t\t\t? () => {}\n\t\t\t: forwardSignals((signal) => {\n\t\t\t\t\tif (interrupted) return;\n\t\t\t\t\tinterrupted = true;\n\t\t\t\t\tinterruptCode = signalExitCode(signal);\n\t\t\t\t\tif (current && current.exitCode === null && current.signalCode === null) {\n\t\t\t\t\t\tcurrent.kill(signal);\n\t\t\t\t\t}\n\t\t\t\t});\n\n\ttry {\n\t\tfor (const [index, pass] of passes.entries()) {\n\t\t\tif (interrupted) {\n\t\t\t\tstderr.write(`[wp-vite] interrupted — skipping the ${pass} pass\\n`);\n\t\t\t\treturn interruptCode;\n\t\t\t}\n\n\t\t\tconst spawned = spawnPass({\n\t\t\t\tpass,\n\t\t\t\trunner: 'build',\n\t\t\t\tbin,\n\t\t\t\tcwd,\n\t\t\t\targv: passArgs(\n\t\t\t\t\toptions.buildArgs ?? DEFAULT_BUILD_ARGS,\n\t\t\t\t\tpass,\n\t\t\t\t\tmodulesMode,\n\t\t\t\t\toptions.args ?? [],\n\t\t\t\t),\n\t\t\t\tenv: options.env,\n\t\t\t\tstdout,\n\t\t\t\tstderr,\n\t\t\t});\n\t\t\tcurrent = spawned.child;\n\t\t\tconst result = await spawned.result;\n\t\t\tcurrent = undefined;\n\n\t\t\tconst code = passExitCode(result);\n\t\t\tif (code === 0) continue;\n\n\t\t\t// Fail fast: `&&` semantics. Name what got skipped so a CI log\n\t\t\t// doesn't look like the module pass silently vanished.\n\t\t\tconst skipped = passes.slice(index + 1);\n\t\t\tstderr.write(\n\t\t\t\t`[wp-vite] the ${pass} pass failed (${describeExit(result.code, result.signal)})` +\n\t\t\t\t\t(skipped.length > 0 ? ` — skipping the ${skipped.join(' and ')} pass` : '') +\n\t\t\t\t\t'\\n',\n\t\t\t);\n\t\t\treturn code;\n\t\t}\n\n\t\tstdout.write(\n\t\t\tpasses.length > 1\n\t\t\t\t? `[wp-vite] built ${passes.join(' + ')} into one dist\\n`\n\t\t\t\t: `[wp-vite] built the ${passes[0]} pass\\n`,\n\t\t);\n\t\treturn 0;\n\t} finally {\n\t\tdisposeSignals();\n\t}\n}\n"]}
package/dist/cli.js CHANGED
@@ -21,10 +21,27 @@ function spawnPass(options) {
21
21
  // `emptyOutDir: !isModulePass && !process.env.WP_VITE_UNIFIED_WATCH`.
22
22
  ...options.runner === "watch" ? { WP_VITE_UNIFIED_WATCH: "1" } : {}
23
23
  },
24
- stdio: ["ignore", "pipe", "pipe"],
24
+ stdio: options.inherit ? "inherit" : ["ignore", "pipe", "pipe"],
25
25
  // .cmd shims are not directly executable on Windows.
26
26
  shell: process.platform === "win32"
27
27
  });
28
+ if (options.inherit) {
29
+ const result2 = new Promise((settle) => {
30
+ let settled = false;
31
+ const finish = (passResult) => {
32
+ if (settled) return;
33
+ settled = true;
34
+ settle(passResult);
35
+ };
36
+ child.on("error", (error) => {
37
+ stderr.write(`[wp-vite] the ${pass} pass failed to start: ${error.message}
38
+ `);
39
+ finish({ pass, code: null, signal: null, error });
40
+ });
41
+ child.on("close", (code, signal) => finish({ pass, code, signal }));
42
+ });
43
+ return { pass, child, result: result2 };
44
+ }
28
45
  const outPrefixer = createLinePrefixer(`[${pass}] `, (text) => stdout.write(text));
29
46
  const errPrefixer = createLinePrefixer(`[${pass}] `, (text) => stderr.write(text));
30
47
  child.stdout?.setEncoding("utf8");
@@ -391,6 +408,57 @@ async function build(options = {}) {
391
408
  disposeSignals();
392
409
  }
393
410
  }
411
+ var DEFAULT_DEV_ARGS = ["dev", "--no-clearScreen"];
412
+ async function dev(options = {}) {
413
+ const cwd = resolve(options.cwd ?? process.cwd());
414
+ const stdout = options.stdout ?? process.stdout;
415
+ const stderr = options.stderr ?? process.stderr;
416
+ const bin = resolveBin(options.bin, cwd);
417
+ if (options.clean === true) {
418
+ const cleaned = await cleanOutDir(options.outDir ?? "dist", cwd);
419
+ stdout.write(`[wp-vite] cleaned ${cleaned}
420
+ `);
421
+ }
422
+ stdout.write(`[wp-vite] starting the dev server via ${bin}
423
+ `);
424
+ let current;
425
+ let interrupted = false;
426
+ const disposeSignals = options.handleSignals === false ? () => {
427
+ } : forwardSignals((signal) => {
428
+ if (interrupted) return;
429
+ interrupted = true;
430
+ if (current && current.exitCode === null && current.signalCode === null) {
431
+ current.kill(signal);
432
+ }
433
+ });
434
+ try {
435
+ const spawned = spawnPass({
436
+ pass: "dev",
437
+ runner: "dev",
438
+ bin,
439
+ cwd,
440
+ argv: [...options.devArgs ?? DEFAULT_DEV_ARGS, ...options.args ?? []],
441
+ env: options.env,
442
+ stdout,
443
+ stderr,
444
+ inherit: options.inherit !== false
445
+ });
446
+ current = spawned.child;
447
+ const result = await spawned.result;
448
+ current = void 0;
449
+ if (interrupted) return 0;
450
+ const code = passExitCode(result);
451
+ if (code !== 0) {
452
+ stderr.write(
453
+ `[wp-vite] the dev server exited (${describeExit(result.code, result.signal)})
454
+ `
455
+ );
456
+ }
457
+ return code;
458
+ } finally {
459
+ disposeSignals();
460
+ }
461
+ }
394
462
 
395
463
  // src/watch.ts
396
464
  async function watch(options = {}) {
@@ -458,9 +526,10 @@ var HELP = `
458
526
  Usage
459
527
  $ wp-vite build [options] [-- <extra vite args>]
460
528
  $ wp-vite watch [options] [-- <extra vite args>]
529
+ $ wp-vite dev [options] [-- <extra vite args>]
461
530
 
462
- Both commands drive the two passes of a dual-pass WordPress build \u2014 the
463
- script pass (\`vite build\`) and, when the package has module entries, the
531
+ \`build\` and \`watch\` drive the two passes of a dual-pass WordPress build \u2014
532
+ the script pass (\`vite build\`) and, when the package has module entries, the
464
533
  module pass (\`vite build --mode modules\`) \u2014 from a single process, after
465
534
  cleaning the out dir exactly once.
466
535
 
@@ -468,14 +537,19 @@ var HELP = `
468
537
  Fails fast: a failing pass skips the rest and exits with its code.
469
538
  watch Runs both passes concurrently as \`--watch\` processes and stays
470
539
  alive until interrupted.
540
+ dev Starts ONE \`vite\` dev server (no second pass \u2014 the wpDevServer
541
+ plugin serves classic scripts and Script Modules from the same
542
+ server) and writes the hot file WordPress reads. Does not clean
543
+ the out dir unless you ask with --clean.
471
544
 
472
545
  Options
473
546
  --out-dir <dir> Directory cleaned once at startup (default: dist).
474
547
  Must match \`build.outDir\` in the Vite config.
475
- --modules Force the module pass on.
476
- --no-modules Force the module pass off.
548
+ --modules Force the module pass on. (build/watch)
549
+ --no-modules Force the module pass off. (build/watch)
477
550
  --modules-mode <mode> \`--mode\` value for the module pass (default: modules).
478
551
  --bin <name|path> Vite CLI to run (default: vite, else vp).
552
+ --clean Clean the out dir at startup (dev: off by default).
479
553
  --no-clean Skip the startup clean of the out dir.
480
554
  --cwd <dir> Package directory to run in (default: cwd).
481
555
  -h, --help Show this message.
@@ -484,8 +558,10 @@ var HELP = `
484
558
  Examples
485
559
  $ wp-vite build
486
560
  $ wp-vite watch
561
+ $ wp-vite dev
487
562
  $ wp-vite build --bin vp --out-dir build
488
563
  $ wp-vite watch -- --minify false
564
+ $ wp-vite dev -- --port 5199
489
565
  `;
490
566
  async function runCli(argv) {
491
567
  const parsed = parseCliArgs(argv);
@@ -506,7 +582,7 @@ async function runCli(argv) {
506
582
  `);
507
583
  return 1;
508
584
  }
509
- if (parsed.command !== "build" && parsed.command !== "watch") {
585
+ if (parsed.command !== "build" && parsed.command !== "watch" && parsed.command !== "dev") {
510
586
  process.stderr.write(`[wp-vite] unknown command: ${parsed.command}
511
587
  `);
512
588
  process.stderr.write(`${HELP.trim()}
@@ -514,7 +590,9 @@ async function runCli(argv) {
514
590
  return 1;
515
591
  }
516
592
  try {
517
- return parsed.command === "build" ? await build(parsed.options) : await watch(parsed.options);
593
+ if (parsed.command === "build") return await build(parsed.options);
594
+ if (parsed.command === "watch") return await watch(parsed.options);
595
+ return await dev(parsed.options);
518
596
  } catch (error) {
519
597
  process.stderr.write(`${error instanceof Error ? error.message : String(error)}
520
598
  `);