@laurence79/wireit 0.14.13-shared-cache.0

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.
Files changed (54) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +1062 -0
  3. package/bin/wireit.js +9 -0
  4. package/lib/analyzer.js +1600 -0
  5. package/lib/caching/cache.js +7 -0
  6. package/lib/caching/github-actions-cache.js +832 -0
  7. package/lib/caching/local-cache.js +78 -0
  8. package/lib/caching/shared-cache.js +256 -0
  9. package/lib/cli-options.js +495 -0
  10. package/lib/cli.js +177 -0
  11. package/lib/config.js +18 -0
  12. package/lib/error.js +160 -0
  13. package/lib/event.js +7 -0
  14. package/lib/execution/base.js +108 -0
  15. package/lib/execution/no-command.js +32 -0
  16. package/lib/execution/service.js +1017 -0
  17. package/lib/execution/standard.js +683 -0
  18. package/lib/executor.js +249 -0
  19. package/lib/fingerprint.js +164 -0
  20. package/lib/ide.js +583 -0
  21. package/lib/language-server.js +135 -0
  22. package/lib/logging/combination-logger.js +41 -0
  23. package/lib/logging/debug-logger.js +43 -0
  24. package/lib/logging/logger.js +38 -0
  25. package/lib/logging/metrics-logger.js +108 -0
  26. package/lib/logging/quiet/run-tracker.js +597 -0
  27. package/lib/logging/quiet/stack-map.js +41 -0
  28. package/lib/logging/quiet/writeover-line.js +197 -0
  29. package/lib/logging/quiet-logger.js +78 -0
  30. package/lib/logging/simple-logger.js +296 -0
  31. package/lib/logging/watch-logger.js +81 -0
  32. package/lib/script-child-process.js +270 -0
  33. package/lib/util/ast.js +71 -0
  34. package/lib/util/async-cache.js +24 -0
  35. package/lib/util/copy.js +120 -0
  36. package/lib/util/deferred.js +35 -0
  37. package/lib/util/delete.js +120 -0
  38. package/lib/util/dispose.js +16 -0
  39. package/lib/util/fs.js +258 -0
  40. package/lib/util/glob.js +255 -0
  41. package/lib/util/line-monitor.js +69 -0
  42. package/lib/util/manifest.js +31 -0
  43. package/lib/util/optimize-mkdirs.js +55 -0
  44. package/lib/util/package-json-reader.js +61 -0
  45. package/lib/util/package-json.js +179 -0
  46. package/lib/util/script-data-dir.js +19 -0
  47. package/lib/util/shuffle.js +16 -0
  48. package/lib/util/unreachable.js +12 -0
  49. package/lib/util/windows.js +87 -0
  50. package/lib/util/worker-pool.js +61 -0
  51. package/lib/watcher.js +396 -0
  52. package/package.json +470 -0
  53. package/schema.json +132 -0
  54. package/wireit.svg +1 -0
