robuild 0.0.19 → 0.1.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/_chunks/{build-snxBrML1.mjs → build-DbAuaVYJ.mjs} +462 -449
- package/dist/_chunks/build-tpynh1ZI.mjs +3 -0
- package/dist/_chunks/{package-DnMk3fWR.mjs → package-05zYHSH0.mjs} +1 -1
- package/dist/cli.mjs +7 -9
- package/dist/config.d.mts +1 -1
- package/dist/index.mjs +2 -2
- package/package.json +1 -1
- package/dist/_chunks/build-Cm8LX2zF.mjs +0 -3
|
@@ -1,26 +1,115 @@
|
|
|
1
1
|
import { t as RobuildPluginManager } from "./plugin-manager-CwMXjVtp.mjs";
|
|
2
2
|
import { builtinModules } from "node:module";
|
|
3
3
|
import { basename, dirname, extname, isAbsolute, join, relative, resolve } from "node:path";
|
|
4
|
-
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
5
4
|
import { colors } from "consola/utils";
|
|
6
5
|
import prettyBytes from "pretty-bytes";
|
|
7
|
-
import { cp, mkdir, readFile, readdir, symlink, writeFile } from "node:fs/promises";
|
|
8
|
-
import { consola } from "consola";
|
|
6
|
+
import { cp, mkdir, readFile, readdir, rm, symlink, writeFile } from "node:fs/promises";
|
|
9
7
|
import { resolveModulePath } from "exsolve";
|
|
10
8
|
import { parseSync } from "oxc-parser";
|
|
11
9
|
import { rolldown, watch } from "rolldown";
|
|
12
10
|
import { dts } from "rolldown-plugin-dts";
|
|
13
11
|
import { existsSync, promises, readdirSync, statSync } from "node:fs";
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
12
|
+
import { consola } from "consola";
|
|
13
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
16
14
|
import { gzipSync } from "node:zlib";
|
|
17
15
|
import { minify } from "oxc-minify";
|
|
16
|
+
import { glob } from "glob";
|
|
17
|
+
import { createHash } from "node:crypto";
|
|
18
18
|
import MagicString from "magic-string";
|
|
19
19
|
import { transform } from "oxc-transform";
|
|
20
20
|
import { glob as glob$1 } from "tinyglobby";
|
|
21
21
|
import { exec } from "node:child_process";
|
|
22
22
|
import { promisify } from "node:util";
|
|
23
23
|
|
|
24
|
+
//#region src/features/logger.ts
|
|
25
|
+
/**
|
|
26
|
+
* Logger instance with configurable log level
|
|
27
|
+
*/
|
|
28
|
+
var Logger = class {
|
|
29
|
+
level = "info";
|
|
30
|
+
warningCount = 0;
|
|
31
|
+
errorCount = 0;
|
|
32
|
+
constructor(level = "info") {
|
|
33
|
+
this.level = level;
|
|
34
|
+
this.updateConsolaLevel();
|
|
35
|
+
}
|
|
36
|
+
setLevel(level) {
|
|
37
|
+
this.level = level;
|
|
38
|
+
this.updateConsolaLevel();
|
|
39
|
+
}
|
|
40
|
+
updateConsolaLevel() {
|
|
41
|
+
consola.level = {
|
|
42
|
+
silent: 0,
|
|
43
|
+
error: 1,
|
|
44
|
+
warn: 2,
|
|
45
|
+
info: 3,
|
|
46
|
+
verbose: 4
|
|
47
|
+
}[this.level];
|
|
48
|
+
}
|
|
49
|
+
silent(message, ...args) {
|
|
50
|
+
consola.log(message, ...args);
|
|
51
|
+
}
|
|
52
|
+
error(message, ...args) {
|
|
53
|
+
this.errorCount++;
|
|
54
|
+
consola.error(message, ...args);
|
|
55
|
+
}
|
|
56
|
+
warn(message, ...args) {
|
|
57
|
+
this.warningCount++;
|
|
58
|
+
consola.warn(message, ...args);
|
|
59
|
+
}
|
|
60
|
+
info(message, ...args) {
|
|
61
|
+
consola.info(message, ...args);
|
|
62
|
+
}
|
|
63
|
+
verbose(message, ...args) {
|
|
64
|
+
if (this.level === "verbose") consola.debug(message, ...args);
|
|
65
|
+
}
|
|
66
|
+
success(message, ...args) {
|
|
67
|
+
consola.success(message, ...args);
|
|
68
|
+
}
|
|
69
|
+
log(message, ...args) {
|
|
70
|
+
consola.log(message, ...args);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Debug output - only visible with INSPECT_BUILD env var
|
|
74
|
+
*/
|
|
75
|
+
debug(message, ...args) {
|
|
76
|
+
if (process.env.INSPECT_BUILD) consola.log(message, ...args);
|
|
77
|
+
}
|
|
78
|
+
getWarningCount() {
|
|
79
|
+
return this.warningCount;
|
|
80
|
+
}
|
|
81
|
+
getErrorCount() {
|
|
82
|
+
return this.errorCount;
|
|
83
|
+
}
|
|
84
|
+
resetCounts() {
|
|
85
|
+
this.warningCount = 0;
|
|
86
|
+
this.errorCount = 0;
|
|
87
|
+
}
|
|
88
|
+
shouldFailOnWarnings(failOnWarn) {
|
|
89
|
+
return failOnWarn && this.warningCount > 0;
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
const logger = new Logger();
|
|
93
|
+
/**
|
|
94
|
+
* Configure global logger
|
|
95
|
+
*/
|
|
96
|
+
function configureLogger(level) {
|
|
97
|
+
logger.setLevel(level);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Reset warning and error counts
|
|
101
|
+
*/
|
|
102
|
+
function resetLogCounts() {
|
|
103
|
+
logger.resetCounts();
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Check if build should fail due to warnings
|
|
107
|
+
*/
|
|
108
|
+
function shouldFailOnWarnings(failOnWarn) {
|
|
109
|
+
return logger.shouldFailOnWarnings(failOnWarn);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
//#endregion
|
|
24
113
|
//#region src/features/advanced-build.ts
|
|
25
114
|
/**
|
|
26
115
|
* Create skip node_modules plugin
|
|
@@ -91,7 +180,7 @@ async function processFileUnbundled(inputPath, outputPath, entry) {
|
|
|
91
180
|
await mkdir(dirname(finalOutputPath), { recursive: true });
|
|
92
181
|
await writeFile(finalOutputPath, transformedContent, "utf-8");
|
|
93
182
|
} catch (error) {
|
|
94
|
-
|
|
183
|
+
logger.warn(`Failed to process file ${inputPath}:`, error);
|
|
95
184
|
}
|
|
96
185
|
}
|
|
97
186
|
/**
|
|
@@ -184,6 +273,136 @@ function addBannerFooter(content, banner, footer) {
|
|
|
184
273
|
return result;
|
|
185
274
|
}
|
|
186
275
|
|
|
276
|
+
//#endregion
|
|
277
|
+
//#region src/utils.ts
|
|
278
|
+
/**
|
|
279
|
+
* Normalize a path to an absolute path.
|
|
280
|
+
* Handles string paths, URL objects, and undefined values.
|
|
281
|
+
*
|
|
282
|
+
* @param path - The path to normalize (string, URL, or undefined)
|
|
283
|
+
* @param resolveFrom - The base directory to resolve relative paths from
|
|
284
|
+
* @returns The normalized absolute path
|
|
285
|
+
*/
|
|
286
|
+
function normalizePath(path, resolveFrom) {
|
|
287
|
+
return typeof path === "string" && isAbsolute(path) ? path : path instanceof URL ? fileURLToPath(path) : resolve(resolveFrom || ".", path || ".");
|
|
288
|
+
}
|
|
289
|
+
function fmtPath(path) {
|
|
290
|
+
return resolve(path).replace(process.cwd(), ".");
|
|
291
|
+
}
|
|
292
|
+
function analyzeDir(dir) {
|
|
293
|
+
if (Array.isArray(dir)) {
|
|
294
|
+
let totalSize = 0;
|
|
295
|
+
let totalFiles = 0;
|
|
296
|
+
for (const d of dir) {
|
|
297
|
+
const { size, files } = analyzeDir(d);
|
|
298
|
+
totalSize += size;
|
|
299
|
+
totalFiles += files;
|
|
300
|
+
}
|
|
301
|
+
return {
|
|
302
|
+
size: totalSize,
|
|
303
|
+
files: totalFiles
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
let totalSize = 0;
|
|
307
|
+
try {
|
|
308
|
+
const files = readdirSync(dir, {
|
|
309
|
+
withFileTypes: true,
|
|
310
|
+
recursive: true
|
|
311
|
+
});
|
|
312
|
+
for (const file of files) {
|
|
313
|
+
const fullPath = join(file.parentPath, file.name);
|
|
314
|
+
if (file.isFile()) {
|
|
315
|
+
const { size } = statSync(fullPath);
|
|
316
|
+
totalSize += size;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
return {
|
|
320
|
+
size: totalSize,
|
|
321
|
+
files: files.length
|
|
322
|
+
};
|
|
323
|
+
} catch (error) {
|
|
324
|
+
if (error.code === "ENOENT" || error.code === "ENOTDIR") return {
|
|
325
|
+
size: 0,
|
|
326
|
+
files: 0
|
|
327
|
+
};
|
|
328
|
+
throw error;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
async function distSize(dir, entry) {
|
|
332
|
+
const { output } = await (await rolldown({
|
|
333
|
+
input: join(dir, entry),
|
|
334
|
+
plugins: [],
|
|
335
|
+
platform: "neutral",
|
|
336
|
+
external: (id) => id[0] !== "." && !id.startsWith(dir)
|
|
337
|
+
})).generate({ codeSplitting: false });
|
|
338
|
+
const code = output[0].code;
|
|
339
|
+
const { code: minified } = await minify(entry, code);
|
|
340
|
+
return {
|
|
341
|
+
size: Buffer.byteLength(code),
|
|
342
|
+
minSize: Buffer.byteLength(minified),
|
|
343
|
+
minGzipSize: gzipSync(minified).length
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
async function sideEffectSize(dir, entry) {
|
|
347
|
+
const { output } = await (await rolldown({
|
|
348
|
+
input: "#entry",
|
|
349
|
+
platform: "neutral",
|
|
350
|
+
external: (id) => id[0] !== "." && !id.startsWith(dir),
|
|
351
|
+
plugins: [{
|
|
352
|
+
name: "virtual-entry",
|
|
353
|
+
async resolveId(id, importer, opts) {
|
|
354
|
+
if (id === "#entry") return { id };
|
|
355
|
+
const resolved = await this.resolve(id, importer, opts);
|
|
356
|
+
if (!resolved) return null;
|
|
357
|
+
resolved.moduleSideEffects = null;
|
|
358
|
+
return resolved;
|
|
359
|
+
},
|
|
360
|
+
load(id) {
|
|
361
|
+
if (id === "#entry") return `import * as _lib from "${join(dir, entry)}";`;
|
|
362
|
+
}
|
|
363
|
+
}]
|
|
364
|
+
})).generate({ codeSplitting: false });
|
|
365
|
+
if (process.env.INSPECT_BUILD) {
|
|
366
|
+
logger.debug("---------[side effects]---------");
|
|
367
|
+
logger.debug(entry);
|
|
368
|
+
logger.debug(output[0].code);
|
|
369
|
+
logger.debug("-------------------------------");
|
|
370
|
+
}
|
|
371
|
+
return Buffer.byteLength(output[0].code.trim());
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
//#endregion
|
|
375
|
+
//#region src/features/clean.ts
|
|
376
|
+
/**
|
|
377
|
+
* Clean output directory or specific paths.
|
|
378
|
+
* Used by both bundle and transform builders.
|
|
379
|
+
*
|
|
380
|
+
* @param projectRoot - The project root directory
|
|
381
|
+
* @param outDir - The output directory to clean
|
|
382
|
+
* @param cleanPaths - true to clean outDir, or array of specific paths to clean
|
|
383
|
+
*/
|
|
384
|
+
async function cleanOutputDir(projectRoot, outDir, cleanPaths) {
|
|
385
|
+
if (!cleanPaths) return;
|
|
386
|
+
if (cleanPaths === true) {
|
|
387
|
+
if (existsSync(outDir)) {
|
|
388
|
+
logger.log(colors.dim(`Cleaning ${fmtPath(outDir)}`));
|
|
389
|
+
await rm(outDir, {
|
|
390
|
+
recursive: true,
|
|
391
|
+
force: true
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
} else if (Array.isArray(cleanPaths)) for (const path of cleanPaths) {
|
|
395
|
+
const fullPath = resolve(projectRoot, path);
|
|
396
|
+
if (existsSync(fullPath)) {
|
|
397
|
+
logger.log(colors.dim(`Cleaning ${fmtPath(fullPath)}`));
|
|
398
|
+
await rm(fullPath, {
|
|
399
|
+
recursive: true,
|
|
400
|
+
force: true
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
187
406
|
//#endregion
|
|
188
407
|
//#region src/features/copy.ts
|
|
189
408
|
/**
|
|
@@ -191,7 +410,7 @@ function addBannerFooter(content, banner, footer) {
|
|
|
191
410
|
*/
|
|
192
411
|
async function copyFiles(cwd, outDir, copyOptions) {
|
|
193
412
|
if (!copyOptions || copyOptions.length === 0) return;
|
|
194
|
-
|
|
413
|
+
logger.verbose("Copying files...");
|
|
195
414
|
await Promise.all(copyOptions.map(async (entry) => {
|
|
196
415
|
const from = typeof entry === "string" ? entry : entry.from;
|
|
197
416
|
const to = typeof entry === "string" ? resolve(outDir, basename(from)) : resolve(cwd, entry.to);
|
|
@@ -201,12 +420,149 @@ async function copyFiles(cwd, outDir, copyOptions) {
|
|
|
201
420
|
recursive: true,
|
|
202
421
|
force: true
|
|
203
422
|
});
|
|
204
|
-
|
|
423
|
+
logger.verbose(` ${from} → ${to}`);
|
|
205
424
|
} catch (error) {
|
|
206
|
-
|
|
425
|
+
logger.warn(`Failed to copy ${from} to ${to}:`, error);
|
|
207
426
|
}
|
|
208
427
|
}));
|
|
209
|
-
|
|
428
|
+
logger.verbose("Files copied successfully");
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
//#endregion
|
|
432
|
+
//#region src/features/entry-resolver.ts
|
|
433
|
+
/**
|
|
434
|
+
* Parse a string entry format like "src/index.ts:dist" or "src/:dist"
|
|
435
|
+
*
|
|
436
|
+
* @param rawEntry - The raw string entry
|
|
437
|
+
* @returns Parsed entry object
|
|
438
|
+
*/
|
|
439
|
+
function parseEntryString(rawEntry) {
|
|
440
|
+
const [input, outDir] = rawEntry.split(":");
|
|
441
|
+
if (input.endsWith("/")) return {
|
|
442
|
+
type: "transform",
|
|
443
|
+
input,
|
|
444
|
+
outDir: outDir || "dist"
|
|
445
|
+
};
|
|
446
|
+
return {
|
|
447
|
+
type: "bundle",
|
|
448
|
+
input: input.includes(",") ? input.split(",") : input,
|
|
449
|
+
outDir: outDir || "dist"
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
/**
|
|
453
|
+
* Normalize entry input paths to absolute paths.
|
|
454
|
+
* Handles string, array, and object (named entries) formats.
|
|
455
|
+
*
|
|
456
|
+
* @param entryInput - The entry input (string, array, or object)
|
|
457
|
+
* @param pkgDir - The package directory to resolve paths from
|
|
458
|
+
* @returns Normalized input
|
|
459
|
+
*/
|
|
460
|
+
function normalizeEntryInput(entryInput, pkgDir) {
|
|
461
|
+
if (typeof entryInput === "object" && !Array.isArray(entryInput)) {
|
|
462
|
+
const normalizedInput = {};
|
|
463
|
+
for (const [key, value] of Object.entries(entryInput)) normalizedInput[key] = normalizePath(value, pkgDir);
|
|
464
|
+
return normalizedInput;
|
|
465
|
+
}
|
|
466
|
+
if (Array.isArray(entryInput)) return entryInput.map((p) => normalizePath(p, pkgDir));
|
|
467
|
+
return normalizePath(entryInput, pkgDir);
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* Get the entry input from a BundleEntry, supporting both 'input' and 'entry' fields.
|
|
471
|
+
* This provides tsup compatibility.
|
|
472
|
+
*
|
|
473
|
+
* @param entry - The bundle entry
|
|
474
|
+
* @returns The entry input or undefined
|
|
475
|
+
*/
|
|
476
|
+
function getBundleEntryInput(entry) {
|
|
477
|
+
return entry.input || entry.entry;
|
|
478
|
+
}
|
|
479
|
+
/**
|
|
480
|
+
* Check if an entry has valid input.
|
|
481
|
+
*
|
|
482
|
+
* @param entry - The entry to check
|
|
483
|
+
* @returns true if the entry has valid input
|
|
484
|
+
*/
|
|
485
|
+
function hasValidInput(entry) {
|
|
486
|
+
if (entry.type === "transform") return !!entry.input;
|
|
487
|
+
return !!getBundleEntryInput(entry);
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
//#endregion
|
|
491
|
+
//#region src/features/extensions.ts
|
|
492
|
+
/**
|
|
493
|
+
* Get file extension for a given format (with leading dot).
|
|
494
|
+
* This is the unified function used by bundle, watch, and transform modes.
|
|
495
|
+
*
|
|
496
|
+
* @param format - The module format (es, cjs, iife, umd, etc.)
|
|
497
|
+
* @param platform - The target platform
|
|
498
|
+
* @param fixedExtension - Whether to force .cjs/.mjs extensions
|
|
499
|
+
* @returns The file extension with leading dot (e.g., '.mjs', '.cjs', '.js')
|
|
500
|
+
*/
|
|
501
|
+
function getFormatExtension(format, platform = "node", fixedExtension = false) {
|
|
502
|
+
if (fixedExtension) return format === "cjs" || format === "commonjs" ? ".cjs" : ".mjs";
|
|
503
|
+
switch (format) {
|
|
504
|
+
case "es":
|
|
505
|
+
case "esm":
|
|
506
|
+
case "module": return ".mjs";
|
|
507
|
+
case "cjs":
|
|
508
|
+
case "commonjs": return platform === "node" ? ".cjs" : ".js";
|
|
509
|
+
case "iife":
|
|
510
|
+
case "umd": return ".js";
|
|
511
|
+
default: return ".js";
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* Resolve JavaScript output extension (without leading dot).
|
|
516
|
+
* @deprecated Use getFormatExtension() instead for consistency
|
|
517
|
+
*/
|
|
518
|
+
function resolveJsOutputExtension(format, platform = "node", fixedExtension = false) {
|
|
519
|
+
if (fixedExtension) return format === "cjs" ? "cjs" : "mjs";
|
|
520
|
+
switch (format) {
|
|
521
|
+
case "es": return platform === "browser" ? "js" : "mjs";
|
|
522
|
+
case "cjs": return platform === "browser" ? "js" : "cjs";
|
|
523
|
+
case "iife":
|
|
524
|
+
case "umd": return "js";
|
|
525
|
+
default: return "js";
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
/**
|
|
529
|
+
* Resolve DTS output extension
|
|
530
|
+
*/
|
|
531
|
+
function resolveDtsOutputExtension(format, fixedExtension = false) {
|
|
532
|
+
if (fixedExtension) return format === "cjs" ? "d.cts" : "d.mts";
|
|
533
|
+
switch (format) {
|
|
534
|
+
case "es": return "d.mts";
|
|
535
|
+
case "cjs": return "d.cts";
|
|
536
|
+
default: return "d.ts";
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
/**
|
|
540
|
+
* Apply custom output extensions
|
|
541
|
+
*/
|
|
542
|
+
function applyOutExtensions(format, outExtensions) {
|
|
543
|
+
const defaultJs = resolveJsOutputExtension(format);
|
|
544
|
+
const defaultDts = resolveDtsOutputExtension(format);
|
|
545
|
+
if (!outExtensions) return {
|
|
546
|
+
js: defaultJs,
|
|
547
|
+
dts: defaultDts
|
|
548
|
+
};
|
|
549
|
+
const custom = outExtensions(format);
|
|
550
|
+
return {
|
|
551
|
+
js: custom.js || defaultJs,
|
|
552
|
+
dts: custom.dts || defaultDts
|
|
553
|
+
};
|
|
554
|
+
}
|
|
555
|
+
/**
|
|
556
|
+
* Create filename with proper extension
|
|
557
|
+
*/
|
|
558
|
+
function createFilename(basename, format, isDts = false, options = {}) {
|
|
559
|
+
const { platform, fixedExtension, outExtensions } = options;
|
|
560
|
+
if (outExtensions) {
|
|
561
|
+
const extensions = applyOutExtensions(format, outExtensions);
|
|
562
|
+
return `${basename}.${isDts ? extensions.dts : extensions.js}`;
|
|
563
|
+
}
|
|
564
|
+
if (isDts) return `${basename}.${resolveDtsOutputExtension(format, fixedExtension)}`;
|
|
565
|
+
return `${basename}.${resolveJsOutputExtension(format, platform, fixedExtension)}`;
|
|
210
566
|
}
|
|
211
567
|
|
|
212
568
|
//#endregion
|
|
@@ -313,7 +669,7 @@ function createGlobImportPlugin(options = {}) {
|
|
|
313
669
|
if (optionsStr) try {
|
|
314
670
|
globOptions = parseGlobOptions(optionsStr);
|
|
315
671
|
} catch {
|
|
316
|
-
|
|
672
|
+
logger.warn("Failed to parse glob options:", optionsStr);
|
|
317
673
|
}
|
|
318
674
|
const isEager = globOptions.eager ?? eager;
|
|
319
675
|
const isAsUrls = globOptions.as === "url" || asUrls;
|
|
@@ -321,7 +677,7 @@ function createGlobImportPlugin(options = {}) {
|
|
|
321
677
|
const replacement = await generateGlobImport(pattern, id, isEager, isAsUrls, patterns);
|
|
322
678
|
transformedCode = transformedCode.replace(fullMatch, replacement);
|
|
323
679
|
} catch (error) {
|
|
324
|
-
|
|
680
|
+
logger.error(`Failed to process glob import ${pattern}:`, error);
|
|
325
681
|
}
|
|
326
682
|
}
|
|
327
683
|
return hasGlobImports ? transformedCode : null;
|
|
@@ -603,203 +959,74 @@ function addNodeProtocol(id) {
|
|
|
603
959
|
return id;
|
|
604
960
|
}
|
|
605
961
|
/**
|
|
606
|
-
* Remove node: prefix from modules
|
|
607
|
-
*/
|
|
608
|
-
function stripNodeProtocol(id) {
|
|
609
|
-
if (id.startsWith("node:")) return id.slice(5);
|
|
610
|
-
return id;
|
|
611
|
-
}
|
|
612
|
-
/**
|
|
613
|
-
* Process module ID based on nodeProtocol setting
|
|
614
|
-
*/
|
|
615
|
-
function processNodeProtocol(id, nodeProtocol) {
|
|
616
|
-
if (nodeProtocol === "strip") return stripNodeProtocol(id);
|
|
617
|
-
if (nodeProtocol === true) return addNodeProtocol(id);
|
|
618
|
-
return id;
|
|
619
|
-
}
|
|
620
|
-
/**
|
|
621
|
-
* Transform import/export statements to handle node protocol
|
|
622
|
-
*/
|
|
623
|
-
function transformNodeProtocol(code, nodeProtocol) {
|
|
624
|
-
if (!nodeProtocol) return code;
|
|
625
|
-
return code.replace(/(?:import|export)(?:\s[^'"]*)?\s['"]([^'"]+)['"]/g, (match, moduleId) => {
|
|
626
|
-
const processedId = processNodeProtocol(moduleId, nodeProtocol);
|
|
627
|
-
return match.replace(moduleId, processedId);
|
|
628
|
-
});
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
//#endregion
|
|
632
|
-
//#region src/plugins/node-protocol.ts
|
|
633
|
-
/**
|
|
634
|
-
* Rolldown plugin for Node.js protocol handling
|
|
635
|
-
*/
|
|
636
|
-
function nodeProtocolPlugin(nodeProtocol) {
|
|
637
|
-
if (!nodeProtocol) return { name: "node-protocol-noop" };
|
|
638
|
-
return {
|
|
639
|
-
name: "node-protocol",
|
|
640
|
-
renderChunk(code) {
|
|
641
|
-
return {
|
|
642
|
-
code: transformNodeProtocol(code, nodeProtocol),
|
|
643
|
-
map: null
|
|
644
|
-
};
|
|
645
|
-
}
|
|
646
|
-
};
|
|
647
|
-
}
|
|
648
|
-
|
|
649
|
-
//#endregion
|
|
650
|
-
//#region src/plugins/shebang.ts
|
|
651
|
-
const SHEBANG_RE = /^#![^\n]*/;
|
|
652
|
-
function shebangPlugin() {
|
|
653
|
-
return {
|
|
654
|
-
name: "robuild-shebang",
|
|
655
|
-
async writeBundle(options, bundle) {
|
|
656
|
-
for (const [fileName, output] of Object.entries(bundle)) {
|
|
657
|
-
if (output.type !== "chunk") continue;
|
|
658
|
-
if (hasShebang(output.code)) await makeExecutable(resolve(options.dir, fileName));
|
|
659
|
-
}
|
|
660
|
-
}
|
|
661
|
-
};
|
|
662
|
-
}
|
|
663
|
-
function hasShebang(code) {
|
|
664
|
-
return SHEBANG_RE.test(code);
|
|
665
|
-
}
|
|
666
|
-
async function makeExecutable(filePath) {
|
|
667
|
-
await promises.chmod(filePath, 493).catch(() => {});
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
//#endregion
|
|
671
|
-
//#region src/utils.ts
|
|
672
|
-
function fmtPath(path) {
|
|
673
|
-
return resolve(path).replace(process.cwd(), ".");
|
|
674
|
-
}
|
|
675
|
-
function analyzeDir(dir) {
|
|
676
|
-
if (Array.isArray(dir)) {
|
|
677
|
-
let totalSize = 0;
|
|
678
|
-
let totalFiles = 0;
|
|
679
|
-
for (const d of dir) {
|
|
680
|
-
const { size, files } = analyzeDir(d);
|
|
681
|
-
totalSize += size;
|
|
682
|
-
totalFiles += files;
|
|
683
|
-
}
|
|
684
|
-
return {
|
|
685
|
-
size: totalSize,
|
|
686
|
-
files: totalFiles
|
|
687
|
-
};
|
|
688
|
-
}
|
|
689
|
-
let totalSize = 0;
|
|
690
|
-
try {
|
|
691
|
-
const files = readdirSync(dir, {
|
|
692
|
-
withFileTypes: true,
|
|
693
|
-
recursive: true
|
|
694
|
-
});
|
|
695
|
-
for (const file of files) {
|
|
696
|
-
const fullPath = join(file.parentPath, file.name);
|
|
697
|
-
if (file.isFile()) {
|
|
698
|
-
const { size } = statSync(fullPath);
|
|
699
|
-
totalSize += size;
|
|
700
|
-
}
|
|
701
|
-
}
|
|
702
|
-
return {
|
|
703
|
-
size: totalSize,
|
|
704
|
-
files: files.length
|
|
705
|
-
};
|
|
706
|
-
} catch (error) {
|
|
707
|
-
if (error.code === "ENOENT" || error.code === "ENOTDIR") return {
|
|
708
|
-
size: 0,
|
|
709
|
-
files: 0
|
|
710
|
-
};
|
|
711
|
-
throw error;
|
|
712
|
-
}
|
|
713
|
-
}
|
|
714
|
-
async function distSize(dir, entry) {
|
|
715
|
-
const { output } = await (await rolldown({
|
|
716
|
-
input: join(dir, entry),
|
|
717
|
-
plugins: [],
|
|
718
|
-
platform: "neutral",
|
|
719
|
-
external: (id) => id[0] !== "." && !id.startsWith(dir)
|
|
720
|
-
})).generate({ inlineDynamicImports: true });
|
|
721
|
-
const code = output[0].code;
|
|
722
|
-
const { code: minified } = await minify(entry, code);
|
|
723
|
-
return {
|
|
724
|
-
size: Buffer.byteLength(code),
|
|
725
|
-
minSize: Buffer.byteLength(minified),
|
|
726
|
-
minGzipSize: gzipSync(minified).length
|
|
727
|
-
};
|
|
728
|
-
}
|
|
729
|
-
async function sideEffectSize(dir, entry) {
|
|
730
|
-
const { output } = await (await rolldown({
|
|
731
|
-
input: "#entry",
|
|
732
|
-
platform: "neutral",
|
|
733
|
-
external: (id) => id[0] !== "." && !id.startsWith(dir),
|
|
734
|
-
plugins: [{
|
|
735
|
-
name: "virtual-entry",
|
|
736
|
-
async resolveId(id, importer, opts) {
|
|
737
|
-
if (id === "#entry") return { id };
|
|
738
|
-
const resolved = await this.resolve(id, importer, opts);
|
|
739
|
-
if (!resolved) return null;
|
|
740
|
-
resolved.moduleSideEffects = null;
|
|
741
|
-
return resolved;
|
|
742
|
-
},
|
|
743
|
-
load(id) {
|
|
744
|
-
if (id === "#entry") return `import * as _lib from "${join(dir, entry)}";`;
|
|
745
|
-
}
|
|
746
|
-
}]
|
|
747
|
-
})).generate({ inlineDynamicImports: true });
|
|
748
|
-
if (process.env.INSPECT_BUILD) {
|
|
749
|
-
console.log("---------[side effects]---------");
|
|
750
|
-
console.log(entry);
|
|
751
|
-
console.log(output[0].code);
|
|
752
|
-
console.log("-------------------------------");
|
|
753
|
-
}
|
|
754
|
-
return Buffer.byteLength(output[0].code.trim());
|
|
755
|
-
}
|
|
756
|
-
|
|
757
|
-
//#endregion
|
|
758
|
-
//#region src/builders/bundle.ts
|
|
759
|
-
/**
|
|
760
|
-
* Get file extension for format
|
|
962
|
+
* Remove node: prefix from modules
|
|
761
963
|
*/
|
|
762
|
-
function
|
|
763
|
-
if (
|
|
764
|
-
|
|
765
|
-
case "es":
|
|
766
|
-
case "esm":
|
|
767
|
-
case "module": return ".mjs";
|
|
768
|
-
case "cjs":
|
|
769
|
-
case "commonjs": return platform === "node" ? ".cjs" : ".js";
|
|
770
|
-
case "iife":
|
|
771
|
-
case "umd": return ".js";
|
|
772
|
-
default: return ".js";
|
|
773
|
-
}
|
|
964
|
+
function stripNodeProtocol(id) {
|
|
965
|
+
if (id.startsWith("node:")) return id.slice(5);
|
|
966
|
+
return id;
|
|
774
967
|
}
|
|
775
968
|
/**
|
|
776
|
-
*
|
|
969
|
+
* Process module ID based on nodeProtocol setting
|
|
777
970
|
*/
|
|
778
|
-
|
|
779
|
-
if (
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
971
|
+
function processNodeProtocol(id, nodeProtocol) {
|
|
972
|
+
if (nodeProtocol === "strip") return stripNodeProtocol(id);
|
|
973
|
+
if (nodeProtocol === true) return addNodeProtocol(id);
|
|
974
|
+
return id;
|
|
975
|
+
}
|
|
976
|
+
/**
|
|
977
|
+
* Transform import/export statements to handle node protocol
|
|
978
|
+
*/
|
|
979
|
+
function transformNodeProtocol(code, nodeProtocol) {
|
|
980
|
+
if (!nodeProtocol) return code;
|
|
981
|
+
return code.replace(/(?:import|export)(?:\s[^'"]*)?\s['"]([^'"]+)['"]/g, (match, moduleId) => {
|
|
982
|
+
const processedId = processNodeProtocol(moduleId, nodeProtocol);
|
|
983
|
+
return match.replace(moduleId, processedId);
|
|
984
|
+
});
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
//#endregion
|
|
988
|
+
//#region src/plugins/node-protocol.ts
|
|
989
|
+
/**
|
|
990
|
+
* Rolldown plugin for Node.js protocol handling
|
|
991
|
+
*/
|
|
992
|
+
function nodeProtocolPlugin(nodeProtocol) {
|
|
993
|
+
if (!nodeProtocol) return { name: "node-protocol-noop" };
|
|
994
|
+
return {
|
|
995
|
+
name: "node-protocol",
|
|
996
|
+
renderChunk(code) {
|
|
997
|
+
return {
|
|
998
|
+
code: transformNodeProtocol(code, nodeProtocol),
|
|
999
|
+
map: null
|
|
1000
|
+
};
|
|
789
1001
|
}
|
|
790
|
-
}
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
1002
|
+
};
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
//#endregion
|
|
1006
|
+
//#region src/plugins/shebang.ts
|
|
1007
|
+
const SHEBANG_RE = /^#![^\n]*/;
|
|
1008
|
+
function shebangPlugin() {
|
|
1009
|
+
return {
|
|
1010
|
+
name: "robuild-shebang",
|
|
1011
|
+
async writeBundle(options, bundle) {
|
|
1012
|
+
for (const [fileName, output] of Object.entries(bundle)) {
|
|
1013
|
+
if (output.type !== "chunk") continue;
|
|
1014
|
+
if (hasShebang(output.code)) await makeExecutable(resolve(options.dir, fileName));
|
|
1015
|
+
}
|
|
798
1016
|
}
|
|
799
|
-
}
|
|
1017
|
+
};
|
|
1018
|
+
}
|
|
1019
|
+
function hasShebang(code) {
|
|
1020
|
+
return SHEBANG_RE.test(code);
|
|
1021
|
+
}
|
|
1022
|
+
async function makeExecutable(filePath) {
|
|
1023
|
+
await promises.chmod(filePath, 493).catch(() => {});
|
|
800
1024
|
}
|
|
1025
|
+
|
|
1026
|
+
//#endregion
|
|
1027
|
+
//#region src/builders/bundle.ts
|
|
801
1028
|
async function rolldownBuild(ctx, entry, hooks, config) {
|
|
802
|
-
const entryInput = entry
|
|
1029
|
+
const entryInput = getBundleEntryInput(entry);
|
|
803
1030
|
if (!entryInput) throw new Error("Entry input is required");
|
|
804
1031
|
const inputs = normalizeBundleInputs(entryInput, ctx);
|
|
805
1032
|
const pluginManager = new RobuildPluginManager(config || {}, entry, ctx.pkgDir);
|
|
@@ -817,16 +1044,16 @@ async function rolldownBuild(ctx, entry, hooks, config) {
|
|
|
817
1044
|
outDir: fullOutDir
|
|
818
1045
|
});
|
|
819
1046
|
await pluginManager.executeRobuildBuildStart();
|
|
820
|
-
await cleanOutputDir
|
|
1047
|
+
await cleanOutputDir(ctx.pkgDir, fullOutDir, entry.clean ?? true);
|
|
821
1048
|
if (entry.dtsOnly) {
|
|
822
|
-
|
|
1049
|
+
logger.info("Running in dtsOnly mode - only generating declaration files");
|
|
823
1050
|
entry.dts = entry.dts === false ? true : entry.dts || true;
|
|
824
1051
|
}
|
|
825
1052
|
if (entry.stub) {
|
|
826
1053
|
for (const [distName, srcPath] of Object.entries(inputs)) {
|
|
827
1054
|
const distPath = join(ctx.pkgDir, "dist", `${distName}.mjs`);
|
|
828
1055
|
await mkdir(dirname(distPath), { recursive: true });
|
|
829
|
-
|
|
1056
|
+
logger.log(`${colors.cyan("Stub")} ${colors.green(fmtPath(distPath))}`);
|
|
830
1057
|
const srcContents = await readFile(srcPath, "utf8");
|
|
831
1058
|
const hasDefaultExport = parseSync(srcPath, srcContents).module.staticExports.flatMap((e) => e.entries.map((e) => e.exportName.kind === "Default" ? "default" : e.exportName.name)).includes("default");
|
|
832
1059
|
const firstLine = srcContents.split("\n")[0];
|
|
@@ -983,11 +1210,11 @@ async function rolldownBuild(ctx, entry, hooks, config) {
|
|
|
983
1210
|
}
|
|
984
1211
|
if (entry.copy) await copyFiles(ctx.pkgDir, fullOutDir, entry.copy);
|
|
985
1212
|
await pluginManager.executeRobuildBuildEnd({ allOutputEntries });
|
|
986
|
-
|
|
987
|
-
`${colors.
|
|
988
|
-
colors.dim(
|
|
989
|
-
o.exports.some((e) => e !== "default") ? colors.dim(
|
|
990
|
-
o.deps.length > 0 ? colors.dim(
|
|
1213
|
+
logger.log(`\n${allOutputEntries.map((o) => [
|
|
1214
|
+
`${colors.cyan("Bundle")} ${colors.green(fmtPath(filePathMap.get(o.name) || join(fullOutDir, o.name)))}`,
|
|
1215
|
+
colors.dim(` ${prettyBytes(o.size)} / minified: ${prettyBytes(o.minSize)} / gzip: ${prettyBytes(o.minGzipSize)}`),
|
|
1216
|
+
o.exports.some((e) => e !== "default") ? colors.dim(` Exports: ${o.exports.map((e) => e).join(", ")}`) : "",
|
|
1217
|
+
o.deps.length > 0 ? colors.dim(` Dependencies: ${o.deps.join(", ")}`) : ""
|
|
991
1218
|
].filter(Boolean).join("\n")).join("\n\n")}`);
|
|
992
1219
|
}
|
|
993
1220
|
function normalizeBundleInputs(input, ctx) {
|
|
@@ -1026,111 +1253,30 @@ function normalizeBundleInputs(input, ctx) {
|
|
|
1026
1253
|
return inputs;
|
|
1027
1254
|
}
|
|
1028
1255
|
|
|
1029
|
-
//#endregion
|
|
1030
|
-
//#region src/features/extensions.ts
|
|
1031
|
-
/**
|
|
1032
|
-
* Resolve JavaScript output extension
|
|
1033
|
-
*/
|
|
1034
|
-
function resolveJsOutputExtension(format, platform = "node", fixedExtension = false) {
|
|
1035
|
-
if (fixedExtension) return format === "cjs" ? "cjs" : "mjs";
|
|
1036
|
-
switch (format) {
|
|
1037
|
-
case "es": return platform === "browser" ? "js" : "mjs";
|
|
1038
|
-
case "cjs": return platform === "browser" ? "js" : "cjs";
|
|
1039
|
-
case "iife":
|
|
1040
|
-
case "umd": return "js";
|
|
1041
|
-
default: return "js";
|
|
1042
|
-
}
|
|
1043
|
-
}
|
|
1044
|
-
/**
|
|
1045
|
-
* Resolve DTS output extension
|
|
1046
|
-
*/
|
|
1047
|
-
function resolveDtsOutputExtension(format, fixedExtension = false) {
|
|
1048
|
-
if (fixedExtension) return format === "cjs" ? "d.cts" : "d.mts";
|
|
1049
|
-
switch (format) {
|
|
1050
|
-
case "es": return "d.mts";
|
|
1051
|
-
case "cjs": return "d.cts";
|
|
1052
|
-
default: return "d.ts";
|
|
1053
|
-
}
|
|
1054
|
-
}
|
|
1055
|
-
/**
|
|
1056
|
-
* Apply custom output extensions
|
|
1057
|
-
*/
|
|
1058
|
-
function applyOutExtensions(format, outExtensions) {
|
|
1059
|
-
const defaultJs = resolveJsOutputExtension(format);
|
|
1060
|
-
const defaultDts = resolveDtsOutputExtension(format);
|
|
1061
|
-
if (!outExtensions) return {
|
|
1062
|
-
js: defaultJs,
|
|
1063
|
-
dts: defaultDts
|
|
1064
|
-
};
|
|
1065
|
-
const custom = outExtensions(format);
|
|
1066
|
-
return {
|
|
1067
|
-
js: custom.js || defaultJs,
|
|
1068
|
-
dts: custom.dts || defaultDts
|
|
1069
|
-
};
|
|
1070
|
-
}
|
|
1071
|
-
/**
|
|
1072
|
-
* Create filename with proper extension
|
|
1073
|
-
*/
|
|
1074
|
-
function createFilename(basename, format, isDts = false, options = {}) {
|
|
1075
|
-
const { platform, fixedExtension, outExtensions } = options;
|
|
1076
|
-
if (outExtensions) {
|
|
1077
|
-
const extensions = applyOutExtensions(format, outExtensions);
|
|
1078
|
-
return `${basename}.${isDts ? extensions.dts : extensions.js}`;
|
|
1079
|
-
}
|
|
1080
|
-
if (isDts) return `${basename}.${resolveDtsOutputExtension(format, fixedExtension)}`;
|
|
1081
|
-
return `${basename}.${resolveJsOutputExtension(format, platform, fixedExtension)}`;
|
|
1082
|
-
}
|
|
1083
|
-
|
|
1084
1256
|
//#endregion
|
|
1085
1257
|
//#region src/builders/transform.ts
|
|
1086
1258
|
/**
|
|
1087
|
-
* Clean output directory for transform entries
|
|
1088
|
-
*/
|
|
1089
|
-
async function cleanOutputDir(projectRoot, outDir, cleanPaths) {
|
|
1090
|
-
if (!cleanPaths) return;
|
|
1091
|
-
const { rm } = await import("node:fs/promises");
|
|
1092
|
-
const { existsSync } = await import("node:fs");
|
|
1093
|
-
if (cleanPaths === true) {
|
|
1094
|
-
if (existsSync(outDir)) {
|
|
1095
|
-
consola.log(`🧻 Cleaning up ${fmtPath(outDir)}`);
|
|
1096
|
-
await rm(outDir, {
|
|
1097
|
-
recursive: true,
|
|
1098
|
-
force: true
|
|
1099
|
-
});
|
|
1100
|
-
}
|
|
1101
|
-
} else if (Array.isArray(cleanPaths)) for (const path of cleanPaths) {
|
|
1102
|
-
const fullPath = resolve(projectRoot, path);
|
|
1103
|
-
if (existsSync(fullPath)) {
|
|
1104
|
-
consola.log(`🧻 Cleaning up ${fmtPath(fullPath)}`);
|
|
1105
|
-
await rm(fullPath, {
|
|
1106
|
-
recursive: true,
|
|
1107
|
-
force: true
|
|
1108
|
-
});
|
|
1109
|
-
}
|
|
1110
|
-
}
|
|
1111
|
-
}
|
|
1112
|
-
/**
|
|
1113
1259
|
* Transform all .ts modules in a directory using oxc-transform.
|
|
1114
1260
|
*/
|
|
1115
1261
|
async function transformDir(ctx, entry) {
|
|
1116
1262
|
if (entry.stub) {
|
|
1117
|
-
|
|
1263
|
+
logger.log(`${colors.cyan("Stub")} ${colors.green(`${fmtPath(entry.outDir)}/`)}`);
|
|
1118
1264
|
await symlink(entry.input, entry.outDir, "junction");
|
|
1119
1265
|
return;
|
|
1120
1266
|
}
|
|
1121
1267
|
if (entry.unbundle) {
|
|
1122
|
-
|
|
1268
|
+
logger.log(`${colors.cyan("Unbundle")} ${colors.green(`${fmtPath(entry.outDir)}/`)}`);
|
|
1123
1269
|
await unbundleTransform(ctx, entry);
|
|
1124
1270
|
return;
|
|
1125
1271
|
}
|
|
1126
|
-
const fullOutDir =
|
|
1272
|
+
const fullOutDir = normalizePath(entry.outDir || "dist", ctx.pkgDir);
|
|
1127
1273
|
await cleanOutputDir(ctx.pkgDir, fullOutDir, entry.clean ?? true);
|
|
1128
1274
|
const { statSync } = await import("node:fs");
|
|
1129
1275
|
let inputDir = entry.input;
|
|
1130
1276
|
try {
|
|
1131
1277
|
if (statSync(inputDir).isFile()) {
|
|
1132
1278
|
inputDir = dirname(inputDir);
|
|
1133
|
-
|
|
1279
|
+
logger.warn(`Transform input should be a directory, not a file. Using directory: ${fmtPath(inputDir)}`);
|
|
1134
1280
|
}
|
|
1135
1281
|
} catch (error) {
|
|
1136
1282
|
if (error.code !== "ENOENT") throw error;
|
|
@@ -1183,7 +1329,7 @@ async function transformDir(ctx, entry) {
|
|
|
1183
1329
|
})());
|
|
1184
1330
|
const writtenFiles = await Promise.all(promises);
|
|
1185
1331
|
if (entry.copy) await copyFiles(ctx.pkgDir, fullOutDir, entry.copy);
|
|
1186
|
-
|
|
1332
|
+
logger.log(`\n${colors.cyan("Transform")} ${colors.green(`${fmtPath(entry.outDir)}/`)} ${colors.dim(`(${writtenFiles.length} files)`)}`);
|
|
1187
1333
|
}
|
|
1188
1334
|
/**
|
|
1189
1335
|
* Transform a .ts module using oxc-transform.
|
|
@@ -1268,89 +1414,6 @@ async function transformModule(entryPath, entry) {
|
|
|
1268
1414
|
return transformed;
|
|
1269
1415
|
}
|
|
1270
1416
|
|
|
1271
|
-
//#endregion
|
|
1272
|
-
//#region src/features/logger.ts
|
|
1273
|
-
/**
|
|
1274
|
-
* Logger instance with configurable log level
|
|
1275
|
-
*/
|
|
1276
|
-
var Logger = class {
|
|
1277
|
-
level = "info";
|
|
1278
|
-
warningCount = 0;
|
|
1279
|
-
errorCount = 0;
|
|
1280
|
-
constructor(level = "info") {
|
|
1281
|
-
this.level = level;
|
|
1282
|
-
this.updateConsolaLevel();
|
|
1283
|
-
}
|
|
1284
|
-
setLevel(level) {
|
|
1285
|
-
this.level = level;
|
|
1286
|
-
this.updateConsolaLevel();
|
|
1287
|
-
}
|
|
1288
|
-
updateConsolaLevel() {
|
|
1289
|
-
consola.level = {
|
|
1290
|
-
silent: 0,
|
|
1291
|
-
error: 1,
|
|
1292
|
-
warn: 2,
|
|
1293
|
-
info: 3,
|
|
1294
|
-
verbose: 4
|
|
1295
|
-
}[this.level];
|
|
1296
|
-
}
|
|
1297
|
-
silent(message, ...args) {
|
|
1298
|
-
console.log(message, ...args);
|
|
1299
|
-
}
|
|
1300
|
-
error(message, ...args) {
|
|
1301
|
-
this.errorCount++;
|
|
1302
|
-
consola.error(message, ...args);
|
|
1303
|
-
}
|
|
1304
|
-
warn(message, ...args) {
|
|
1305
|
-
this.warningCount++;
|
|
1306
|
-
consola.warn(message, ...args);
|
|
1307
|
-
}
|
|
1308
|
-
info(message, ...args) {
|
|
1309
|
-
consola.info(message, ...args);
|
|
1310
|
-
}
|
|
1311
|
-
verbose(message, ...args) {
|
|
1312
|
-
if (this.level === "verbose") consola.debug(message, ...args);
|
|
1313
|
-
}
|
|
1314
|
-
success(message, ...args) {
|
|
1315
|
-
consola.success(message, ...args);
|
|
1316
|
-
}
|
|
1317
|
-
log(message, ...args) {
|
|
1318
|
-
consola.log(message, ...args);
|
|
1319
|
-
}
|
|
1320
|
-
getWarningCount() {
|
|
1321
|
-
return this.warningCount;
|
|
1322
|
-
}
|
|
1323
|
-
getErrorCount() {
|
|
1324
|
-
return this.errorCount;
|
|
1325
|
-
}
|
|
1326
|
-
resetCounts() {
|
|
1327
|
-
this.warningCount = 0;
|
|
1328
|
-
this.errorCount = 0;
|
|
1329
|
-
}
|
|
1330
|
-
shouldFailOnWarnings(failOnWarn) {
|
|
1331
|
-
return failOnWarn && this.warningCount > 0;
|
|
1332
|
-
}
|
|
1333
|
-
};
|
|
1334
|
-
const logger = new Logger();
|
|
1335
|
-
/**
|
|
1336
|
-
* Configure global logger
|
|
1337
|
-
*/
|
|
1338
|
-
function configureLogger(level) {
|
|
1339
|
-
logger.setLevel(level);
|
|
1340
|
-
}
|
|
1341
|
-
/**
|
|
1342
|
-
* Reset warning and error counts
|
|
1343
|
-
*/
|
|
1344
|
-
function resetLogCounts() {
|
|
1345
|
-
logger.resetCounts();
|
|
1346
|
-
}
|
|
1347
|
-
/**
|
|
1348
|
-
* Check if build should fail due to warnings
|
|
1349
|
-
*/
|
|
1350
|
-
function shouldFailOnWarnings(failOnWarn) {
|
|
1351
|
-
return logger.shouldFailOnWarnings(failOnWarn);
|
|
1352
|
-
}
|
|
1353
|
-
|
|
1354
1417
|
//#endregion
|
|
1355
1418
|
//#region src/features/on-success.ts
|
|
1356
1419
|
const execAsync = promisify(exec);
|
|
@@ -1501,14 +1564,11 @@ function convertExternal(external) {
|
|
|
1501
1564
|
|
|
1502
1565
|
//#endregion
|
|
1503
1566
|
//#region src/watch.ts
|
|
1504
|
-
function normalizePath$1(path, resolveFrom) {
|
|
1505
|
-
return typeof path === "string" && isAbsolute(path) ? path : path instanceof URL ? fileURLToPath(path) : resolve(resolveFrom || ".", path || ".");
|
|
1506
|
-
}
|
|
1507
1567
|
/**
|
|
1508
1568
|
* Perform watch build using rolldown's built-in watch mode
|
|
1509
1569
|
*/
|
|
1510
1570
|
async function performWatchBuild(config, ctx, startTime) {
|
|
1511
|
-
const { performBuild } = await import("./build-
|
|
1571
|
+
const { performBuild } = await import("./build-tpynh1ZI.mjs");
|
|
1512
1572
|
await performBuild(config, ctx, startTime);
|
|
1513
1573
|
const bundleEntries = (config.entries || []).filter((entry) => {
|
|
1514
1574
|
if (typeof entry === "string") return !entry.endsWith("/");
|
|
@@ -1528,45 +1588,22 @@ async function performWatchBuild(config, ctx, startTime) {
|
|
|
1528
1588
|
* The watch mode then monitors for file changes and triggers rebuilds.
|
|
1529
1589
|
*/
|
|
1530
1590
|
async function startRolldownWatch(config, ctx, bundleEntries) {
|
|
1531
|
-
logger.info("
|
|
1591
|
+
logger.info("Watching for changes...");
|
|
1532
1592
|
const { RobuildPluginManager } = await import("./plugin-manager-pCQvlo7q.mjs");
|
|
1533
1593
|
const watchConfigs = [];
|
|
1534
1594
|
for (const rawEntry of bundleEntries) {
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
const [input, outDir] = rawEntry.split(":");
|
|
1538
|
-
entry = {
|
|
1539
|
-
type: "bundle",
|
|
1540
|
-
input,
|
|
1541
|
-
outDir: outDir || "dist"
|
|
1542
|
-
};
|
|
1543
|
-
} else entry = rawEntry;
|
|
1544
|
-
const entryInput = entry.input || entry.entry;
|
|
1595
|
+
const entry = typeof rawEntry === "string" ? parseEntryString(rawEntry) : rawEntry;
|
|
1596
|
+
const entryInput = getBundleEntryInput(entry);
|
|
1545
1597
|
if (!entryInput) {
|
|
1546
1598
|
logger.warn("Skipping entry without input:", entry);
|
|
1547
1599
|
continue;
|
|
1548
1600
|
}
|
|
1549
|
-
|
|
1550
|
-
if (typeof entryInput === "object" && !Array.isArray(entryInput)) {
|
|
1551
|
-
const normalizedObj = {};
|
|
1552
|
-
for (const [key, value] of Object.entries(entryInput)) normalizedObj[key] = normalizePath$1(value, ctx.pkgDir);
|
|
1553
|
-
normalizedInput = normalizedObj;
|
|
1554
|
-
} else if (Array.isArray(entryInput)) normalizedInput = entryInput.map((i) => normalizePath$1(i, ctx.pkgDir));
|
|
1555
|
-
else normalizedInput = normalizePath$1(entryInput, ctx.pkgDir);
|
|
1601
|
+
const normalizedInput = normalizeEntryInput(entryInput, ctx.pkgDir);
|
|
1556
1602
|
const target = entry.target || "es2022";
|
|
1557
1603
|
const platform = entry.platform || "node";
|
|
1558
1604
|
const format = entry.format || "es";
|
|
1559
|
-
const getExtension = (fmt) => {
|
|
1560
|
-
switch (fmt) {
|
|
1561
|
-
case "es": return ".mjs";
|
|
1562
|
-
case "cjs": return ".cjs";
|
|
1563
|
-
case "iife":
|
|
1564
|
-
case "umd": return ".js";
|
|
1565
|
-
default: return ".mjs";
|
|
1566
|
-
}
|
|
1567
|
-
};
|
|
1568
|
-
const extension = getExtension(Array.isArray(format) ? format[0] : format);
|
|
1569
1605
|
const rolldownFormat = Array.isArray(format) ? format[0] : format;
|
|
1606
|
+
const extension = getFormatExtension(rolldownFormat, platform);
|
|
1570
1607
|
const formatMap = {
|
|
1571
1608
|
esm: "es",
|
|
1572
1609
|
cjs: "cjs",
|
|
@@ -1601,24 +1638,20 @@ async function startRolldownWatch(config, ctx, bundleEntries) {
|
|
|
1601
1638
|
watcher.on("event", (event) => {
|
|
1602
1639
|
switch (event.code) {
|
|
1603
1640
|
case "START":
|
|
1604
|
-
logger.info("
|
|
1605
|
-
break;
|
|
1606
|
-
case "BUNDLE_START":
|
|
1607
|
-
logger.info("📦 Bundling...");
|
|
1608
|
-
break;
|
|
1609
|
-
case "BUNDLE_END":
|
|
1610
|
-
logger.success("✅ Bundle complete");
|
|
1641
|
+
logger.info("Rebuilding...");
|
|
1611
1642
|
break;
|
|
1643
|
+
case "BUNDLE_START": break;
|
|
1644
|
+
case "BUNDLE_END": break;
|
|
1612
1645
|
case "END":
|
|
1613
|
-
logger.success("
|
|
1646
|
+
logger.success("Rebuilt");
|
|
1614
1647
|
break;
|
|
1615
1648
|
case "ERROR":
|
|
1616
|
-
logger.error("
|
|
1649
|
+
logger.error("Build error:", event.error);
|
|
1617
1650
|
break;
|
|
1618
1651
|
}
|
|
1619
1652
|
});
|
|
1620
1653
|
const cleanup = async () => {
|
|
1621
|
-
|
|
1654
|
+
logger.info("Stopping watch mode...");
|
|
1622
1655
|
await watcher.close();
|
|
1623
1656
|
process.exit(0);
|
|
1624
1657
|
};
|
|
@@ -1704,11 +1737,11 @@ async function build(config) {
|
|
|
1704
1737
|
}
|
|
1705
1738
|
finalConfig = normalizeTsupConfig(finalConfig);
|
|
1706
1739
|
if (finalConfig.watch?.enabled) {
|
|
1707
|
-
logger.info(
|
|
1740
|
+
logger.info(`Watching ${colors.cyan(ctx.pkg.name || "<unnamed>")}`);
|
|
1708
1741
|
await performWatchBuild(finalConfig, ctx, startTime);
|
|
1709
1742
|
return;
|
|
1710
1743
|
}
|
|
1711
|
-
logger.info(
|
|
1744
|
+
logger.info(`Building ${colors.cyan(ctx.pkg.name || "<unnamed>")}`);
|
|
1712
1745
|
await performBuild(finalConfig, ctx, startTime);
|
|
1713
1746
|
}
|
|
1714
1747
|
/**
|
|
@@ -1719,34 +1752,17 @@ async function performBuild(config, ctx, startTime) {
|
|
|
1719
1752
|
const hooks = config.hooks || {};
|
|
1720
1753
|
await hooks.start?.(ctx);
|
|
1721
1754
|
const entries = (config.entries || []).map((rawEntry) => {
|
|
1722
|
-
let entry;
|
|
1723
|
-
if (typeof rawEntry === "string") {
|
|
1724
|
-
const [input, outDir] = rawEntry.split(":");
|
|
1725
|
-
entry = input.endsWith("/") ? {
|
|
1726
|
-
type: "transform",
|
|
1727
|
-
input,
|
|
1728
|
-
outDir
|
|
1729
|
-
} : {
|
|
1730
|
-
type: "bundle",
|
|
1731
|
-
input: input.split(","),
|
|
1732
|
-
outDir
|
|
1733
|
-
};
|
|
1734
|
-
} else entry = rawEntry;
|
|
1755
|
+
let entry = typeof rawEntry === "string" ? parseEntryString(rawEntry) : rawEntry;
|
|
1735
1756
|
if (entry.type === "bundle") entry = inheritConfig(entry, config);
|
|
1736
1757
|
else if (entry.type === "transform") entry = inheritConfig(entry, config);
|
|
1737
|
-
if (!(entry
|
|
1758
|
+
if (!hasValidInput(entry)) throw new Error(`Build entry missing \`input\` or \`entry\`: ${JSON.stringify(entry, null, 2)}`);
|
|
1738
1759
|
entry = { ...entry };
|
|
1739
1760
|
entry.outDir = normalizePath(entry.outDir || "dist", ctx.pkgDir);
|
|
1740
1761
|
if (entry.type === "transform") {
|
|
1741
1762
|
if (entry.input) entry.input = normalizePath(entry.input, ctx.pkgDir);
|
|
1742
1763
|
} else {
|
|
1743
|
-
const entryInput = entry
|
|
1744
|
-
if (entryInput)
|
|
1745
|
-
const normalizedInput = {};
|
|
1746
|
-
for (const [key, value] of Object.entries(entryInput)) normalizedInput[key] = normalizePath(value, ctx.pkgDir);
|
|
1747
|
-
entry.input = normalizedInput;
|
|
1748
|
-
} else if (Array.isArray(entryInput)) entry.input = entryInput.map((p) => normalizePath(p, ctx.pkgDir));
|
|
1749
|
-
else entry.input = normalizePath(entryInput, ctx.pkgDir);
|
|
1764
|
+
const entryInput = getBundleEntryInput(entry);
|
|
1765
|
+
if (entryInput) entry.input = normalizeEntryInput(entryInput, ctx.pkgDir);
|
|
1750
1766
|
}
|
|
1751
1767
|
return entry;
|
|
1752
1768
|
});
|
|
@@ -1757,20 +1773,17 @@ async function performBuild(config, ctx, startTime) {
|
|
|
1757
1773
|
await hooks.end?.(ctx);
|
|
1758
1774
|
if (shouldFailOnWarnings(config.failOnWarn || false)) throw new Error("Build failed due to warnings");
|
|
1759
1775
|
const dirSize = analyzeDir(outDirs);
|
|
1760
|
-
logger.info(colors.dim(`\
|
|
1776
|
+
logger.info(colors.dim(`\nTotal: ${colors.bold(prettyBytes(dirSize.size))} (${dirSize.files} files)`));
|
|
1761
1777
|
const duration = Date.now() - start;
|
|
1762
|
-
logger.success(`\
|
|
1778
|
+
logger.success(`\nBuild succeeded in ${colors.bold(`${duration}ms`)}`);
|
|
1763
1779
|
if (config.onSuccess) {
|
|
1764
1780
|
const buildResult = createBuildResult([], startTime);
|
|
1765
1781
|
await executeOnSuccess(config.onSuccess, buildResult, ctx.pkgDir);
|
|
1766
1782
|
}
|
|
1767
1783
|
}
|
|
1768
|
-
function normalizePath(path, resolveFrom) {
|
|
1769
|
-
return typeof path === "string" && isAbsolute(path) ? path : path instanceof URL ? fileURLToPath(path) : resolve(resolveFrom || ".", path || ".");
|
|
1770
|
-
}
|
|
1771
1784
|
async function readJSON(specifier) {
|
|
1772
1785
|
return (await import(specifier, { with: { type: "json" } })).default;
|
|
1773
1786
|
}
|
|
1774
1787
|
|
|
1775
1788
|
//#endregion
|
|
1776
|
-
export { makeExecutable as a, hasShebang as i, performBuild as n, shebangPlugin as o, SHEBANG_RE as r, nodeProtocolPlugin as s, build as t };
|
|
1789
|
+
export { makeExecutable as a, configureLogger as c, hasShebang as i, logger as l, performBuild as n, shebangPlugin as o, SHEBANG_RE as r, nodeProtocolPlugin as s, build as t };
|
package/dist/cli.mjs
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { t as build } from "./_chunks/build-
|
|
2
|
+
import { c as configureLogger, l as logger, t as build } from "./_chunks/build-DbAuaVYJ.mjs";
|
|
3
3
|
import { colors } from "consola/utils";
|
|
4
|
-
import { consola } from "consola";
|
|
5
4
|
import process from "node:process";
|
|
6
5
|
import { loadConfig } from "c12";
|
|
7
6
|
import { cac } from "cac";
|
|
@@ -17,14 +16,13 @@ cli.command("[...entries]", "Bundle or transform files", {
|
|
|
17
16
|
try {
|
|
18
17
|
await runBuild(entries, flags);
|
|
19
18
|
} catch (error) {
|
|
20
|
-
|
|
19
|
+
logger.error(String(error));
|
|
21
20
|
process.exit(1);
|
|
22
21
|
}
|
|
23
22
|
});
|
|
24
23
|
async function runBuild(entries, flags) {
|
|
25
|
-
if (flags.logLevel)
|
|
26
|
-
|
|
27
|
-
consola.info("");
|
|
24
|
+
if (flags.logLevel) configureLogger(flags.logLevel);
|
|
25
|
+
logger.info(`${colors.cyan("robuild")} ${colors.dim(`v${pkg.default.version}`)}`);
|
|
28
26
|
const configOptions = {
|
|
29
27
|
name: "robuild",
|
|
30
28
|
cwd: flags.dir || "."
|
|
@@ -102,8 +100,8 @@ async function runBuild(entries, flags) {
|
|
|
102
100
|
});
|
|
103
101
|
if (flags.stub) for (const entry of processedEntries) entry.stub = true;
|
|
104
102
|
if (rawEntries.length === 0) {
|
|
105
|
-
|
|
106
|
-
|
|
103
|
+
logger.error("No build entries specified.");
|
|
104
|
+
logger.info("Run `robuild --help` for usage information.");
|
|
107
105
|
process.exit(1);
|
|
108
106
|
}
|
|
109
107
|
await build({
|
|
@@ -130,7 +128,7 @@ cli.parse(process.argv, { run: false });
|
|
|
130
128
|
try {
|
|
131
129
|
await cli.runMatchedCommand();
|
|
132
130
|
} catch (error) {
|
|
133
|
-
|
|
131
|
+
logger.error(String(error));
|
|
134
132
|
process.exit(1);
|
|
135
133
|
}
|
|
136
134
|
|
package/dist/config.d.mts
CHANGED
|
@@ -13,7 +13,7 @@ type Platform = 'browser' | 'node' | 'neutral';
|
|
|
13
13
|
/**
|
|
14
14
|
* Target ES version
|
|
15
15
|
*/
|
|
16
|
-
type Target = '
|
|
16
|
+
type Target = 'es2015' | 'es2016' | 'es2017' | 'es2018' | 'es2019' | 'es2020' | 'es2021' | 'es2022' | 'esnext';
|
|
17
17
|
interface CopyEntry {
|
|
18
18
|
from: string;
|
|
19
19
|
to: string;
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as makeExecutable, i as hasShebang, o as shebangPlugin, r as SHEBANG_RE, s as nodeProtocolPlugin, t as build } from "./_chunks/build-
|
|
1
|
+
import { a as makeExecutable, i as hasShebang, l as logger, o as shebangPlugin, r as SHEBANG_RE, s as nodeProtocolPlugin, t as build } from "./_chunks/build-DbAuaVYJ.mjs";
|
|
2
2
|
import { defineConfig } from "./config.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/features/plugin-utils.ts
|
|
@@ -132,7 +132,7 @@ function textPlugin(extensions = [".txt", ".md"]) {
|
|
|
132
132
|
const content = await readFile(id, "utf-8");
|
|
133
133
|
return `export default ${JSON.stringify(content)}`;
|
|
134
134
|
} catch (error) {
|
|
135
|
-
|
|
135
|
+
logger.error(`Failed to load text file ${id}:`, error);
|
|
136
136
|
return null;
|
|
137
137
|
}
|
|
138
138
|
return null;
|
package/package.json
CHANGED