vantris 0.1.0 → 0.3.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.
package/dist/index.d.ts CHANGED
@@ -6,6 +6,113 @@
6
6
  * single extension point through which future versions will grow (plugins,
7
7
  * build options, HMR, server tuning, …) without breaking existing configs.
8
8
  */
9
+ /**
10
+ * Development server options.
11
+ *
12
+ * Extension point for the dev server. v0.2.0 exposes only `port` and `host`;
13
+ * future versions will add HMR, proxy, HTTPS, and middleware hooks here
14
+ * without breaking existing configs.
15
+ */
16
+ interface DevConfig {
17
+ /**
18
+ * Port the dev server listens on.
19
+ *
20
+ * @default 3000
21
+ */
22
+ port?: number;
23
+ /**
24
+ * Host the dev server binds to.
25
+ *
26
+ * @default "localhost"
27
+ */
28
+ host?: string;
29
+ }
30
+ /**
31
+ * Information about a chunk, passed to a {@link ChunkFileNames} function.
32
+ *
33
+ * This is a Vantris-owned mirror of the bundler's pre-render data: it exposes a
34
+ * stable, curated subset so naming functions never touch Rolldown's types.
35
+ */
36
+ interface ChunkInfo {
37
+ /** Chunk name used in naming patterns. */
38
+ name: string;
39
+ /** Whether this is a static entry chunk. */
40
+ isEntry: boolean;
41
+ /** Whether this is a dynamic-import entry chunk. */
42
+ isDynamicEntry: boolean;
43
+ /** Absolute id of the module this chunk represents, if any. */
44
+ facadeModuleId: string | null;
45
+ /** Absolute ids of the modules included in this chunk. */
46
+ moduleIds: string[];
47
+ /** Names exported by this chunk. */
48
+ exports: string[];
49
+ }
50
+ /** Information about an asset, passed to an {@link AssetFileNames} function. */
51
+ interface AssetInfo {
52
+ /** Candidate names for the asset. */
53
+ names: string[];
54
+ /** Absolute paths of the asset's original source files. */
55
+ originalFileNames: string[];
56
+ }
57
+ /** A chunk naming pattern, or a function returning one per chunk. */
58
+ type ChunkFileNames = string | ((chunk: ChunkInfo) => string);
59
+ /** An asset naming pattern, or a function returning one per asset. */
60
+ type AssetFileNames = string | ((asset: AssetInfo) => string);
61
+ /**
62
+ * Production build options.
63
+ *
64
+ * Extension point for the build system. v0.3.0 exposes a small surface; the
65
+ * interface is shaped to grow (e.g. `target`, `manifest`, `cssCodeSplit`,
66
+ * build hooks/plugins) without breaking existing configs. The underlying
67
+ * bundler (Rolldown) is an internal detail and is never exposed here.
68
+ */
69
+ interface BuildConfig {
70
+ /**
71
+ * Minify the output.
72
+ *
73
+ * @default true
74
+ */
75
+ minify?: boolean;
76
+ /**
77
+ * Source map strategy.
78
+ *
79
+ * - `false` — no source maps
80
+ * - `true` — separate `.map` files
81
+ * - `"inline"` — appended to each file as a data URL
82
+ * - `"hidden"` — separate files without the `//# sourceMappingURL` comment
83
+ *
84
+ * @default false
85
+ */
86
+ sourcemap?: boolean | "inline" | "hidden";
87
+ /**
88
+ * Directory (relative to `outDir`) for built chunks and assets. Used to
89
+ * derive the default `*FileNames` patterns below.
90
+ *
91
+ * @default "assets"
92
+ */
93
+ assetsDir?: string;
94
+ /**
95
+ * Naming pattern for entry chunks — a string with `[name]`, `[hash]`,
96
+ * `[ext]`, `[extname]` placeholders, or a function receiving {@link ChunkInfo}.
97
+ *
98
+ * @default `${assetsDir}/[name]-[hash].js`
99
+ */
100
+ entryFileNames?: ChunkFileNames;
101
+ /**
102
+ * Naming pattern for shared/dynamic chunks (code splitting). String or a
103
+ * function receiving {@link ChunkInfo}.
104
+ *
105
+ * @default `${assetsDir}/[name]-[hash].js`
106
+ */
107
+ chunkFileNames?: ChunkFileNames;
108
+ /**
109
+ * Naming pattern for emitted assets (images, fonts, …). String or a function
110
+ * receiving {@link AssetInfo}.
111
+ *
112
+ * @default `${assetsDir}/[name]-[hash][extname]`
113
+ */
114
+ assetFileNames?: AssetFileNames;
115
+ }
9
116
  interface Config {
10
117
  /**
11
118
  * Project root. Resolved relative to the current working directory.
@@ -33,6 +140,23 @@ interface Config {
33
140
  * @default "./dist"
34
141
  */
35
142
  outDir?: string;
143
+ /**
144
+ * Public base path the app is served from. Prefixed to built asset and entry
145
+ * URLs so they resolve correctly when deployed under a sub-path or a CDN.
146
+ * Normalised to always start and end with `/` (URLs keep their trailing `/`).
147
+ *
148
+ * @example "/" (default), "/my-app/", "https://cdn.example.com/assets/"
149
+ * @default "/"
150
+ */
151
+ base?: string;
152
+ /**
153
+ * Development server options. See {@link DevConfig}.
154
+ */
155
+ dev?: DevConfig;
156
+ /**
157
+ * Production build options. See {@link BuildConfig}.
158
+ */
159
+ build?: BuildConfig;
36
160
  }
