webanvil 0.0.6 → 0.0.8

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 (88) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +549 -38
  3. package/bin/webanvil +6 -0
  4. package/bin/webanvil.cmd +2 -0
  5. package/dist/_chunks/commands.mjs +1890 -0
  6. package/dist/_chunks/config.mjs +140 -0
  7. package/dist/_chunks/project-vite.mjs +9 -0
  8. package/dist/cli.d.mts +1 -0
  9. package/dist/cli.mjs +30 -0
  10. package/dist/index.d.mts +668 -0
  11. package/dist/index.mjs +6 -0
  12. package/dist/storybook/react/index.d.mts +3 -0
  13. package/dist/storybook/react/index.mjs +4 -0
  14. package/dist/storybook/react/preset +8 -0
  15. package/dist/storybook/react/preset.d.mts +5 -0
  16. package/dist/storybook/react/preset.mjs +8 -0
  17. package/dist/storybook/svelte/index.d.mts +3 -0
  18. package/dist/storybook/svelte/index.mjs +4 -0
  19. package/dist/storybook/svelte/preset +8 -0
  20. package/dist/storybook/svelte/preset.d.mts +5 -0
  21. package/dist/storybook/svelte/preset.mjs +8 -0
  22. package/dist/storybook/test/preset +2 -0
  23. package/dist/storybook/test/preset.d.mts +1 -0
  24. package/dist/storybook/test/preset.mjs +2 -0
  25. package/dist/storybook/vue/index.d.mts +3 -0
  26. package/dist/storybook/vue/index.mjs +4 -0
  27. package/dist/storybook/vue/preset +8 -0
  28. package/dist/storybook/vue/preset.d.mts +5 -0
  29. package/dist/storybook/vue/preset.mjs +8 -0
  30. package/dist/storybook/web-components/index.d.mts +3 -0
  31. package/dist/storybook/web-components/index.mjs +4 -0
  32. package/dist/storybook/web-components/preset +7 -0
  33. package/dist/storybook/web-components/preset.d.mts +4 -0
  34. package/dist/storybook/web-components/preset.mjs +7 -0
  35. package/package.json +151 -60
  36. package/bin/run +0 -3
  37. package/bin/run.cmd +0 -3
  38. package/lib/commands/build.d.ts +0 -3
  39. package/lib/commands/build.d.ts.map +0 -1
  40. package/lib/commands/build.js +0 -34
  41. package/lib/commands/serve.d.ts +0 -3
  42. package/lib/commands/serve.d.ts.map +0 -1
  43. package/lib/commands/serve.js +0 -44
  44. package/lib/commons/io/core/File.d.ts +0 -11
  45. package/lib/commons/io/core/File.d.ts.map +0 -1
  46. package/lib/commons/io/core/File.js +0 -23
  47. package/lib/commons/io/core/Path.d.ts +0 -30
  48. package/lib/commons/io/core/Path.d.ts.map +0 -1
  49. package/lib/commons/io/core/Path.js +0 -122
  50. package/lib/commons/io/sync/fs.d.ts +0 -11
  51. package/lib/commons/io/sync/fs.d.ts.map +0 -1
  52. package/lib/commons/io/sync/fs.js +0 -46
  53. package/lib/commons/io/sync/index.d.ts +0 -5
  54. package/lib/commons/io/sync/index.d.ts.map +0 -1
  55. package/lib/commons/io/sync/index.js +0 -9
  56. package/lib/commons/io/sync/path.d.ts +0 -4
  57. package/lib/commons/io/sync/path.d.ts.map +0 -1
  58. package/lib/commons/io/sync/path.js +0 -13
  59. package/lib/core/Configuration.d.ts +0 -37
  60. package/lib/core/Configuration.d.ts.map +0 -1
  61. package/lib/core/Configuration.js +0 -56
  62. package/lib/core/EventEmitter.d.ts +0 -14
  63. package/lib/core/EventEmitter.d.ts.map +0 -1
  64. package/lib/core/EventEmitter.js +0 -42
  65. package/lib/core/Page.d.ts +0 -14
  66. package/lib/core/Page.d.ts.map +0 -1
  67. package/lib/core/Page.js +0 -34
  68. package/lib/core/Plugin.d.ts +0 -13
  69. package/lib/core/Plugin.d.ts.map +0 -1
  70. package/lib/core/Plugin.js +0 -12
  71. package/lib/core/Renderer/Renderer.d.ts +0 -8
  72. package/lib/core/Renderer/Renderer.d.ts.map +0 -1
  73. package/lib/core/Renderer/Renderer.js +0 -9
  74. package/lib/core/Renderer/index.d.ts +0 -8
  75. package/lib/core/Renderer/index.d.ts.map +0 -1
  76. package/lib/core/Renderer/index.js +0 -18
  77. package/lib/index.d.ts +0 -1
  78. package/lib/index.d.ts.map +0 -1
  79. package/lib/index.js +0 -1
  80. package/lib/main.d.ts +0 -2
  81. package/lib/main.d.ts.map +0 -1
  82. package/lib/main.js +0 -36
  83. package/lib/plugins/outlinecss.d.ts +0 -4
  84. package/lib/plugins/outlinecss.d.ts.map +0 -1
  85. package/lib/plugins/outlinecss.js +0 -34
  86. package/lib/renderers/EJSRenderer.d.ts +0 -7
  87. package/lib/renderers/EJSRenderer.d.ts.map +0 -1
  88. package/lib/renderers/EJSRenderer.js +0 -34