package/README.md ADDED
@@ -0,0 +1,1062 @@
1
+ <div align="center">
2
+
3
+ <img src="wireit.svg" height="125" alt="wireit"/>
4
+
5
+ _Wireit upgrades your npm scripts to make them smarter and more efficient._
6
+
7
+ [![Published on npm](https://img.shields.io/npm/v/wireit.svg?logo=npm)](https://www.npmjs.com/package/wireit)
8
+ [![Build Status](https://github.com/google/wireit/actions/workflows/tests.yml/badge.svg)](https://github.com/google/wireit/actions/workflows/tests.yml)
9
+ [![Discord](https://discordapp.com/api/guilds/1036766782867914792/widget.png?style=shield)](https://discord.gg/chmdAwvq4e)
10
+
11
+ </div>
12
+
13
+ ## Features
14
+
15
+ - 🙂 Use the `npm run` commands you already know
16
+ - ⛓️ Automatically run dependencies between npm scripts in parallel
17
+ - 👀 Watch any script and continuously re-run on changes
18
+ - 🥬 Skip scripts that are already fresh
19
+ - ♻️ Cache output locally and remotely on GitHub Actions for free
20
+ - 🛠️ Works with single packages, npm workspaces, and other monorepos
21
+ - ✏️ [VSCode plugin](https://marketplace.visualstudio.com/items?itemName=google.wireit) gives suggestions, documentation, and warnings as you develop
22
+
23
+ ## Contents
24
+
25
+ - [Features](#features)
26
+ - [Install](#install)
27
+ - [Setup](#setup)
28
+ - [VSCode Extension](#vscode-extension)
29
+ - [Discord](#discord)
30
+ - [Dependencies](#dependencies)
31
+ - [Vanilla scripts](#vanilla-scripts)
32
+ - [Cross-package dependencies](#cross-package-dependencies)
33
+ - [Parallelism](#parallelism)
34
+ - [Extra arguments](#extra-arguments)
35
+ - [Input and output files](#input-and-output-files)
36
+ - [Example configuration](#example-configuration)
37
+ - [Default excluded paths](#default-excluded-paths)
38
+ - [Incremental build](#incremental-build)
39
+ - [Caching](#caching)
40
+ - [Local caching](#local-caching)
41
+ - [GitHub Actions caching](#github-actions-caching)
42
+ - [Shared caching](#shared-caching)
43
+ - [Cleaning output](#cleaning-output)
44
+ - [Watch mode](#watch-mode)
45
+ - [Services](#services)
46
+ - [Execution cascade](#execution-cascade)
47
+ - [Environment variables](#environment-variables)
48
+ - [Failures and errors](#failures-and-errors)
49
+ - [Package locks](#package-locks)
50
+ - [Recipes](#recipes)
51
+ - [TypeScript](#typescript)
52
+ - [ESLint](#eslint)
53
+ - [Reference](#reference)
54
+ - [Configuration](#configuration)
55
+ - [Dependency syntax](#dependency-syntax)
56
+ - [Environment variable reference](#environment-variable-reference)
57
+ - [Glob patterns](#glob-patterns)
58
+ - [Fingerprint](#fingerprint)
59
+ - [Requirements](#requirements)
60
+ - [Related tools](#related-tools)
61
+ - [Contributing](#contributing)
62
+
63
+ ## Install
64
+
65
+ ```sh
66
+ npm i -D wireit
67
+ ```
68
+
69
+ ## Setup
70
+
71
+ Wireit works _with_ `npm run`, it doesn't replace it. To configure an NPM script
72
+ for Wireit, move the command into a new `wireit` section of your `package.json`,
73
+ and replace the original script with the `wireit` command.
74
+
75
+ <table>
76
+ <tr>
77
+ <th>Before</th>
78
+ <th>After</th>
79
+ </tr>
80
+ <tr>
81
+ <td>
82
+ <pre lang="json">
83
+ {
84
+ "scripts": {
85
+ "build": "tsc"
86
+ }
87
+ }
88
+ </pre>
89
+ </td>
90
+ <td>
91
+ <pre lang="json">
92
+ {
93
+ "scripts": {
94
+ "build": "wireit"
95
+ },
96
+ "wireit": {
97
+ "build": {
98
+ "command": "tsc"
99
+ }
100
+ }
101
+ }
102
+ </pre>
103
+ </td>
104
+ </tr>
105
+ </table>
106
+
107
+ Now when you run `npm run build`, Wireit upgrades the script to be smarter and
108
+ more efficient. Wireit also works with [`node --run`](https://nodejs.org/en/blog/announcements/v22-release-announce#running-packagejson-scripts), [yarn](https://yarnpkg.com/), and [pnpm](https://pnpm.io/).
109
+
110
+ You should also add `.wireit` to your `.gitignore` file. Wireit uses the
111
+ `.wireit` directory to store caches and other data for your scripts.
112
+
113
+ ```sh
114
+ echo .wireit >> .gitignore
115
+ ```
116
+
117
+ ## VSCode Extension
118
+
119
+ If you use VSCode, consider installing the `google.wireit` extension. It adds documentation on hover, autocomplete, can diagnose a number of common mistakes, and even suggest a refactoring to convert an npm script to use wireit.
120
+
121
+ Install it [from the marketplace](https://marketplace.visualstudio.com/items?itemName=google.wireit) or on the command line like:
122
+
123
+ ```sh
124
+ code --install-extension google.wireit
125
+ ```
126
+
127
+ ## Discord
128
+
129
+ Join the [Wireit Discord](https://discord.gg/chmdAwvq4e) to chat with the Wireit community and get support for your project.
130
+
131
+ [![Discord](https://discordapp.com/api/guilds/1036766782867914792/widget.png?style=banner2)](https://discord.gg/chmdAwvq4e)
132
+
133
+ ## Dependencies
134
+
135
+ To declare a dependency between two scripts, edit the
136
+ `wireit.<script>.dependencies` list:
137
+
138
+ ```json
139
+ {
140
+ "scripts": {
141
+ "build": "wireit",
142
+ "bundle": "wireit"
143
+ },
144
+ "wireit": {
145
+ "build": {
146
+ "command": "tsc"
147
+ },
148
+ "bundle": {
149
+ "command": "rollup -c",
150
+ "dependencies": ["build"]
151
+ }
152
+ }
153
+ }
154
+ ```
155
+
156
+ Now when you run `npm run bundle`, the `build` script will automatically run
157
+ first.
158
+
159
+ ### Vanilla scripts
160
+
161
+ The scripts you depend on don't need to be configured for Wireit, they can be
162
+ vanilla `npm` scripts. This lets you only use Wireit for some of your scripts,
163
+ or to upgrade incrementally. Scripts that haven't been configured for Wireit are
164
+ always safe to use as dependencies; they just won't be fully optimized.
165
+
166
+ ### Wireit-only scripts
167
+
168
+ It is valid to define a script in the `wireit` section that is not in the
169
+ `scripts` section, but such scripts can only be used as `dependencies` from
170
+ other wireit scripts, and can never be run directly.
171
+
172
+ ### Cross-package dependencies
173
+
174
+ Dependencies can refer to scripts in other npm packages by using a relative path
175
+ with the syntax `<relative-path>:<script-name>`. All cross-package dependencies
176
+ should start with a `"."`. Cross-package dependencies work well for npm
177
+ workspaces, as well as in other kinds of monorepos.
178
+
179
+ ```json
180
+ {
181
+ "scripts": {
182
+ "build": "wireit"
183
+ },
184
+ "wireit": {
185
+ "build": {
186
+ "command": "tsc",
187
+ "dependencies": ["../other-package:build"]
188
+ }
189
+ }
190
+ }
191
+ ```
192
+
193
+ ## Parallelism
194
+
195
+ Wireit will run scripts in parallel whenever it is safe to do so according to
196
+ the dependency graph.
197
+
198
+ For example, in this diagram, the `B` and `C` scripts will run in parallel,
199
+ while the `A` script won't start until both `B` and `C` finish.
200
+
201
+ ```mermaid
202
+ graph TD
203
+ A-->B;
204
+ A-->C;
205
+ subgraph parallel
206
+ B;
207
+ C;
208
+ end
209
+ ```
210
+
211
+ By default, Wireit will run up to 2 scripts in parallel for every logical CPU
212
+ core detected on your system. To change this default, set the `WIREIT_PARALLEL`
213
+ [environment variable](#environment-variable-reference) to a positive integer, or
214
+ `infinity` to run without a limit. You may want to lower this number if you
215
+ experience resource starvation in large builds. For example, to run only one
216
+ script at a time:
217
+
218
+ ```sh
219
+ export WIREIT_PARALLEL=1
220
+ npm run build
221
+ ```
222
+
223
+ If two or more separate `npm run` commands are run for the same Wireit script
224
+ simultaneously, then only one instance will be allowed to run at a time, while
225
+ the others wait their turn. This prevents coordination problems that can result
226
+ in incorrect output files being produced. If `output` is set to an empty array,
227
+ then this restriction is removed.
228
+
229
+ ## Extra arguments
230
+
231
+ As with plain npm scripts, you can pass extra arguments to a Wireit script by
232
+ placing a `--` double-dash argument in front of them. Any arguments after a `--`
233
+ are sent to the underlying command, instead of being interpreted as arguments to
234
+ npm or Wireit:
235
+
236
+ ```sh
237
+ npm run build -- --verbose
238
+ ```
239
+
240
+ Or in general:
241
+
242
+ ```sh
243
+ npm run {script} {npm args} {wireit args} -- {script args}
244
+ ```
245
+
246
+ An additional `--` is required when using `node --run` in order to distinguish
247
+ between arguments intended for `node`, `wireit`, and the script itself:
248
+
249
+ ```sh
250
+ node --run {script} {node args} -- {wireit args} -- {script args}
251
+ ```
252
+
253
+ ## Input and output files
254
+
255
+ The `files` and `output` properties of `wireit.<script>` tell Wireit what your
256
+ script's input and output files are, respectively. They should be arrays of
257
+ [glob patterns](#glob-patterns), where paths are interpreted relative to the
258
+ package directory. They can be set on some, all, or none of your scripts.
259
+
260
+ Setting these properties allow you to use more features of Wireit:
261
+
262
+ | | Requires<br>`files` | Requires<br>`output` |
263
+ | ------------------------------------------: | :-----------------: | :------------------: |
264
+ | [**Dependency graph**](#dependencies) | - | - |
265
+ | [**Watch mode**](#watch-mode) | ☑️ | - |
266
+ | [**Clean build**](#cleaning-output) | - | ☑️ |
267
+ | [**Incremental build**](#incremental-build) | ☑️ | ☑️ |
268
+ | [**Caching**](#caching) | ☑️ | ☑️ |
269
+
270
+ ### Example configuration
271
+
272
+ ```json
273
+ {
274
+ "scripts": {
275
+ "build": "wireit",
276
+ "bundle": "wireit"
277
+ },
278
+ "wireit": {
279
+ "build": {
280
+ "command": "tsc",
281
+ "files": ["src/**/*.ts", "tsconfig.json"],
282
+ "output": ["lib/**"]
283
+ },
284
+ "bundle": {
285
+ "command": "rollup -c",
286
+ "dependencies": ["build"],
287
+ "files": ["rollup.config.json"],
288
+ "output": ["dist/bundle.js"]
289
+ }
290
+ }
291
+ }
292
+ ```
293
+
294
+ ### Default excluded paths
295
+
296
+ By default, the following folders are excluded from the `files` and `output`
297
+ arrays:
298
+
299
+ - `.git/`
300
+ - `.hg/`
301
+ - `.svn/`
302
+ - `.wireit/`
303
+ - `.yarn/`
304
+ - `CVS/`
305
+ - `node_modules/`
306
+
307
+ In the highly unusual case that you need to reference a file in one of those
308
+ folders, set `allowUsuallyExcludedPaths: true` to remove all default excludes.
309
+
310
+ ## Incremental build
311
+
312
+ Wireit can automatically skip execution of a script if nothing has changed that
313
+ would cause it to produce different output since the last time it ran. This is
314
+ called _incremental build_.
315
+
316
+ To enable incremental build, configure the input and output files for each
317
+ script by specifying [glob patterns](#glob-patterns) in the
318
+ `wireit.<script>.files` and `wireit.<script>.output` arrays.
319
+
320
+ > ℹ️ If a script doesn't have a `files` or `output` list defined at all, then it
321
+ > will _always_ run, because Wireit doesn't know which files to check for
322
+ > changes. To tell Wireit it is safe to skip execution of a script that
323
+ > definitely has no input and/or files, set `files` and/or `output` to an empty
324
+ > array (`files: [], output: []`).
325
+
326
+ ## Caching
327
+
328
+ If a script has previously succeeded with the same configuration and input
329
+ files, then Wireit can copy the output from a cache, instead of running the
330
+ command. This can significantly improve build and test time.
331
+
332
+ To enable caching for a script, ensure you have defined both the [`files` and
333
+ `output`](#input-and-output-files) arrays.
334
+
335
+ > ℹ️ If a script doesn't produce any output files, it can still be cached by
336
+ > setting `output` to an empty array (`"output": []`). Empty output is common for
337
+ > tests, and is useful because it allows you to skip running tests if they
338
+ > previously passed with the exact same inputs.
339
+
340
+ ### Local caching
341
+
342
+ In _local_ mode, Wireit caches `output` files to the `.wireit` folder inside
343
+ each of your packages.
344
+
345
+ Local caching is enabled by default, unless the
346
+ [`CI=true`](https://docs.github.com/en/enterprise-cloud@latest/actions/learn-github-actions/environment-variables#default-environment-variables)
347
+ environment variable is detected. To force local caching, set
348
+ `WIREIT_CACHE=local`. To disable local caching, set `WIREIT_CACHE=none`.
349
+
350
+ > ⚠️ Wireit does not currently limit the size of local caches. To free up this
351
+ > space, use `rm -rf .wireit/*/cache`. Automatic cache size limits will be added
352
+ > in an upcoming release, tracked at
353
+ > [wireit#71](https://github.com/google/wireit/issues/71).
354
+
355
+ ### GitHub Actions caching
356
+
357
+ In _[GitHub Actions](https://github.com/features/actions)_ mode, Wireit caches
358
+ `output` files to the [GitHub Actions
359
+ cache](https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows)
360
+ service. This service is available whenever running in GitHub Actions, and is
361
+ free for all GitHub users.
362
+
363
+ > ℹ️ GitHub Actions cache entries are automatically deleted after 7 days, or if
364
+ > total usage exceeds 10 GB (the least recently used cache entry is deleted
365
+ > first). See the [GitHub Actions
366
+ > documentation](https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#usage-limits-and-eviction-policy)
367
+ > for more details.
368
+
369
+ To enable caching on GitHub Actions, add the following
370
+ [`uses`](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsuses)
371
+ clause to your workflow. It can appear anywhere before the first `npm run` or
372
+ `npm test` command:
373
+
374
+ ```yaml
375
+ - uses: google/wireit@setup-github-actions-caching/v2
376
+ ```
377
+
378
+ #### Example workflow
379
+
380
+ ```yaml
381
+ # File: .github/workflows/tests.yml
382
+
383
+ name: Tests
384
+ on: [push, pull_request]
385
+ jobs:
386
+ tests:
387
+ runs-on: ubuntu-latest
388
+ steps:
389
+ - uses: actions/checkout@v6
390
+ - uses: actions/setup-node@v6
391
+ with:
392
+ node-version: 24
393
+ cache: npm
394
+
395
+ # Set up GitHub Actions caching for Wireit.
396
+ - uses: google/wireit@setup-github-actions-caching/v2
397
+
398
+ # Install npm dependencies.
399
+ - run: npm ci
400
+
401
+ # Run tests. Wireit will automatically use
402
+ # the GitHub Actions cache whenever possible.
403
+ - run: npm test
404
+ ```
405
+
406
+ ### Shared caching
407
+
408
+ In _shared_ mode, Wireit caches `output` files to a single
409
+ [content-addressed](https://en.wikipedia.org/wiki/Content-addressable_storage)
410
+ directory that lives outside your working tree, at a stable path. Because the
411
+ location is stable and writes are multi-writer-safe, this cache survives across
412
+ builds and can be shared between multiple build agents running on one long-lived
413
+ machine, each with its own checkout. Set `WIREIT_CACHE=shared` to enable it.
414
+
415
+ ```sh
416
+ WIREIT_CACHE=shared npm run build
417
+ ```
418
+
419
+ By default the cache is stored in `~/.wireit/cache`. Set
420
+ `WIREIT_CACHE_SHARED_DIR` to use a different location:
421
+
422
+ ```sh
423
+ WIREIT_CACHE_SHARED_DIR=/srv/wireit-cache WIREIT_CACHE=shared npm run build
424
+ ```
425
+
426
+ Entries are keyed only by Wireit's [fingerprint](#incremental-build) — the
427
+ command, input file contents, declared `env`, lockfiles, platform, and Node
428
+ version — and never by the package or script name. So two packages (or two
429
+ agents) that build the exact same thing automatically share a single cache
430
+ entry. Restores are always a copy, and use
431
+ [copy-on-write](https://en.wikipedia.org/wiki/Copy-on-write) (reflink)
432
+ automatically when the cache directory and your working tree are on the same
433
+ filesystem.
434
+
435
+ A shared-cache problem can only make a build slower, never broken: an
436
+ unwritable or unavailable cache directory degrades to read-only (or disables
437
+ caching) and the build proceeds. Wireit prints a one-line status at startup, for
438
+ example `ℹ️ Shared cache: /home/me/.wireit/cache (read-write)`.
439
+
440
+ For untrusted writers, set `WIREIT_CACHE_SHARED_READONLY=true` so that `get()`
441
+ still restores from the cache but `set()` becomes a no-op:
442
+
443
+ ```sh
444
+ WIREIT_CACHE_SHARED_READONLY=true WIREIT_CACHE=shared npm run build
445
+ ```
446
+
447
+ > ⚠️ **Trust boundary.** Anyone who can write to the shared cache directory can
448
+ > poison it: a malicious build that writes a cache entry can have its output
449
+ > restored into a later, trusted build that produces the same fingerprint (see
450
+ > [CVE-2025-36852](https://nvd.nist.gov/vuln/detail/CVE-2025-36852)). Content
451
+ > addressing and integrity hashing do **not** prevent this, because an
452
+ > authorized writer controls the content. Only point `WIREIT_CACHE_SHARED_DIR`
453
+ > at a directory shared by builds you trust equally. The conservative default of
454
+ > `~/.wireit/cache` scopes sharing to a single OS user. To share across users,
455
+ > gate writes with filesystem permissions: have the trusted-build user own and
456
+ > write the directory, and give untrusted builds at most read access (plus
457
+ > `WIREIT_CACHE_SHARED_READONLY=true`). On Windows, use directory ACLs or
458
+ > separate cache directories per trust level.
459
+
460
+ > ⚠️ Wireit does not limit the size of the shared cache, and does not evict
461
+ > entries (tracked at [wireit#71](https://github.com/google/wireit/issues/71)).
462
+ > Because entries are restored with a copy, their access times stay meaningful,
463
+ > so you can reap stale entries with an external `atime`-based job, for example a
464
+ > daily cron:
465
+ >
466
+ > ```sh
467
+ > # Delete entries not read in the last 14 days.
468
+ > find /srv/wireit-cache -mindepth 3 -maxdepth 3 -type d -atime +14 \
469
+ > -exec rm -rf {} +
470
+ > ```
471
+
472
+ ## Cleaning output
473
+
474
+ Wireit can automatically delete output files from previous runs before executing
475
+ a script. This is helpful for ensuring that every build is clean and free from
476
+ outdated files created in previous runs from source files that have since been
477
+ removed.
478
+
479
+ Cleaning is enabled by default as long as the
480
+ [`output`](#input-and-output-files) array is defined. To change this behavior,
481
+ set the `wireit.<script>.clean` property to one of these values:
482
+
483
+ | Setting | Description |
484
+ | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
485
+ | `true` | Clean before every run (the default). |
486
+ | `"if-file-deleted"` | Clean only if an input file has been deleted since the last run.<br><br>Use this option for tools that have incremental build support, but do not clean up outdated output when a source file has been deleted, such as `tsc --build` (see [TypeScript](#typescript) for more on this example.) |
487
+ | `false` | Do not clean.<br><br>Only use this option if you are certain that the script command itself already takes care of removing outdated files from previous runs. |
488
+
489
+ ## Watch mode
490
+
491
+ In _watch_ mode, Wireit monitors all `files` of a script, and all `files` of its
492
+ transitive dependencies, and when there is a change, it re-runs only the
493
+ affected scripts. To enable watch mode, first ensure that the
494
+ [`files`](#input-and-output-files) array is defined, and then run:
495
+
496
+ ```sh
497
+ WIREIT_WATCH=true npm run <script>
498
+ ```
499
+
500
+ The benefit of Wireit's watch mode over the built-in watch modes of Node and other programs are:
501
+
502
+ - Wireit watches the entire dependency graph, so a single watch command replaces
503
+ many built-in ones.
504
+ - It prevents problems that can occur when running many separate watch commands
505
+ simultaneously, such as build steps being triggered before all preceding steps
506
+ have finished.
507
+
508
+ By default, watch mode uses whichever filesystem change API is available on your
509
+ OS. This behavior can be changed with the `WIREIT_WATCH_STRATEGY` and
510
+ `WIREIT_WATCH_POLL_MS` environment variables (see
511
+ [below](#environment-variable-reference)).
512
+
513
+ ## Environment variables
514
+
515
+ Use the `env` setting to either directly set environment variables, or to
516
+ indicate that an externally-defined environment variable affects the behavior of
517
+ a script.
518
+
519
+ ### Setting environment variables directly
520
+
521
+ If a property value in the `env` object is a string, then that environment
522
+ variable will be set to that value when the script's `command` runs,
523
+ overriding any value from the parent process.
524
+
525
+ Unlike built-in shell environment variable syntaxes, using `env` to set
526
+ environment variables works the same in macOS/Linux vs Windows, and in all
527
+ shells.
528
+
529
+ > **Note** Setting an environment variable with `env` does not apply
530
+ > transitively through dependencies. If you need the same environment variable
531
+ > to be set for multiple scripts, you must configure it for each of them.
532
+
533
+ ```json
534
+ {
535
+ "wireit": {
536
+ "my-script": {
537
+ "command": "my-command",
538
+ "env": {
539
+ "MY_VARIABLE": "my value"
540
+ }
541
+ }
542
+ }
543
+ }
544
+ ```
545
+
546
+ ### Indicating external environment variables
547
+
548
+ If an environment variable affects the behavior of a script but is set
549
+ _externally_ (i.e. it is passed to the `wireit` parent process), set the `env`
550
+ property to `{"external": true}`. This tells Wireit that if the value of an
551
+ environment variable changes across executions of a script, then its output
552
+ should not be re-used. You may also set a `default` value for the variable
553
+ to use when none is provided externally.
554
+
555
+ ```json
556
+ {
557
+ "wireit": {
558
+ "my-script": {
559
+ "command": "my-command",
560
+ "env": {
561
+ "MY_VARIABLE": {
562
+ "external": true
563
+ },
564
+ "MY_VARIABLE_2": {
565
+ "external": true,
566
+ "default": "foo"
567
+ }
568
+ }
569
+ }
570
+ }
571
+ }
572
+ ```
573
+
574
+ ## Services
575
+
576
+ By default, Wireit assumes that your scripts will eventually exit by themselves.
577
+ This is well suited for build and test scripts, but not for long-running
578
+ processes like servers. To tell Wireit that a process is long-running and not
579
+ expected to exit by itself, set `"service": true`.
580
+
581
+ ```json
582
+ {
583
+ "scripts": {
584
+ "start": "wireit",
585
+ "build:server": "wireit"
586
+ },
587
+ "wireit": {
588
+ "start": {
589
+ "command": "node my-server.js",
590
+ "service": true,
591
+ "files": ["my-server.js"],
592
+ "dependencies": [
593
+ "build:server",
594
+ {
595
+ "script": "../assets:build",
596
+ "cascade": false
597
+ }
598
+ ]
599
+ },
600
+ "build:server": {
601
+ ...
602
+ }
603
+ }
604
+ }
605
+ ```
606
+
607
+ ### Service lifetime
608
+
609
+ If a service is run _directly_ (e.g. `npm run serve`), then it will stay running
610
+ until the user kills Wireit (e.g. `Ctrl-C`).
611
+
612
+ If a service is a _dependency_ of one or more other scripts, then it will start
613
+ up before any depending script runs, and will shut down after all depending
614
+ scripts finish.
615
+
616
+ ### Service readiness
617
+
618
+ By default, a service is considered _ready_ as soon as its process spawns,
619
+ allowing any scripts that depend on that service to start.
620
+
621
+ However, often times a service needs to perform certain actions before it is
622
+ safe for dependents to interact with it, such as starting a server and listening
623
+ on a network interface.
624
+
625
+ Use `service.readyWhen.lineMatches` to tell Wireit to monitor the `stdout` and
626
+ `stderr` of the service and defer readiness until a line is printed that matches
627
+ the given regular expression.
628
+
629
+ ```json
630
+ {
631
+ "command": "node my-server.js",
632
+ "service": {
633
+ "readyWhen": {
634
+ "lineMatches": "Server listening on port \\d+"
635
+ }
636
+ }
637
+ }
638
+ ```
639
+
640
+ ### Service restarts
641
+
642
+ In watch mode, a service will be restarted whenever one of its input files or
643
+ dependencies change, except for dependencies with
644
+ [`cascade`](#execution-cascade) set to `false`.
645
+
646
+ ### Service output
647
+
648
+ Services cannot have `output` files, because there is no way for Wireit to know
649
+ when a service has finished writing its output.
650
+
651
+ If you have a service that produces output, you should define a _non-service_
652
+ script that depends on it, and which exits when the service's output is
653
+ complete.
654
+
655
+ ## Execution cascade
656
+
657
+ By default, a script always needs to run (or restart in the case of
658
+ [`services`](#services)) if any of its dependencies needed to run, _regardless
659
+ of whether the dependency produced new or relevant output_.
660
+
661
+ This automatic _cascade_ of script execution is the default behavior because it
662
+ ensures that any _possible_ output produced by a dependent script propagates to all other
663
+ scripts that might depend on it. In other words, Wireit does not assume that the
664
+ `files` array completely describes the inputs to a script with dependencies.
665
+
666
+ ### Disabling cascade
667
+
668
+ This execution cascade behavior can be disabled by expanding a dependency into
669
+ an object, and setting the `cascade` property to `false`:
670
+
671
+ > **Note**
672
+ > What really happens under the hood is that the `cascade` property simply controls
673
+ > whether the [fingerprint](#fingerprint) of a script _includes the fingerprints
674
+ > of its dependencies_, which in turn determines whether a script needs to run or restart.
675
+
676
+ ```json
677
+ {
678
+ "dependencies": [
679
+ {
680
+ "script": "foo",
681
+ "cascade": false
682
+ }
683
+ ]
684
+ }
685
+ ```
686
+
687
+ ### Reasons to disable cascade
688
+
689
+ There are two main reasons you might want to set `cascade` to `false`:
690
+
691
+ 1. **Your script only consumes a subset of a dependency's output.**
692
+
693
+ For example, `tsc` produces both `.js` files and `.d.ts` files, but only the
694
+ `.js` files might be consumed by `rollup`. There is no need to re-bundle
695
+ when a typings-only changed occurred.
696
+
697
+ > **Note**
698
+ > In addition to setting `cascade` to `false`, the subset of output that
699
+ > _does_ matter (`lib/**/*.js`) has been added to the `files` array.
700
+
701
+ ```json
702
+ {
703
+ "scripts": {
704
+ "build": "wireit",
705
+ "bundle": "wireit"
706
+ },
707
+ "wireit": {
708
+ "build": {
709
+ "command": "tsc",
710
+ "files": ["src/**/*.ts", "tsconfig.json"],
711
+ "output": ["lib/**"]
712
+ },
713
+ "bundle": {
714
+ "command": "rollup -c",
715
+ "dependencies": [
716
+ {
717
+ "script": "build",
718
+ "cascade": false
719
+ }
720
+ ],
721
+ "files": ["rollup.config.json", "lib/**/*.js"],
722
+ "output": ["dist/bundle.js"]
723
+ }
724
+ }
725
+ }
726
+ ```
727
+
728
+ 2. **Your server doesn't need to restart for certain changes.**
729
+
730
+ For example, a web server depends on some static assets, but the server
731
+ reads those assets from disk dynamically on each request. In [`watch`](#watch-mode) mode,
732
+ there is no need to restart the server when the assets change.
733
+
734
+ > **Note**
735
+ > The `build:server` dependency uses the default `cascade` behavior
736
+ > (`true`), because changing the implementation of the server itself _does_
737
+ > require the server to be restarted.
738
+
739
+ ```json
740
+ {
741
+ "scripts": {
742
+ "start": "wireit",
743
+ "build:server": "wireit"
744
+ },
745
+ "wireit": {
746
+ "start": {
747
+ "command": "node lib/server.js",
748
+ "service": true,
749
+ "dependencies": [
750
+ "build:server",
751
+ {
752
+ "script": "../assets:build",
753
+ "cascade": false
754
+ }
755
+ ],
756
+ "files": ["lib/**/*.js"]
757
+ },
758
+ "build:server": {
759
+ "command": "tsc",
760
+ "files": ["src/**/*.ts", "tsconfig.json"],
761
+ "output": ["lib/**"]
762
+ }
763
+ }
764
+ }
765
+ ```
766
+
767
+ ## Failures and errors
768
+
769
+ By default, when a script fails (meaning it returned with a non-zero exit code),
770
+ all scripts that are already running are allowed to finish, but new scripts are
771
+ not started.
772
+
773
+ In some situations a different behavior may be better suited. There are 2
774
+ additional modes, which you can set with the `WIREIT_FAILURES` environment
775
+ variable. Note that Wireit always ultimately exits with a non-zero exit code if
776
+ there was a failure, regardless of the mode.
777
+
778
+ ### Continue
779
+
780
+ When a failure occurs in `continue` mode, running scripts continue, and new
781
+ scripts are started as long as the failure did not affect their dependencies.
782
+ This mode is useful if you want a complete picture of which scripts are
783
+ succeeding and which are failing.
784
+
785
+ ```bash
786
+ WIREIT_FAILURES=continue
787
+ ```
788
+
789
+ ### Kill
790
+
791
+ When a failure occurs in `kill` mode, running scripts are immediately killed,
792
+ and new scripts are not started. This mode is useful if you want to be notified
793
+ as soon as possible about any failures.
794
+
795
+ ```bash
796
+ WIREIT_FAILURES=kill
797
+ ```
798
+
799
+ ## Package locks
800
+
801
+ By default, Wireit automatically treats package manager lock files as input
802
+ files
803
+ ([`package-lock.json`](https://docs.npmjs.com/cli/v8/configuring-npm/package-lock-json)
804
+ for npm and `node --run`,
805
+ [`yarn.lock`](https://yarnpkg.com/configuration/yarnrc#lockfileFilename) for
806
+ yarn, and [`pnpm-lock.yaml`](https://pnpm.io/git#lockfiles) for pnpm). Wireit
807
+ will look for these lock files in the script's package, and all parent
808
+ directories.
809
+
810
+ This is useful because installing or upgrading your dependencies can affect the
811
+ behavior of your scripts, so it's important to re-run them whenever your
812
+ dependencies change.
813
+
814
+ To change the name of the package lock file Wireit should look for, specify it
815
+ in the `wireit.<script>.packageLocks` array. You can specify multiple filenames
816
+ here, if needed.
817
+
818
+ ```json
819
+ {
820
+ "scripts": {
821
+ "build": "wireit"
822
+ },
823
+ "wireit": {
824
+ "build": {
825
+ "command": "tsc",
826
+ "files": ["src/**/*.ts", "tsconfig.json"],
827
+ "output": ["lib/**"],
828
+ "packageLocks": ["another-package-manager.lock"]
829
+ }
830
+ }
831
+ }
832
+ ```
833
+
834
+ If you're sure that a script isn't affected by dependencies at all, you can turn
835
+ off this behavior entirely to improve your cache hit rate by setting
836
+ `wireit.<script>.packageLocks` to `[]`.
837
+
838
+ ## Recipes
839
+
840
+ This section contains advice about integrating specific build tools with Wireit.
841
+
842
+ ### TypeScript
843
+
844
+ ```json
845
+ {
846
+ "scripts": {
847
+ "ts": "wireit"
848
+ },
849
+ "wireit": {
850
+ "ts": {
851
+ "command": "tsc --build --pretty",
852
+ "clean": "if-file-deleted",
853
+ "files": ["src/**/*.ts", "tsconfig.json"],
854
+ "output": ["lib/**", ".tsbuildinfo"]
855
+ }
856
+ }
857
+ }
858
+ ```
859
+
860
+ - Set [`"incremental": true`](https://www.typescriptlang.org/tsconfig#incremental) and use
861
+ [`--build`](https://www.typescriptlang.org/docs/handbook/project-references.html#build-mode-for-typescript)
862
+ to enable incremental compilation, which significantly improves performance.
863
+ - Include
864
+ [`.tsbuildinfo`](https://www.typescriptlang.org/tsconfig#tsBuildInfoFile) in
865
+ `output` so that it is reset on clean builds. Otherwise `tsc` will get out of
866
+ sync and produce incorrect output.
867
+ - Set [`"clean": "if-file-deleted"`](#cleaning-output) so that you get fast
868
+ incremental compilation when sources are changed/added, but also stale outputs
869
+ are cleaned up when a source is deleted (`tsc` does not clean up stale outputs
870
+ by itself).
871
+ - Include `tsconfig.json` in `files` so that changing your configuration re-runs
872
+ `tsc`.
873
+ - Use [`--pretty`](https://www.typescriptlang.org/tsconfig#pretty) to get
874
+ colorful output despite not being attached to a TTY.
875
+
876
+ ### ESLint
877
+
878
+ ```json
879
+ {
880
+ "scripts": {
881
+ "lint": "wireit"
882
+ },
883
+ "wireit": {
884
+ "lint": {
885
+ "command": "eslint --color --cache --cache-location .eslintcache .",
886
+ "files": ["src/**/*.ts", ".eslintignore", ".eslintrc.cjs"],
887
+ "output": []
888
+ }
889
+ }
890
+ }
891
+ ```
892
+
893
+ - Use
894
+ [`--cache`](https://eslint.org/docs/user-guide/command-line-interface#caching)
895
+ so that `eslint` only lints the files that were added or changed since the
896
+ last run, which significantly improves performance.
897
+ - Use
898
+ [`--color`](https://eslint.org/docs/user-guide/command-line-interface#--color---no-color)
899
+ to get colorful output despite not being attached to a TTY.
900
+ - Include config and ignore files in `files` so that changing your configuration
901
+ re-runs `eslint`.
902
+
903
+ ## Reference
904
+
905
+ ### Configuration
906
+
907
+ The following properties can be set inside `wireit.<script>` objects in
908
+ `package.json` files:
909
+
910
+ | Property | Type | Default | Description |
911
+ | ------------------------- | ---------------------------------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
912
+ | `command` | `string` | `undefined` | The shell command to run. |
913
+ | `dependencies` | `string[] \| object[]` | `[]` | [Scripts that must run before this one](#dependencies). |
914
+ | `dependencies[i].script` | `string` | `undefined` | [The name of the script, when the dependency is an object.](#dependencies). |
915
+ | `dependencies[i].cascade` | `boolean` | `true` | [Whether this dependency always causes this script to re-execute](#execution-cascade). |
916
+ | `files` | `string[]` | `undefined` | Input file [glob patterns](#glob-patterns), used to determine the [fingerprint](#fingerprint). |
917
+ | `output` | `string[]` | `undefined` | Output file [glob patterns](#glob-patterns), used for [caching](#caching) and [cleaning](#cleaning-output). |
918
+ | `clean` | `boolean \| "if-file-deleted"` | `true` | [Delete output files before running](#cleaning-output). |
919
+ | `env` | `Record<string, string \| object>` | `false` | [Environment variables](#environment-variables) to set when running this command, or that are external and affect the behavior. |
920
+ | `env[i].external` | `true \| undefined` | `undefined` | `true` if an [environment variable](#environment-variables) is set externally and affects the script's behavior. |
921
+ | `env[i].default` | `string \| undefined` | `undefined` | Default value to use when an external [environment variable](#environment-variables) is not provided. |
922
+ | `service` | `boolean` | `false` | [Whether this script is long-running, e.g. a server](#cleaning-output). |
923
+ | `packageLocks` | `string[]` | `['package-lock.json']` | [Names of package lock files](#package-locks). |
924
+
925
+ ### Dependency syntax
926
+
927
+ The following syntaxes can be used in the `wireit.<script>.dependencies` array:
928
+
929
+ | Example | Description |
930
+ | ------------ | ----------------------------------------------------------------------------------------------- |
931
+ | `foo` | Script named `"foo"` in the same package. |
932
+ | `../foo:bar` | Script named `"bar"` in the package found at `../foo` ([details](#cross-package-dependencies)). |
933
+
934
+ ### Environment variable reference
935
+
936
+ The following environment variables affect the behavior of Wireit:
937
+
938
+ | Variable | Description |
939
+ | ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
940
+ | `WIREIT_CACHE` | [Caching mode](#caching).<br><br>Defaults to `local` unless `CI` is `true`, in which case defaults to `none`.<br><br>Automatically set to `github` by the [`google/wireit@setup-github-actions-caching/v2`](#github-actions-caching) action.<br><br>Options:<ul><li>[`local`](#local-caching): Cache to local disk.</li><li>[`github`](#github-actions-caching): Cache to GitHub Actions.</li><li>[`shared`](#shared-caching): Cache to a stable, content-addressed directory shared across builds and agents.</li><li>`none`: Disable caching.</li></ul> |
941
+ | `WIREIT_CACHE_SHARED_DIR` | Root directory of the [shared cache](#shared-caching). Only applies when `WIREIT_CACHE=shared`.<br><br>Defaults to `~/.wireit/cache`. |
942
+ | `WIREIT_CACHE_SHARED_READONLY` | When `true`, the [shared cache](#shared-caching) restores entries but never writes them. Useful for untrusted writers. Only applies when `WIREIT_CACHE=shared`.<br><br>Must be exactly `true` or `false`. Defaults to `false`. |
943
+ | `WIREIT_FAILURES` | [How to handle script failures](#failures-and-errors).<br><br>Options:<br><ul><li>[`no-new`](#failures-and-errors) (default): Allow running scripts to finish, but don't start new ones.</li><li>[`continue`](#continue): Allow running scripts to continue, and start new ones unless any of their dependencies failed.</li><li>[`kill`](#kill): Immediately kill running scripts, and don't start new ones.</li></ul> |
944
+ | `WIREIT_LOGGER` | How to present progress and results on the command line.<br><br>Options:<br><ul><li>`quiet` (default for normal execution): Writes a single dynamically updating line summarizing progress. Only passes along stdout and stderr from commands if there's a failure, or if the command is a service.</li><li>`quiet-ci` (default when `env.CI` or `!stdout.isTTY`): like `quiet` but optimized for non-interactive environments, like GitHub Actions runners.</li><li>`simple`: A verbose logger that presents clear information about the work that Wireit is doing.</li><li>`metrics`: Like `simple`, but also presents a summary table of results once a command is finished.</li></ul> |
945
+ | `WIREIT_DEBUG_LOG_FILE` | Path to a file which will receive detailed event logging. |
946
+ | `WIREIT_MAX_OPEN_FILES` | Limits the number of file descriptors Wireit will have open concurrently. Prevents resource exhaustion when checking large numbers of cached files. Set to a lower number if you hit file descriptor limits. |
947
+ | `WIREIT_PARALLEL` | [Maximum number of scripts to run at one time](#parallelism).<br><br>Defaults to 2×logical CPU cores.<br><br>Must be a positive integer or `infinity`. |
948
+ | `WIREIT_WATCH` | Set to `true` to enable [watch mode](#watch-mode). |
949
+ | `WIREIT_WATCH_STRATEGY` | How Wireit determines when a file has changed which warrants a new watch iteration.<br><br>Options:<br><ul><li>`event` (default): Register OS file system watcher callbacks (using [chokidar](https://github.com/paulmillr/chokidar)).</li><li>`poll`: Poll the filesystem every `WIREIT_WATCH_POLL_MS` milliseconds. Less responsive and worse performance than `event`, but a good fallback for when `event` does not work well or at all (e.g. filesystems that don't support filesystem events, or performance and memory problems with large file trees).</li></ul> |
950
+ | `WIREIT_WATCH_POLL_MS` | When `WIREIT_WATCH_STRATEGY` is `poll`, how many milliseconds to wait between each filesystem poll. Defaults to `500`. |
951
+ | `CI` | Affects the default value of `WIREIT_CACHE`.<br><br>Automatically set to `true` by [GitHub Actions](https://docs.github.com/en/actions/learn-github-actions/environment-variables#default-environment-variables) and most other CI (continuous integration) services.<br><br>Must be exactly `true`. If unset or any other value, interpreted as `false`. |
952
+
953
+ ### Glob patterns
954
+
955
+ The following glob syntaxes are supported in the `files` and `output` arrays:
956
+
957
+ | Example | Description |
958
+ | --------------- | ---------------------------------------------------------------------------------------- |
959
+ | `foo` | The file named `foo`, or if `foo` is a directory, all recursive children of `foo`. |
960
+ | `foo/*.js` | All files directly in the `foo/` directory which end in `.js`. |
961
+ | `foo/**/*.js` | All files in the `foo/` directory, and all recursive subdirectories, which end in `.js`. |
962
+ | `foo.{html,js}` | Files named `foo.html` or `foo.js`. |
963
+ | `!foo` | Exclude the file or directory `foo` from previous matches. |
964
+
965
+ Also note these details:
966
+
967
+ - Paths should always use `/` (forward-slash) delimiters, even on Windows.
968
+ - Paths are interpreted relative to the current package even if there is a
969
+ leading `/` (e.g. `/foo` is the same as `foo`).
970
+ - Whenever a directory is matched, all recursive children of that directory are
971
+ included.
972
+ - `files` are allowed to reach outside of the current package using e.g.
973
+ `../foo`. `output` files cannot reference files outside of the current
974
+ package.
975
+ - Symlinks in input `files` are followed, so that they are identified by their content.
976
+ - Symlinks in `output` files are cached as symlinks, so that restoring from
977
+ cache doesn't create unnecessary copies.
978
+ - The order of `!exclude` patterns is significant.
979
+ - Hidden/dot files are matched by `*` and `**`.
980
+ - Patterns are case-sensitive (if supported by the filesystem).
981
+
982
+ ### Fingerprint
983
+
984
+ The following inputs determine the _fingerprint_ for a script. This value is
985
+ used to determine whether a script can be skipped for [incremental
986
+ build](#incremental-build), and whether its output can be [restored from
987
+ cache](#caching).
988
+
989
+ - The `command` setting.
990
+ - The [extra arguments](#extra-arguments) set on the command-line.
991
+ - The `clean` setting.
992
+ - The `output` glob patterns.
993
+ - The SHA256 content hashes of all files matching `files`.
994
+ - The SHA256 content hashes of all files matching `packageLocks` in the current
995
+ package and all parent directories.
996
+ - The environment variable values configured in `env`.
997
+ - The system platform (e.g. `linux`, `win32`).
998
+ - The system CPU architecture (e.g. `x64`).
999
+ - The system Node version (e.g. `24.11.1`).
1000
+ - The fingerprint of all transitive dependencies, unless `cascade` is set to
1001
+ `false`.
1002
+
1003
+ When using [GitHub Actions caching](#github-actions-caching), the following
1004
+ input also affects the fingerprint:
1005
+
1006
+ - The `ImageOS` environment variable (e.g. `ubuntu20`, `macos11`).
1007
+
1008
+ ## Requirements
1009
+
1010
+ Wireit is supported on Linux, macOS, and Windows.
1011
+
1012
+ Wireit is supported on Node 18+.
1013
+
1014
+ Wireit scripts can be launched via `npm`, `node --run`, `pnpm`, and `yarn`.
1015
+
1016
+ ## Related tools
1017
+
1018
+ Wireit shares a number of features with these other great tools, and we highly
1019
+ recommend you check them out too:
1020
+
1021
+ - [Nx](https://nx.dev/)
1022
+ - [Turborepo](https://turborepo.org/)
1023
+ - [Chomp](https://chompbuild.com/)
1024
+ - [Bazel](https://bazel.build/)
1025
+
1026
+ Here are some things you might especially like about Wireit:
1027
+
1028
+ - **Feels like npm**. When you use Wireit, you'll continue typing the same npm
1029
+ commands you already use, like `npm run build` and `npm test`. There are no
1030
+ new command-line tools to learn, and there's only one way to run each script.
1031
+ Your script config stays in your `package.json`, too. Wireit is designed to be
1032
+ the minimal addition to npm needed to get script dependencies and incremental
1033
+ build.
1034
+
1035
+ - **Caching with GitHub Actions**. Wireit supports caching build artifacts and
1036
+ test results directly through GitHub Actions, without any extra third-party
1037
+ services. Just add a single `uses:` line to your workflows.
1038
+
1039
+ - **Watch any script**. Want to automatically re-run your build and tests
1040
+ whenever you make a change? Type `npm test --watch`. Any script you've
1041
+ configured using Wireit can be watched by typing `--watch` after it.
1042
+
1043
+ - **Great for single packages and monorepos**. Wireit has no opinion about how
1044
+ your packages are arranged. It works great with single packages, because you
1045
+ can link together scripts within the same package. It also works great with
1046
+ any kind of monorepo, because you can link together scripts across different
1047
+ packages using relative paths.
1048
+
1049
+ - **Complements npm workspaces**. We think Wireit could be the missing tool that
1050
+ unlocks the potential for [npm
1051
+ workspaces](https://docs.npmjs.com/cli/v8/using-npm/workspaces) to become the
1052
+ best way to set up monorepos. To use Wireit with npm workspaces, you'll just
1053
+ use standard npm workspace commands like `npm run build -ws`.
1054
+
1055
+ - **Adopt incrementally**. Wireit scripts can depend on plain npm scripts, so
1056
+ they can be freely mixed. This means you can use Wireit only for the parts of
1057
+ your build that need it most, or you can try it out on a script-by-script
1058
+ basis without changing too much at the same time.
1059
+
1060
+ ## Contributing
1061
+
1062
+ See [CONTRIBUTING.md](./CONTRIBUTING.md)