37
161
  /**
38
162
  * A factory form of {@link Config}. Supporting a function (sync or async)
@@ -119,6 +243,20 @@ interface ResolvedPaths {
119
243
  outDir: string;
120
244
  }
121
245
 
246
+ /** Dev-server options after defaults have been applied (no optionals). */
247
+ interface ResolvedDevConfig {
248
+ readonly port: number;
249
+ readonly host: string;
250
+ }
251
+ /** Build options after defaults have been applied (no optionals). */
252
+ interface ResolvedBuildConfig {
253
+ readonly minify: boolean;
254
+ readonly sourcemap: boolean | "inline" | "hidden";
255
+ readonly assetsDir: string;
256
+ readonly entryFileNames: ChunkFileNames;
257
+ readonly chunkFileNames: ChunkFileNames;
258
+ readonly assetFileNames: AssetFileNames;
259
+ }
122
260
  /**
123
261
  * A {@link Config} after defaults have been applied and paths resolved.
124
262
  *
@@ -131,6 +269,12 @@ interface ResolvedConfig {
131
269
  readonly raw: Config;
132
270
  /** Absolute paths derived from the configuration. */
133
271
  readonly paths: ResolvedPaths;
272
+ /** Public base path, normalised to start and end with `/`. */
273
+ readonly base: string;
274
+ /** Resolved dev-server options. */
275
+ readonly dev: ResolvedDevConfig;
276
+ /** Resolved build options. */
277
+ readonly build: ResolvedBuildConfig;
134
278
  /** Absolute path of the config file that was loaded, if any. */
135
279
  readonly configFile: string | null;
136
280
  }