package/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2025 Mateusz Pietrzak
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Mateusz Pietrzak
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,38 +1,549 @@
1
- <div align="center">
2
-
3
- [![license](https://img.shields.io/npm/l/webanvil.svg)](https://github.com/mzpkdev/webanvil/blob/master/LICENSE)
4
- [![npm version](https://img.shields.io/npm/v/webanvil.svg)](https://www.npmjs.com/package/webanvil)
5
- [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](https://www.typescriptlang.org/)
6
- [![bundle size](https://img.shields.io/bundlephobia/min/webanvil)](https://bundlephobia.com/result?p=webanvil)
7
-
8
- </div>
9
- <br>
10
- <br>
11
-
12
- <p align="center">
13
- <strong>WebAnvil</strong>
14
- <p align="center">
15
- A zero configuration static site generator that just works.
16
- <br />
17
- <br />
18
- <a href="https://github.com/mzpkdev/webanvil/issues">Report a bug</a>
19
- &nbsp;&nbsp;·&nbsp;&nbsp;
20
- <a href="https://github.com/mzpkdev/webanvil/issues">Request a feature</a>
21
- </p>
22
- <br />
23
- <br />
24
-
25
- Table of Contents
26
- ------------------
27
-
28
- * [Getting started](#getting-started)
29
- * [How to install](#how-to-install)
30
-
31
- Getting started
32
- ----------------
33
-
34
- ### How to install
35
-
36
- ```shell
37
- npm install webanvil
38
- ```
1
+ <div align="center">
2
+ <img src=".github/assets/banner.svg" width="1012" alt="WebAnvil: build the web, forge the backend" />
3
+
4
+ <p>
5
+ <strong>WebAnvil</strong> · one CLI for building, testing, linting, formatting, and type-checking JavaScript and TypeScript projects
6
+ <br />
7
+ <br />
8
+ <a href="#getting-started"><strong>Get started »</strong></a>
9
+ <br />
10
+ <br />
11
+ <a href="https://github.com/mzpkdev/webanvil/issues">Report a bug</a>
12
+ &nbsp;&nbsp;·&nbsp;&nbsp;
13
+ <a href="https://github.com/mzpkdev/webanvil/issues">Request a feature</a>
14
+ </p>
15
+ </div>
16
+
17
+ Table of contents
18
+ -----------------
19
+
20
+ - [Why WebAnvil?](#why-webanvil)
21
+ - [What it includes](#what-it-includes)
22
+ - [Getting started](#getting-started)
23
+ - [Install](#install)
24
+ - [Everyday commands](#everyday-commands)
25
+ - [A web app](#a-web-app)
26
+ - [Storybook](#storybook)
27
+ - [A Node project](#a-node-project)
28
+ - [Configuration](#configuration)
29
+ - [Tool selection](#tool-selection)
30
+ - [Native tool configuration](#native-tool-configuration)
31
+ - [Node declarations](#node-declarations)
32
+ - [Command-line options](#command-line-options)
33
+ - [Migration](#migration)
34
+ - [Command reference](#command-reference)
35
+
36
+ Why WebAnvil?
37
+ -------------
38
+
39
+ JavaScript projects usually need a builder, a development server, a test runner, a linter, a formatter, and a type checker. Each tool has its own command and configuration. That is workable, but it makes the project setup longer than it needs to be.
40
+
41
+ WebAnvil puts the common jobs behind `wa`. It uses Vite for web projects, Rolldown for Node builds, Vitest for tests, and Oxc for linting and formatting. You keep those tools, but package scripts and the first layer of configuration stay in one place.
42
+
43
+ ```sh
44
+ wa dev # develop a web app or watch a Node build
45
+ wa build # build the project
46
+ wa preview # serve the production web build
47
+ wa clean # remove tracked build output
48
+ wa check # check formatting, linting, and types
49
+ wa check --fix # format files and apply safe lint fixes before type checking
50
+ wa test # run tests, watch them, collect coverage, or open the UI
51
+ wa lint # lint files
52
+ wa format # format files
53
+ wa typecheck # type-check the project
54
+ ```
55
+
56
+ What it includes
57
+ ----------------
58
+
59
+ | Project job | WebAnvil command | Tool |
60
+ | -------------------------- | ------------------------------------------------------ | -------------------------------- |
61
+ | Web builds and development | `wa build`, `wa dev`, `wa preview` | Vite |
62
+ | Node builds and watch mode | `wa build`, `wa dev` | Rolldown |
63
+ | Storybook development | `wa build --mode storybook`, `wa dev --mode storybook` | Storybook |
64
+ | Tracked output cleanup | `wa clean` | WebAnvil |
65
+ | Static checks | `wa check` | Oxfmt, Oxlint, TypeScript Native |
66
+ | Tests | `wa test` | Vitest |
67
+ | Linting | `wa lint` | Oxlint |
68
+ | Formatting | `wa format` | Oxfmt |
69
+ | Type checking | `wa typecheck` | TypeScript Native |
70
+
71
+ Getting started
72
+ ---------------
73
+
74
+ ### Install
75
+
76
+ Install WebAnvil as a development dependency:
77
+
78
+ ```sh
79
+ npm install --save-dev webanvil
80
+ ```
81
+
82
+ Your package manager remains responsible for dependencies, the lockfile, and
83
+ the installed tree. WebAnvil never installs or updates tools. When a supported
84
+ tool is declared directly by the active project, or by a workspace that contains
85
+ it, WebAnvil uses that installed version. Otherwise it uses the exact version
86
+ shipped with WebAnvil.
87
+
88
+ Add the scripts you want to `package.json`:
89
+
90
+ ```json
91
+ {
92
+ "scripts": {
93
+ "dev": "wa dev",
94
+ "build": "wa build",
95
+ "clean": "wa clean",
96
+ "check": "wa check",
97
+ "test": "wa test",
98
+ "lint": "wa lint",
99
+ "format": "wa format",
100
+ "typecheck": "wa typecheck"
101
+ }
102
+ }
103
+ ```
104
+
105
+ You can start without a config file. WebAnvil defaults to a Node project with `src/index.ts` as its entry and `dist` as its output directory.
106
+
107
+ ### Everyday commands
108
+
109
+ Run the commands through npm or directly with `wa`:
110
+
111
+ ```sh
112
+ npm run dev
113
+ npm run build
114
+ npm run clean
115
+ npm run check
116
+ npm run test
117
+ npm run lint
118
+ npm run format
119
+ npm run typecheck
120
+ ```
121
+
122
+ `wa check` checks formatting, linting, and types sequentially, stopping on the
123
+ first failure. It is read-only by default. Use `wa check --fix` to format files
124
+ and apply safe lint fixes before type checking. Tests stay separate under
125
+ `wa test`.
126
+
127
+ ### A web app
128
+
129
+ Set the build mode to `"web"` and point it at an HTML entry point. `wa dev` starts Vite's development server, `wa build` produces a production bundle, and `wa preview` serves that bundle locally.
130
+
131
+ ```ts
132
+ import { defineConfig } from "webanvil"
133
+
134
+ export default defineConfig({
135
+ build: {
136
+ mode: "web",
137
+ entry: "index.html",
138
+ outDir: "dist",
139
+ copy: [{ from: "assets/**", to: "assets" }]
140
+ }
141
+ })
142
+ ```
143
+
144
+ Pass framework plugins through your WebAnvil configuration:
145
+
146
+ ```ts
147
+ import react from "@vitejs/plugin-react"
148
+ import { defineConfig } from "webanvil"
149
+
150
+ export default defineConfig({
151
+ build: { mode: "web", entry: "index.html" },
152
+ plugins: [react()]
153
+ })
154
+ ```
155
+
156
+ ### Storybook
157
+
158
+ WebAnvil includes Storybook, the supported Vite framework adapters, Vitest's
159
+ browser support, and Chromium. Add only a Storybook configuration and your
160
+ project's normal framework dependencies.
161
+
162
+ For example, a Svelte project can use this `.storybook/main.ts`:
163
+
164
+ ```ts
165
+ import { framework, type StorybookConfig } from "webanvil/storybook/svelte"
166
+
167
+ export default {
168
+ framework,
169
+ stories: ["../src/**/*.stories.@(js|ts|svelte)"]
170
+ } satisfies StorybookConfig
171
+ ```
172
+
173
+ Use `webanvil/storybook/react`, `webanvil/storybook/vue`, or
174
+ `webanvil/storybook/web-components` for those frameworks. The WebAnvil wrapper
175
+ uses the framework plugins already declared in `webanvil.config.*`.
176
+
177
+ Set Storybook as the project's build mode when it is the primary development
178
+ target:
179
+
180
+ ```ts
181
+ import { defineConfig } from "webanvil"
182
+
183
+ export default defineConfig({
184
+ build: { mode: "storybook" }
185
+ })
186
+ ```
187
+
188
+ Or select it for one command:
189
+
190
+ ```sh
191
+ wa dev --mode storybook
192
+ wa build --mode storybook
193
+ ```
194
+
195
+ The build writes to `storybook-static` unless `storybook.outDir` in
196
+ `webanvil.config.*` or `--out-dir` selects another directory. `wa test`
197
+ automatically runs Storybook stories, including `play` functions, when it finds
198
+ `.storybook/main.*`. Set `storybook.test: false` to exclude them. Chromium is
199
+ downloaded by `@playwright/browser-chromium` when your package manager runs
200
+ install scripts. If the project declares Vitest, Storybook tests require
201
+ version `4.1.10` to match the bundled browser provider.
202
+
203
+ ### A Node project
204
+
205
+ Node mode is the default. Declare the package's public roots with `entry` or
206
+ `entries`, then choose whether Rolldown should preserve or bundle the reachable
207
+ module graph:
208
+
209
+ ```ts
210
+ import { defineConfig } from "webanvil"
211
+
212
+ export default defineConfig({
213
+ build: {
214
+ mode: "node",
215
+ entries: {
216
+ ".": "src/index.ts",
217
+ "./feature": "src/internal/implementation.ts"
218
+ },
219
+ outDir: "dist",
220
+ bundle: true,
221
+ formats: ["esm", "cjs"],
222
+ declaration: true,
223
+ sourcemap: true,
224
+ platform: "node",
225
+ target: "es2022"
226
+ }
227
+ })
228
+ ```
229
+
230
+ Without `bundle`, Rolldown uses `preserveModules` and emits only modules
231
+ reachable from the public roots. It does not mirror the source tree, so tests,
232
+ examples, setup files, and other unreachable modules are omitted. With
233
+ `bundle`, those same roots become bundle entries. An explicit positional entry
234
+ overrides configured `entries`.
235
+
236
+ TypeScript paths, native Rolldown aliases and resolver plugins, and package
237
+ export conditions resolve before WebAnvil decides whether an import is a
238
+ dependency. Project-local results stay in the graph. Node built-ins and
239
+ installed packages remain external with their original portable specifiers,
240
+ while unresolved imports fail the build.
241
+
242
+ `platform` (`node`, `browser`, or `neutral`) is Node-only. `target` is one
243
+ syntax target or an array; CLI lists are comma-separated. Node defaults are
244
+ `platform: "node"` and `target: "node20"`. Web production forwards only an
245
+ explicit target; Vite config wins, and web dev does not apply it.
246
+
247
+ For Node builds, WebAnvil fills omitted output settings from the nearest
248
+ `package.json`: `import` and `require` export conditions enable ESM and CommonJS
249
+ respectively, while a top-level `types` field or `types` export condition enables
250
+ declarations. Explicit CLI options override `webanvil.config.*`, which overrides
251
+ package metadata, which overrides built-in defaults. Package metadata does not
252
+ affect web builds.
253
+
254
+ `wa dev` watches and rebuilds Node output with the same `build` configuration as
255
+ `wa build`: bundle mode, entries, formats, declarations, source maps,
256
+ minification, platform, target, plugins, static copies, stale-output cleanup, and
257
+ build metadata all stay in sync. It does not run or restart the server process.
258
+
259
+ Node output is transactional. WebAnvil generates every requested format before
260
+ writing, rejects filename or copy collisions, and replaces the previous output
261
+ only after the complete build succeeds. A failed one-shot build or watch cycle
262
+ rolls back to the last successful files and build metadata.
263
+
264
+ ### Node build plugins
265
+
266
+ Node builds use Rolldown. To use a plugin in both web and Node builds, wrap an
267
+ unplugin implementation with `definePlugin()`:
268
+
269
+ ```ts
270
+ import { defineConfig, definePlugin } from "webanvil"
271
+ import { createUnplugin } from "unplugin"
272
+
273
+ const replace = createUnplugin<{ from: string; to: string }>((options) => ({
274
+ name: "replace",
275
+ transform: (code) => code.replace(options.from, options.to)
276
+ }))
277
+
278
+ export default defineConfig({
279
+ plugins: [definePlugin(replace, { from: "development", to: "production" })]
280
+ })
281
+ ```
282
+
283
+ Plain Vite plugins work in effective web mode. Effective Node builds require
284
+ plugins created with `definePlugin()`; raw Vite and Rolldown plugins are rejected
285
+ during config validation after explicit CLI overrides are applied.
286
+
287
+ Configuration
288
+ -------------
289
+
290
+ Use `webanvil.config.ts` to keep WebAnvil orchestration and native tool settings
291
+ together:
292
+
293
+ ```ts
294
+ import { defineConfig } from "webanvil"
295
+
296
+ export default defineConfig({
297
+ build: {
298
+ mode: "web",
299
+ entry: "index.html",
300
+ outDir: "dist"
301
+ },
302
+ vite: {
303
+ base: "/app/"
304
+ },
305
+ test: {
306
+ globals: true,
307
+ environment: "jsdom",
308
+ include: ["test/**/*.test.ts"]
309
+ },
310
+ lint: {
311
+ rules: { "no-console": "deny" }
312
+ },
313
+ format: {
314
+ printWidth: 100,
315
+ semi: false
316
+ }
317
+ })
318
+ ```
319
+
320
+ For a new WebAnvil project, keep Oxfmt and Oxlint settings in the `format` and
321
+ `lint` blocks. `wa format`, `wa lint`, and `wa check` pass those options to the
322
+ matching Oxc tool, so you do not need to create `.oxfmtrc.json` or
323
+ `.oxlintrc.json`.
324
+
325
+ Keep a native Oxc config when you are adopting an existing project configuration
326
+ or need Oxc's native configuration lookup. A native Oxc config takes precedence
327
+ over the matching WebAnvil block.
328
+
329
+ ### Tool selection
330
+
331
+ WebAnvil selects compatible project and workspace declarations before its own
332
+ fallbacks. A transitive or merely hoisted package is not selected. Each command
333
+ preflights the engines it can dispatch before `webanvil.config.*` is loaded or
334
+ its plugins are evaluated, so a declared command engine that is missing, has
335
+ invalid package identity, or is outside the supported range fails first.
336
+
337
+ | Tool | Supported project/workspace versions | Exact WebAnvil fallback |
338
+ | -------------------------- | ------------------------------------ | ----------------------- |
339
+ | Vite | `>=8.1.5 <9` | `8.1.5` |
340
+ | Vitest | `>=4.1.10 <5` | `4.1.10` |
341
+ | Storybook | `>=10.5.9 <11` | `10.5.9` |
342
+ | Rolldown | `>=1.2.0 <2` | `1.2.0` |
343
+ | Oxlint | `>=1.75.0 <2` | `1.75.0` |
344
+ | Oxfmt | `>=0.60.0 <0.61` | `0.60.0` |
345
+ | TypeScript (declarations) | `>=5 <7` | `6.0.3` |
346
+ | TypeScript Native (`tsgo`) | `>=7.0.0-dev.20260707.2 <7.0.0` | `7.0.0-dev.20260707.2` |
347
+
348
+ When a tool is first used, the CLI reports its package, version, and source, for
349
+ example `Using rolldown 1.2.0 (project)` or
350
+ `Using rolldown 1.2.0 (webanvil)`.
351
+
352
+ The TypeScript compiler is selected only after configuration enables a
353
+ declaration build, but before Rolldown starts that build. It follows the same
354
+ direct project/workspace declaration and exact-fallback rules.
355
+
356
+ ### Native tool configuration
357
+
358
+ The `vite`, `test`, `rolldown`, `lint`, and `format` blocks use the owning
359
+ tool's exported TypeScript types. WebAnvil validates them as opaque native
360
+ objects and passes compatible upstream options through without duplicating
361
+ their schemas.
362
+
363
+ Precedence is:
364
+
365
+ 1. explicit CLI values for the current run;
366
+ 2. an existing native `vite.config.*`, `vitest.config.*`, `.oxlintrc.json`, or
367
+ `.oxfmtrc.json`;
368
+ 3. the matching native block in `webanvil.config.*`;
369
+ 4. WebAnvil defaults.
370
+
371
+ WebAnvil-owned `build`, `copy`, cross-engine `plugins`, and CLI behavior remain
372
+ orchestration settings. `rolldown.input` and per-format `rolldown.output`
373
+ options extend Node builds; WebAnvil still owns the input roots, output
374
+ directory, format, cleanup, and `preserveModules` strategy.
375
+
376
+ ```ts
377
+ import { defineConfig } from "webanvil"
378
+
379
+ export default defineConfig({
380
+ build: {
381
+ mode: "node",
382
+ entries: { ".": "src/index.ts", "./feature": "src/feature.ts" },
383
+ formats: ["esm", "cjs"]
384
+ },
385
+ rolldown: {
386
+ input: {
387
+ resolve: { conditionNames: ["source", "node", "import"] }
388
+ },
389
+ output: {
390
+ esm: {
391
+ entryFileNames: "[name].mjs",
392
+ chunkFileNames: "chunks/[name]-[hash].mjs"
393
+ },
394
+ cjs: {
395
+ entryFileNames: "[name].js",
396
+ chunkFileNames: "chunks/[name]-[hash].js"
397
+ }
398
+ }
399
+ }
400
+ })
401
+ ```
402
+
403
+ Native `entryFileNames`, `chunkFileNames`, and `assetFileNames` accept the same
404
+ strings or callbacks as Rolldown. WebAnvil records the actual emitted paths, so
405
+ stale-output removal, rollback, build metadata, and `wa clean` follow customized
406
+ names and source maps.
407
+
408
+ ### Node declarations
409
+
410
+ `build.declaration: true` uses `rolldown-plugin-dts` with its TypeScript
411
+ generator. Pass a native declaration options object to select the `"oxc"` or
412
+ `"tsgo"` generator and other plugin settings:
413
+
414
+ ```ts
415
+ import { defineConfig } from "webanvil"
416
+
417
+ export default defineConfig({
418
+ build: {
419
+ declaration: {
420
+ generator: "tsc",
421
+ sourcemap: true
422
+ }
423
+ }
424
+ })
425
+ ```
426
+
427
+ The TypeScript generator selects a compatible project/workspace TypeScript
428
+ declaration when present, otherwise WebAnvil's exact TypeScript fallback.
429
+ Project-local `ts-patch` and TypeScript emit transforms are honored when they
430
+ are directly declared and resolve to that same compiler. Emit transforms
431
+ require the `tsc` generator; Oxc and `tsgo` are explicit alternatives.
432
+
433
+ `rolldown-plugin-dts` owns declaration paths and imports. ESM-only builds attach
434
+ one declaration graph; CommonJS-only and dual-format builds use one
435
+ declaration-only ESM pass. Because the plugin initializes TypeScript in process,
436
+ one process cannot switch to a different compiler path or version after its
437
+ first TypeScript declaration build—run builds needing different compilers in
438
+ separate processes.
439
+
440
+ ### Command-line options
441
+
442
+ Command-line options override the config file. For example, this writes a build to `preview` without changing `webanvil.config.ts`:
443
+
444
+ ```sh
445
+ wa build --out-dir preview
446
+ ```
447
+
448
+ For Node builds and watchers, `--bundle` and `--no-bundle` are explicit
449
+ opposites. `--no-bundle` overrides `build.bundle: true` for that run and emits
450
+ the reachable module graph with Rolldown `preserveModules`.
451
+
452
+ Use `build.copy` for static files that should be copied unchanged after either a
453
+ web or Node build. Each mapping preserves the path beneath the source glob's
454
+ static base. For example, `assets/**` mapped to `assets` copies
455
+ `assets/images/logo.svg` to `dist/assets/images/logo.svg`. `--copy` accepts one
456
+ or more `source=destination` mappings and replaces configured mappings for that
457
+ run:
458
+
459
+ ```sh
460
+ wa build --copy "assets/**=assets" "src/templates/**=templates"
461
+ ```
462
+
463
+ Both paths are relative to the project root: `from` is a file path or glob and
464
+ `to` is an output directory. This is useful for Node runtime files such as Fastify email
465
+ or response templates: `{ from: "src/templates/**", to: "templates" }` makes
466
+ `src/templates/welcome.txt` available as `dist/templates/welcome.txt`.
467
+
468
+ Copy destinations must not resolve to the same file as generated output, another
469
+ mapping, or an untracked file already in the output directory. WebAnvil fails
470
+ instead of overwriting in each case.
471
+
472
+ Node watch mode re-expands copy globs on every rebuild. Changes and deletions to
473
+ currently matched files trigger rebuilds; newly matching files are included on
474
+ the next rebuild.
475
+
476
+ Web builds keep Vite's `publicDir` behavior unchanged. Do not use `copy` for
477
+ assets imported by application code; Vite continues to manage those assets.
478
+
479
+ ### Test modes
480
+
481
+ `wa test` runs once by default. Use `--watch` to rerun affected tests after a
482
+ change, `--coverage` to write V8 coverage reports, or `--ui` to start the
483
+ Vitest UI:
484
+
485
+ ```sh
486
+ wa test --watch
487
+ wa test --coverage
488
+ wa test --ui
489
+ wa test --ui --ui-port 51204
490
+ ```
491
+
492
+ These are run-specific modes; keep persistent Vitest configuration in
493
+ `vitest.config.*`. `--ui-port` selects a strict loopback port and requires
494
+ `--ui`.
495
+
496
+ ### Cleaning build output
497
+
498
+ `wa build` records the actual emitted and copied files in
499
+ `.webanvil/buildinfo.json`. Run `wa clean` to remove only those files across
500
+ every build target; source files and other untracked files stay in place. The
501
+ command leaves `.webanvil/` behind with an empty output list.
502
+
503
+ Migration
504
+ ---------
505
+
506
+ Start with WebAnvil without rewriting your project configuration. You do not need `webanvil.config.ts` before you can use the unified CLI, and you do not need to translate existing Vite, Vitest, or Oxc settings first.
507
+
508
+ Install WebAnvil, then replace the project scripts with the WebAnvil commands:
509
+
510
+ ```json
511
+ {
512
+ "scripts": {
513
+ "dev": "wa dev",
514
+ "build": "wa build",
515
+ "clean": "wa clean",
516
+ "check": "wa check",
517
+ "test": "wa test",
518
+ "lint": "wa lint",
519
+ "format": "wa format",
520
+ "typecheck": "wa typecheck"
521
+ }
522
+ }
523
+ ```
524
+
525
+ For a Node project that follows the defaults, this is enough. WebAnvil reads `src/index.ts`, writes to `dist`, and uses the project's TypeScript configuration when you run `wa typecheck`.
526
+
527
+ Your existing configuration stays in charge. A `vite.config.*` or
528
+ `vitest.config.*` takes precedence over the matching WebAnvil native block.
529
+ `.oxfmtrc.json` and `.oxlintrc.json` do the same for Oxc. Explicit CLI values
530
+ remain the final run-specific override.
531
+
532
+ That lets a project standardize on `wa` now and move settings into `webanvil.config.ts` later, one part at a time. New WebAnvil projects should keep Oxfmt and Oxlint settings in the `format` and `lint` blocks; move existing native Oxc configuration there when it makes sense.
533
+
534
+ Command reference
535
+ -----------------
536
+
537
+ | Command | Description | Options |
538
+ | ------------------------- | --------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
539
+ | `wa build [entry]` | Builds with Vite in web mode, Rolldown in Node mode, or Storybook. | `--mode`, `--out-dir`, `--copy`, `--bundle`, `--no-bundle`, `--formats`, `--declaration`, `--sourcemap`, `--minify`, `--platform`, `--target` |
540
+ | `wa clean` | Removes files emitted by prior WebAnvil builds. | No options |
541
+ | `wa check` | Checks formatting, linting, and types, stopping on the first failure. | `--fix` |
542
+ | `wa dev [entry]` | Starts Vite, a Node build watcher, or Storybook. | `--mode`, `--out-dir`, `--host`, `--port`, `--copy`, `--bundle`, `--no-bundle`, `--formats`, `--declaration`, `--sourcemap`, `--minify`, `--platform`, `--target` |
543
+ | `wa preview` | Serves a Vite production build. | `--out-dir`, `--host`, `--port`, `--open` |
544
+ | `wa test [filters...]` | Runs Vitest once, in watch mode, with coverage, or UI. | `--environment`, `--watch`, `--coverage`, `--ui`, `--ui-port` |
545
+ | `wa lint [paths...]` | Runs Oxlint and treats warnings as failures. | `--fix` |
546
+ | `wa format [paths...]` | Formats with Oxfmt. | `--check` |
547
+ | `wa typecheck [paths...]` | Type-checks with TypeScript Native. | No options |
548
+
549
+ Run `wa <command> --help` for the complete reference for a command.
package/bin/webanvil ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env node
2
+
3
+ import("../dist/cli.mjs").catch((error) => {
4
+ console.error(error);
5
+ process.exit(1);
6
+ });
@@ -0,0 +1,2 @@
1
+ @echo off
2
+ node "%~dp0\..\dist\cli.mjs" %*