@@ -146,17 +290,31 @@ interface ResolvedConfig {
146
290
  */
147
291
  declare function resolveConfig(raw: Config, cwd: string, configFile?: string | null): ResolvedConfig;
148
292
 
293
+ /**
294
+ * A `<script type="module">` reference discovered in the HTML entry.
295
+ *
296
+ * Only the `src` is captured in v0.2.0. The shape is deliberately an object
297
+ * (rather than a bare string) so later versions can attach resolved paths,
298
+ * inline contents, or transform metadata without breaking consumers.
299
+ */
300
+ interface HtmlModuleScript {
301
+ /** The `src` attribute value, exactly as authored (e.g. `/src/main.ts`). */
302
+ src: string;
303
+ }
149
304
  /**
150
305
  * The HTML entry point of a project, as discovered and parsed by the
151
- * `html` subsystem. Parsing is deliberately minimal in v0.1.0 only what is
152
- * needed to locate the entry — but the shape anticipates richer analysis
153
- * (script tags, module graph roots, asset references) in later versions.
306
+ * `html` subsystem. Parsing stays intentionally lightweightjust enough to
307
+ * locate the entry and its module scripts — but the shape anticipates richer
308
+ * analysis (asset references, injection points, module graph roots) in later
309
+ * versions on the road to HMR and plugin transforms.
154
310
  */
155
311
  interface HtmlEntry {
156
312
  /** Absolute path to the `index.html` file. */
157
313
  file: string;
158
314
  /** Raw HTML contents. */
159
315
  html: string;
316
+ /** Module scripts (`<script type="module" src=...>`) found in the entry. */
317
+ scripts: HtmlModuleScript[];
160
318
  }
161
319
 
162
320
  /**
@@ -167,32 +325,33 @@ interface HtmlEntry {
167
325
  declare function detectHtmlEntry(root: string): Promise<HtmlEntry | null>;
168
326
 
169
327
  /**
170
- * Parses raw HTML into an {@link HtmlEntry}.
328
+ * Parses raw HTML into an {@link HtmlEntry}, extracting `<script type="module">`
329
+ * `src` references.
171
330
  *
172
- * v0.1.0 keeps this intentionally minimal: it only wraps the file path and
173
- * contents. The function exists as the single, isolated home for HTML
174
- * analysis so later versions can grow it (extracting `<script type="module">`
175
- * entries, asset references, injection points for HMR) without scattering
176
- * parsing logic across the codebase.
331
+ * The analysis is intentionally regex-light rather than a full DOM parse: in
332
+ * dev we only need to know the module entry points. This module is the single,
333
+ * isolated home for HTML analysis, so it can grow toward a real parser (for
334
+ * HMR boundaries, plugin transforms, virtual modules) without touching callers.
177
335
  */
178
336
  declare function parseHtml(file: string, html: string): HtmlEntry;
179
337
 
180
- /** Current Vantris version. Kept in sync with package.json at release time. */
181
- declare const VERSION = "0.1.0";
182
-
183
- interface LoggerOptions {
184
- /** When `false`, `debug` calls are dropped. @default false */
185
- verbose?: boolean;
186
- /** Sink for output. Defaults to the console; overridable for tests. */
187
- sink?: Pick<Console, "log" | "warn" | "error">;
188
- }
189
338
  /**
190
- * Creates the default console-backed {@link Logger}.
339
+ * The dev-only live-reload client, injected into the served HTML.
191
340
  *
192
- * The sink is injectable so tests can capture output, and verbosity is a
193
- * construction-time concern rather than a global flag.
341
+ * v0.2.0 does a full page reload on any change. The WebSocket URL is derived
342
+ * from `location.host` so it works regardless of how the host is addressed
343
+ * (`localhost`, `127.0.0.1`, LAN IP). The message payload is ignored for now;
344
+ * v1.x will branch on it to drive HMR instead of a full reload.
194
345
  */
195
- declare function createLogger(options?: LoggerOptions): Logger;
346
+ declare const DEV_CLIENT_SCRIPT = "<script type=\"module\">\n // Injected by Vantris dev server \u2014 live reload (full page).\n const connect = () => {\n const ws = new WebSocket(\"ws://\" + location.host);\n ws.addEventListener(\"message\", () => location.reload());\n // Reconnect if the dev server restarts.\n ws.addEventListener(\"close\", () => setTimeout(connect, 1000));\n };\n connect();\n</script>";
347
+ /**
348
+ * Injects {@link DEV_CLIENT_SCRIPT} into an HTML document.
349
+ *
350
+ * The script is placed just before `</head>` when present, otherwise before
351
+ * `</body>`, otherwise appended — so it loads before user modules without
352
+ * requiring a well-formed document.
353
+ */
354
+ declare function injectDevClient(html: string): string;
196
355
 
197
356
  /**
198
357
  * The execution context threaded into every command.
@@ -210,6 +369,84 @@ interface Context {
210
369
  readonly logger: Logger;
211
370
  }
212
371
 
372
+ /** Options for {@link startDevServer}. */
373
+ interface DevServerOptions {
374
+ ctx: Context;
375
+ /** The detected HTML entry, when present. */
376
+ entry: HtmlEntry | null;
377
+ }
378
+ /** A running dev server. */
379
+ interface DevServerHandle {
380
+ /** Address the server is listening on, e.g. `http://localhost:3000/`. */
381
+ readonly url: string;
382
+ readonly host: string;
383
+ readonly port: number;
384
+ /** Pushes a full-page reload to every connected browser. */
385
+ broadcastReload(): void;
386
+ /** Stops the HTTP and WebSocket servers. */
387
+ close(): Promise<void>;
388
+ }
389
+ /**
390
+ * Starts the H3-based development server.
391
+ *
392
+ * Responsibilities are split across the `server` module: this file owns the
393
+ * HTTP routing (H3) and lifecycle, {@link createStaticLoader} owns file
394
+ * resolution + transpilation, and {@link createReloadSocket} owns live reload.
395
+ * The HTTP and WebSocket servers share a single port.
396
+ */
397
+ declare function startDevServer(options: DevServerOptions): Promise<DevServerHandle>;
398
+
399
+ /** Options handed to the build pipeline. */
400
+ interface BuildOptions {
401
+ ctx: Context;
402
+ /** The detected HTML entry; required for a build. */
403
+ entry: HtmlEntry | null;
404
+ }
405
+ /** Summary of a completed build. */
406
+ interface BuildResult {
407
+ /** Absolute output directory. */
408
+ outDir: string;
409
+ /** Entry points: original HTML `src` → emitted file name. */
410
+ entries: ReadonlyArray<{
411
+ src: string;
412
+ fileName: string;
413
+ }>;
414
+ /** Total build duration in milliseconds. */
415
+ durationMs: number;
416
+ /** Number of files emitted by the bundler (chunks + assets), plus HTML. */
417
+ fileCount: number;
418
+ }
419
+ /**
420
+ * Produces an optimised production build into `outDir`.
421
+ *
422
+ * The pipeline is split across the `build` module by responsibility — entry
423
+ * resolution + HTML ({@link resolveHtmlEntry}/{@link renderProductionHtml}),
424
+ * bundling ({@link bundle}), assets ({@link copyPublicDir}), and filesystem
425
+ * output ({@link cleanOutDir}/{@link writeHtml}). This file only orchestrates
426
+ * and logs, which keeps each stage independently testable and leaves room for
427
+ * future build hooks/plugins to slot between stages.
428
+ *
429
+ * @throws {HtmlEntryError | BuildError} with an explicit message on failure.
430
+ */
431
+ declare function runBuild(options: BuildOptions): Promise<BuildResult>;
432
+
433
+ /** Current Vantris version. Kept in sync with package.json at release time. */
434
+ declare const VERSION = "0.3.0";
435
+
436
+ interface LoggerOptions {
437
+ /** When `false`, `debug` calls are dropped. @default false */
438
+ verbose?: boolean;
439
+ /** Sink for output. Defaults to the console; overridable for tests. */
440
+ sink?: Pick<Console, "log" | "warn" | "error">;
441
+ }
442
+ /**
443
+ * Creates the default console-backed {@link Logger}.
444
+ *
445
+ * The sink is injectable so tests can capture output, and verbosity is a
446
+ * construction-time concern rather than a global flag.
447
+ */
448
+ declare function createLogger(options?: LoggerOptions): Logger;
449
+
213
450
  interface CreateContextOptions {
214
451
  /** Working directory the command was invoked from. */
215
452
  cwd: string;
@@ -227,6 +464,34 @@ interface CreateContextOptions {
227
464
  */
228
465
  declare function createContext(options: CreateContextOptions): Promise<Context>;
229
466
 
467
+ /** A change reported by the {@link Watcher}. */
468
+ interface WatchEvent {
469
+ /** What happened to the file. */
470
+ kind: "add" | "change" | "unlink";
471
+ /** Absolute path of the affected file. */
472
+ file: string;
473
+ }
474
+ interface WatcherOptions {
475
+ /** Directory tree to watch (typically `rootDir`). */
476
+ dir: string;
477
+ logger: Logger;
478
+ /** Called on every relevant filesystem change. */
479
+ onChange: (event: WatchEvent) => void;
480
+ }
481
+ /** A running filesystem watcher. */
482
+ interface Watcher {
483
+ /** Stops watching and releases OS resources. */
484
+ close(): Promise<void>;
485
+ }
486
+ /**
487
+ * Watches a directory tree and reports file changes.
488
+ *
489
+ * This is the single home for filesystem watching — the dev server depends on
490
+ * the {@link Watcher} interface, not on chokidar, so the backing implementation
491
+ * can change (or gain HMR-oriented metadata) without rippling outward.
492
+ */
493
+ declare function createWatcher(options: WatcherOptions): Watcher;
494
+
230
495
  /**
231
496
  * Base class for all errors thrown intentionally by Vantris. The CLI layer can
232
497
  * recognise these and render them cleanly (without a stack trace), while
@@ -244,6 +509,10 @@ declare class ConfigError extends VantrisError {
244
509
  declare class HtmlEntryError extends VantrisError {
245
510
  readonly name = "HtmlEntryError";
246
511
  }
512
+ /** Thrown when the production build fails (bundling, HTML, asset copy, …). */
513
+ declare class BuildError extends VantrisError {
514
+ readonly name = "BuildError";
515
+ }
247
516
  /** Thrown for functionality declared but not yet implemented in this version. */
248
517
  declare class NotImplementedError extends VantrisError {
249
518
  readonly name = "NotImplementedError";
@@ -296,4 +565,4 @@ declare const enum ExitCode {
296
565
  */
297
566
  declare function run(argv: readonly string[], options?: RunOptions): Promise<ExitCode>;
298
567
 
299
- export { type Command, type Config, ConfigError, type ConfigFn, type ConfigInput, type Context, type HtmlEntry, HtmlEntryError, type Logger, NotImplementedError, type ResolvedConfig, type ResolvedPaths, VERSION, VantrisError, commands, createContext, createLogger, defineConfig, detectHtmlEntry, isVantrisError, loadConfig, parseHtml, resolveConfig, run };
568
+ export { type AssetFileNames, type AssetInfo, type BuildConfig, BuildError, type BuildOptions, type BuildResult, type ChunkFileNames, type ChunkInfo, type Command, type Config, ConfigError, type ConfigFn, type ConfigInput, type Context, DEV_CLIENT_SCRIPT, type DevConfig, type DevServerHandle, type DevServerOptions, type HtmlEntry, HtmlEntryError, type HtmlModuleScript, type Logger, NotImplementedError, type ResolvedBuildConfig, type ResolvedConfig, type ResolvedDevConfig, type ResolvedPaths, VERSION, VantrisError, type WatchEvent, type Watcher, type WatcherOptions, commands, createContext, createLogger, createWatcher, defineConfig, detectHtmlEntry, injectDevClient, isVantrisError, loadConfig, parseHtml, resolveConfig, run, runBuild, startDevServer };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- export { ConfigError, HtmlEntryError, NotImplementedError, VERSION, VantrisError, commands, createContext, createLogger, detectHtmlEntry, isVantrisError, loadConfig, parseHtml, resolveConfig, run } from './chunk-PSXNP5S5.js';
1
+ export { BuildError, ConfigError, DEV_CLIENT_SCRIPT, HtmlEntryError, NotImplementedError, VERSION, VantrisError, commands, createContext, createLogger, createWatcher, detectHtmlEntry, injectDevClient, isVantrisError, loadConfig, parseHtml, resolveConfig, run, runBuild, startDevServer } from './chunk-LRSN7SF4.js';
2
2
 
3
3
  // src/config/define-config.ts
4
4
  function defineConfig(config) {
package/package.json CHANGED
@@ -1,10 +1,15 @@
1
1
  {
2
2
  "name": "vantris",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "description": "A modern bundler for JavaScript/TypeScript",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
- "keywords": ["bundler", "build-tool", "dev-server", "typescript"],
7
+ "keywords": [
8
+ "bundler",
9
+ "build-tool",
10
+ "dev-server",
11
+ "typescript"
12
+ ],
8
13
  "bin": {
9
14
  "vantris": "dist/cli/index.js"
10
15
  },
@@ -17,7 +22,9 @@
17
22
  },
18
23
  "main": "./dist/index.js",
19
24
  "types": "./dist/index.d.ts",
20
- "files": ["dist"],
25
+ "files": [
26
+ "dist"
27
+ ],
21
28
  "engines": {
22
29
  "node": ">=20.11.0"
23
30
  },
@@ -25,10 +32,35 @@
25
32
  "build": "tsup",
26
33
  "dev": "tsup --watch",
27
34
  "typecheck": "tsc -p tsconfig.json --noEmit",
35
+ "test": "vitest run",
36
+ "test:watch": "vitest",
28
37
  "clean": "rm -rf dist",
29
38
  "prepublishOnly": "pnpm run build"
30
39
  },
31
40
  "devDependencies": {
32
- "tsup": "^8.3.5"
41
+ "@types/ws": "^8.18.1",
42
+ "less": "^4.6.7",
43
+ "sass": "^1.101.0",
44
+ "tsup": "^8.3.5",
45
+ "vitest": "^4.1.9"
46
+ },
47
+ "dependencies": {
48
+ "chokidar": "^5.0.0",
49
+ "esbuild": "^0.28.1",
50
+ "h3": "2.0.1-rc.22",
51
+ "lightningcss": "^1.32.0",
52
+ "magic-string": "^0.30.21",
53
+ "postcss": "^8.5.15",
54
+ "postcss-load-config": "^6.0.1",
55
+ "rolldown": "^1.1.3",
56
+ "ws": "^8.21.0"
57
+ },
58
+ "peerDependencies": {
59
+ "less": "*",
60
+ "sass": "*"
61
+ },
62
+ "peerDependenciesMeta": {
63
+ "sass": { "optional": true },
64
+ "less": { "optional": true }
33
65
  }
34
66
  }