robuild 0.0.18 → 0.0.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -6
- package/dist/_chunks/build-B-lzI2ff.mjs +3 -0
- package/dist/_chunks/{build-omZA_xD-.mjs → build-ZNO1BJMb.mjs} +584 -560
- package/dist/_chunks/package-CspMOSID.mjs +80 -0
- package/dist/_chunks/{plugin-manager-w5yRGJRn.mjs → plugin-manager-CwMXjVtp.mjs} +2 -2
- package/dist/_chunks/plugin-manager-pCQvlo7q.mjs +3 -0
- package/dist/cli.mjs +12 -16
- package/dist/config.d.mts +726 -2
- package/dist/config.mjs +5 -1
- package/dist/config2.d.mts +2 -0
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +7 -10
- package/package.json +16 -9
- package/dist/_chunks/build-S2eglIZn.mjs +0 -4
- package/dist/_chunks/config-2CRkKJ3l.d.mts +0 -726
- package/dist/_chunks/config-BsKCDKT5.mjs +0 -7
- package/dist/_chunks/package-B75WwJYL.mjs +0 -88
- package/dist/_chunks/plugin-manager-WN1-NA--.mjs +0 -3
|
@@ -1,26 +1,115 @@
|
|
|
1
|
-
import { RobuildPluginManager } from "./plugin-manager-
|
|
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
|
|
@@ -52,9 +141,7 @@ function createSkipNodeModulesPlugin(options) {
|
|
|
52
141
|
* Unbundle mode: preserve file structure without bundling
|
|
53
142
|
*/
|
|
54
143
|
async function unbundleTransform(ctx, entry) {
|
|
55
|
-
|
|
56
|
-
const outputDir = join(ctx.pkgDir, entry.outDir || "dist");
|
|
57
|
-
await processDirectoryUnbundled(inputDir, outputDir, entry);
|
|
144
|
+
await processDirectoryUnbundled(isAbsolute(entry.input) ? entry.input : join(ctx.pkgDir, entry.input), join(ctx.pkgDir, entry.outDir || "dist"), entry);
|
|
58
145
|
}
|
|
59
146
|
/**
|
|
60
147
|
* Process directory in unbundle mode
|
|
@@ -87,14 +174,13 @@ async function processFileUnbundled(inputPath, outputPath, entry) {
|
|
|
87
174
|
".cts"
|
|
88
175
|
].includes(ext)) return;
|
|
89
176
|
try {
|
|
90
|
-
const
|
|
91
|
-
const transformedContent = transformImportsForUnbundle(content, inputPath, entry);
|
|
177
|
+
const transformedContent = transformImportsForUnbundle(await readFile(inputPath, "utf-8"), inputPath, entry);
|
|
92
178
|
const outputExt = getUnbundleOutputExtension(ext, entry);
|
|
93
179
|
const finalOutputPath = outputPath.replace(ext, outputExt);
|
|
94
180
|
await mkdir(dirname(finalOutputPath), { recursive: true });
|
|
95
181
|
await writeFile(finalOutputPath, transformedContent, "utf-8");
|
|
96
182
|
} catch (error) {
|
|
97
|
-
|
|
183
|
+
logger.warn(`Failed to process file ${inputPath}:`, error);
|
|
98
184
|
}
|
|
99
185
|
}
|
|
100
186
|
/**
|
|
@@ -159,10 +245,9 @@ function getUnbundleOutputExtension(inputExt, entry) {
|
|
|
159
245
|
* Resolve banner/footer addon for specific format
|
|
160
246
|
*/
|
|
161
247
|
function resolveChunkAddon(addon, format) {
|
|
162
|
-
if (!addon) return
|
|
248
|
+
if (!addon) return;
|
|
163
249
|
if (typeof addon === "string") return addon;
|
|
164
|
-
|
|
165
|
-
return addon[formatKey] || addon.js;
|
|
250
|
+
return addon[format === "es" ? "js" : format] || addon.js;
|
|
166
251
|
}
|
|
167
252
|
/**
|
|
168
253
|
* Add banner to content
|
|
@@ -188,6 +273,136 @@ function addBannerFooter(content, banner, footer) {
|
|
|
188
273
|
return result;
|
|
189
274
|
}
|
|
190
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({ inlineDynamicImports: true });
|
|
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({ inlineDynamicImports: true });
|
|
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
|
+
|
|
191
406
|
//#endregion
|
|
192
407
|
//#region src/features/copy.ts
|
|
193
408
|
/**
|
|
@@ -195,7 +410,7 @@ function addBannerFooter(content, banner, footer) {
|
|
|
195
410
|
*/
|
|
196
411
|
async function copyFiles(cwd, outDir, copyOptions) {
|
|
197
412
|
if (!copyOptions || copyOptions.length === 0) return;
|
|
198
|
-
|
|
413
|
+
logger.verbose("Copying files...");
|
|
199
414
|
await Promise.all(copyOptions.map(async (entry) => {
|
|
200
415
|
const from = typeof entry === "string" ? entry : entry.from;
|
|
201
416
|
const to = typeof entry === "string" ? resolve(outDir, basename(from)) : resolve(cwd, entry.to);
|
|
@@ -205,12 +420,231 @@ async function copyFiles(cwd, outDir, copyOptions) {
|
|
|
205
420
|
recursive: true,
|
|
206
421
|
force: true
|
|
207
422
|
});
|
|
208
|
-
|
|
423
|
+
logger.verbose(` ${from} → ${to}`);
|
|
209
424
|
} catch (error) {
|
|
210
|
-
|
|
425
|
+
logger.warn(`Failed to copy ${from} to ${to}:`, error);
|
|
211
426
|
}
|
|
212
427
|
}));
|
|
213
|
-
|
|
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)}`;
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
//#endregion
|
|
569
|
+
//#region src/features/external.ts
|
|
570
|
+
/**
|
|
571
|
+
* Build external dependencies list from package.json dependencies and peerDependencies.
|
|
572
|
+
* This is the shared logic used by both bundle and watch modes.
|
|
573
|
+
*/
|
|
574
|
+
function buildExternalDeps(ctx) {
|
|
575
|
+
return [
|
|
576
|
+
...builtinModules,
|
|
577
|
+
...builtinModules.map((m) => `node:${m}`),
|
|
578
|
+
...[...Object.keys(ctx.pkg.dependencies || {}), ...Object.keys(ctx.pkg.peerDependencies || {})].flatMap((p) => [p, new RegExp(`^${p}/`)])
|
|
579
|
+
];
|
|
580
|
+
}
|
|
581
|
+
/**
|
|
582
|
+
* Escape special regex characters in a string
|
|
583
|
+
*/
|
|
584
|
+
function escapeRegExp(s) {
|
|
585
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
586
|
+
}
|
|
587
|
+
/**
|
|
588
|
+
* Apply noExternal configuration to filter out dependencies that should be bundled.
|
|
589
|
+
* Supports both function and array forms.
|
|
590
|
+
*/
|
|
591
|
+
function applyNoExternal(externalDeps, noExternal, ctx) {
|
|
592
|
+
if (!noExternal) return externalDeps;
|
|
593
|
+
if (typeof noExternal === "function") {
|
|
594
|
+
const predicate = noExternal;
|
|
595
|
+
const depNames = [...Object.keys(ctx.pkg.dependencies || {}), ...Object.keys(ctx.pkg.peerDependencies || {})];
|
|
596
|
+
const excludedNames = /* @__PURE__ */ new Set();
|
|
597
|
+
for (const name of depNames) try {
|
|
598
|
+
if (predicate(name)) excludedNames.add(name);
|
|
599
|
+
} catch {}
|
|
600
|
+
return externalDeps.filter((dep) => {
|
|
601
|
+
if (typeof dep === "string") return !excludedNames.has(dep);
|
|
602
|
+
if (dep instanceof RegExp) {
|
|
603
|
+
for (const name of Array.from(excludedNames)) if (dep.source.startsWith(`^${escapeRegExp(name)}/`)) return false;
|
|
604
|
+
return true;
|
|
605
|
+
}
|
|
606
|
+
return true;
|
|
607
|
+
});
|
|
608
|
+
}
|
|
609
|
+
if (Array.isArray(noExternal)) {
|
|
610
|
+
const rules = noExternal;
|
|
611
|
+
return externalDeps.filter((dep) => {
|
|
612
|
+
for (const rule of rules) if (typeof rule === "string") {
|
|
613
|
+
if (typeof dep === "string") {
|
|
614
|
+
if (dep === rule) return false;
|
|
615
|
+
} else if (dep instanceof RegExp) {
|
|
616
|
+
if (dep.source.startsWith(`^${escapeRegExp(rule)}/`)) return false;
|
|
617
|
+
}
|
|
618
|
+
} else if (rule instanceof RegExp) {
|
|
619
|
+
if (typeof dep === "string") {
|
|
620
|
+
if (rule.test(dep)) return false;
|
|
621
|
+
} else if (dep instanceof RegExp) {
|
|
622
|
+
if (dep.source === rule.source && dep.flags === rule.flags) return false;
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
return true;
|
|
626
|
+
});
|
|
627
|
+
}
|
|
628
|
+
return externalDeps;
|
|
629
|
+
}
|
|
630
|
+
/**
|
|
631
|
+
* Add custom external dependencies to the list.
|
|
632
|
+
* Only handles array form; function form is handled separately.
|
|
633
|
+
*/
|
|
634
|
+
function addCustomExternal(externalDeps, external) {
|
|
635
|
+
if (external && typeof external !== "function") return [...externalDeps, ...external];
|
|
636
|
+
return externalDeps;
|
|
637
|
+
}
|
|
638
|
+
/**
|
|
639
|
+
* Build the complete external configuration for rolldown.
|
|
640
|
+
* Returns either a function (if entry.external is a function) or the processed array.
|
|
641
|
+
*/
|
|
642
|
+
function resolveExternalConfig(ctx, options) {
|
|
643
|
+
let externalDeps = buildExternalDeps(ctx);
|
|
644
|
+
externalDeps = applyNoExternal(externalDeps, options.noExternal, ctx);
|
|
645
|
+
externalDeps = addCustomExternal(externalDeps, options.external);
|
|
646
|
+
if (typeof options.external === "function") return options.external;
|
|
647
|
+
return externalDeps;
|
|
214
648
|
}
|
|
215
649
|
|
|
216
650
|
//#endregion
|
|
@@ -235,7 +669,7 @@ function createGlobImportPlugin(options = {}) {
|
|
|
235
669
|
if (optionsStr) try {
|
|
236
670
|
globOptions = parseGlobOptions(optionsStr);
|
|
237
671
|
} catch {
|
|
238
|
-
|
|
672
|
+
logger.warn("Failed to parse glob options:", optionsStr);
|
|
239
673
|
}
|
|
240
674
|
const isEager = globOptions.eager ?? eager;
|
|
241
675
|
const isAsUrls = globOptions.as === "url" || asUrls;
|
|
@@ -243,7 +677,7 @@ function createGlobImportPlugin(options = {}) {
|
|
|
243
677
|
const replacement = await generateGlobImport(pattern, id, isEager, isAsUrls, patterns);
|
|
244
678
|
transformedCode = transformedCode.replace(fullMatch, replacement);
|
|
245
679
|
} catch (error) {
|
|
246
|
-
|
|
680
|
+
logger.error(`Failed to process glob import ${pattern}:`, error);
|
|
247
681
|
}
|
|
248
682
|
}
|
|
249
683
|
return hasGlobImports ? transformedCode : null;
|
|
@@ -258,8 +692,7 @@ async function generateGlobImport(pattern, importer, eager, asUrls, allowedPatte
|
|
|
258
692
|
if (!isPatternAllowed(pattern, allowedPatterns)) throw new Error(`Glob pattern "${pattern}" is not allowed`);
|
|
259
693
|
let files = [];
|
|
260
694
|
try {
|
|
261
|
-
|
|
262
|
-
files = await glob(absolutePattern, { ignore: ["**/node_modules/**", "**/.git/**"] });
|
|
695
|
+
files = await glob(resolve(importerDir, pattern), { ignore: ["**/node_modules/**", "**/.git/**"] });
|
|
263
696
|
} catch {
|
|
264
697
|
if (pattern.includes("*.js")) files = [resolve(importerDir, pattern.replace("*", "module1")), resolve(importerDir, pattern.replace("*", "module2"))];
|
|
265
698
|
}
|
|
@@ -336,9 +769,7 @@ function addHashToFilename(filename, content, hashLength = 8) {
|
|
|
336
769
|
const hash = generateContentHash(content, hashLength);
|
|
337
770
|
const dotIndex = filename.lastIndexOf(".");
|
|
338
771
|
if (dotIndex === -1) return `${filename}-${hash}`;
|
|
339
|
-
|
|
340
|
-
const ext = filename.slice(dotIndex);
|
|
341
|
-
return `${name}-${hash}${ext}`;
|
|
772
|
+
return `${filename.slice(0, dotIndex)}-${hash}${filename.slice(dotIndex)}`;
|
|
342
773
|
}
|
|
343
774
|
/**
|
|
344
775
|
* Check if filename already has hash
|
|
@@ -402,15 +833,11 @@ if (typeof exports === 'undefined') {
|
|
|
402
833
|
*/
|
|
403
834
|
function detectShimNeeds(code) {
|
|
404
835
|
const cleanCode = removeCommentsAndStrings(code);
|
|
405
|
-
const needsDirname = /\b__dirname\b/.test(cleanCode) || /\b__filename\b/.test(cleanCode);
|
|
406
|
-
const needsRequire = /\brequire\s*\(/.test(cleanCode);
|
|
407
|
-
const needsExports = /\bmodule\.exports\b/.test(cleanCode) || /\bexports\.\w+/.test(cleanCode);
|
|
408
|
-
const needsEnv = /\bprocess\.env\b/.test(cleanCode);
|
|
409
836
|
return {
|
|
410
|
-
needsDirname,
|
|
411
|
-
needsRequire,
|
|
412
|
-
needsExports,
|
|
413
|
-
needsEnv
|
|
837
|
+
needsDirname: /\b__dirname\b/.test(cleanCode) || /\b__filename\b/.test(cleanCode),
|
|
838
|
+
needsRequire: /\brequire\s*\(/.test(cleanCode),
|
|
839
|
+
needsExports: /\bmodule\.exports\b/.test(cleanCode) || /\bexports\.\w+/.test(cleanCode),
|
|
840
|
+
needsEnv: /\bprocess\.env\b/.test(cleanCode)
|
|
414
841
|
};
|
|
415
842
|
}
|
|
416
843
|
/**
|
|
@@ -438,8 +865,7 @@ const require = createRequire(import.meta.url)
|
|
|
438
865
|
* Transform code to use shims
|
|
439
866
|
*/
|
|
440
867
|
function transformWithShims(code, config) {
|
|
441
|
-
const
|
|
442
|
-
const shims = generateShims(config, needs);
|
|
868
|
+
const shims = generateShims(config, detectShimNeeds(code));
|
|
443
869
|
if (!shims) return code;
|
|
444
870
|
return `${shims}\n${code}`;
|
|
445
871
|
}
|
|
@@ -552,191 +978,55 @@ function processNodeProtocol(id, nodeProtocol) {
|
|
|
552
978
|
*/
|
|
553
979
|
function transformNodeProtocol(code, nodeProtocol) {
|
|
554
980
|
if (!nodeProtocol) return code;
|
|
555
|
-
|
|
556
|
-
return code.replace(importRegex, (match, moduleId) => {
|
|
981
|
+
return code.replace(/(?:import|export)(?:\s[^'"]*)?\s['"]([^'"]+)['"]/g, (match, moduleId) => {
|
|
557
982
|
const processedId = processNodeProtocol(moduleId, nodeProtocol);
|
|
558
|
-
return match.replace(moduleId, processedId);
|
|
559
|
-
});
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
//#endregion
|
|
563
|
-
//#region src/plugins/node-protocol.ts
|
|
564
|
-
/**
|
|
565
|
-
* Rolldown plugin for Node.js protocol handling
|
|
566
|
-
*/
|
|
567
|
-
function nodeProtocolPlugin(nodeProtocol) {
|
|
568
|
-
if (!nodeProtocol) return { name: "node-protocol-noop" };
|
|
569
|
-
return {
|
|
570
|
-
name: "node-protocol",
|
|
571
|
-
renderChunk(code) {
|
|
572
|
-
return {
|
|
573
|
-
code: transformNodeProtocol(code, nodeProtocol),
|
|
574
|
-
map: null
|
|
575
|
-
};
|
|
576
|
-
}
|
|
577
|
-
};
|
|
578
|
-
}
|
|
579
|
-
|
|
580
|
-
//#endregion
|
|
581
|
-
//#region src/plugins/shebang.ts
|
|
582
|
-
const SHEBANG_RE = /^#![^\n]*/;
|
|
583
|
-
function shebangPlugin() {
|
|
584
|
-
return {
|
|
585
|
-
name: "robuild-shebang",
|
|
586
|
-
async writeBundle(options, bundle) {
|
|
587
|
-
for (const [fileName, output] of Object.entries(bundle)) {
|
|
588
|
-
if (output.type !== "chunk") continue;
|
|
589
|
-
if (hasShebang(output.code)) {
|
|
590
|
-
const outFile = resolve(options.dir, fileName);
|
|
591
|
-
await makeExecutable(outFile);
|
|
592
|
-
}
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
|
-
};
|
|
596
|
-
}
|
|
597
|
-
function hasShebang(code) {
|
|
598
|
-
return SHEBANG_RE.test(code);
|
|
599
|
-
}
|
|
600
|
-
async function makeExecutable(filePath) {
|
|
601
|
-
await promises.chmod(filePath, 493).catch(() => {});
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
//#endregion
|
|
605
|
-
//#region src/utils.ts
|
|
606
|
-
function fmtPath(path) {
|
|
607
|
-
return resolve(path).replace(process.cwd(), ".");
|
|
608
|
-
}
|
|
609
|
-
function analyzeDir(dir) {
|
|
610
|
-
if (Array.isArray(dir)) {
|
|
611
|
-
let totalSize$1 = 0;
|
|
612
|
-
let totalFiles = 0;
|
|
613
|
-
for (const d of dir) {
|
|
614
|
-
const { size, files } = analyzeDir(d);
|
|
615
|
-
totalSize$1 += size;
|
|
616
|
-
totalFiles += files;
|
|
617
|
-
}
|
|
618
|
-
return {
|
|
619
|
-
size: totalSize$1,
|
|
620
|
-
files: totalFiles
|
|
621
|
-
};
|
|
622
|
-
}
|
|
623
|
-
let totalSize = 0;
|
|
624
|
-
try {
|
|
625
|
-
const files = readdirSync(dir, {
|
|
626
|
-
withFileTypes: true,
|
|
627
|
-
recursive: true
|
|
628
|
-
});
|
|
629
|
-
for (const file of files) {
|
|
630
|
-
const fullPath = join(file.parentPath, file.name);
|
|
631
|
-
if (file.isFile()) {
|
|
632
|
-
const { size } = statSync(fullPath);
|
|
633
|
-
totalSize += size;
|
|
634
|
-
}
|
|
635
|
-
}
|
|
636
|
-
return {
|
|
637
|
-
size: totalSize,
|
|
638
|
-
files: files.length
|
|
639
|
-
};
|
|
640
|
-
} catch (error) {
|
|
641
|
-
if (error.code === "ENOENT" || error.code === "ENOTDIR") return {
|
|
642
|
-
size: 0,
|
|
643
|
-
files: 0
|
|
644
|
-
};
|
|
645
|
-
throw error;
|
|
646
|
-
}
|
|
647
|
-
}
|
|
648
|
-
async function distSize(dir, entry) {
|
|
649
|
-
const build$1 = await rolldown({
|
|
650
|
-
input: join(dir, entry),
|
|
651
|
-
plugins: [],
|
|
652
|
-
platform: "neutral",
|
|
653
|
-
external: (id) => id[0] !== "." && !id.startsWith(dir)
|
|
654
|
-
});
|
|
655
|
-
const { output } = await build$1.generate({ inlineDynamicImports: true });
|
|
656
|
-
const code = output[0].code;
|
|
657
|
-
const { code: minified } = await minify(entry, code);
|
|
658
|
-
return {
|
|
659
|
-
size: Buffer.byteLength(code),
|
|
660
|
-
minSize: Buffer.byteLength(minified),
|
|
661
|
-
minGzipSize: gzipSync(minified).length
|
|
662
|
-
};
|
|
663
|
-
}
|
|
664
|
-
async function sideEffectSize(dir, entry) {
|
|
665
|
-
const virtualEntry = {
|
|
666
|
-
name: "virtual-entry",
|
|
667
|
-
async resolveId(id, importer, opts) {
|
|
668
|
-
if (id === "#entry") return { id };
|
|
669
|
-
const resolved = await this.resolve(id, importer, opts);
|
|
670
|
-
if (!resolved) return null;
|
|
671
|
-
resolved.moduleSideEffects = null;
|
|
672
|
-
return resolved;
|
|
673
|
-
},
|
|
674
|
-
load(id) {
|
|
675
|
-
if (id === "#entry") return `import * as _lib from "${join(dir, entry)}";`;
|
|
676
|
-
}
|
|
677
|
-
};
|
|
678
|
-
const build$1 = await rolldown({
|
|
679
|
-
input: "#entry",
|
|
680
|
-
platform: "neutral",
|
|
681
|
-
external: (id) => id[0] !== "." && !id.startsWith(dir),
|
|
682
|
-
plugins: [virtualEntry]
|
|
983
|
+
return match.replace(moduleId, processedId);
|
|
683
984
|
});
|
|
684
|
-
const { output } = await build$1.generate({ inlineDynamicImports: true });
|
|
685
|
-
if (process.env.INSPECT_BUILD) {
|
|
686
|
-
console.log("---------[side effects]---------");
|
|
687
|
-
console.log(entry);
|
|
688
|
-
console.log(output[0].code);
|
|
689
|
-
console.log("-------------------------------");
|
|
690
|
-
}
|
|
691
|
-
return Buffer.byteLength(output[0].code.trim());
|
|
692
985
|
}
|
|
693
986
|
|
|
694
987
|
//#endregion
|
|
695
|
-
//#region src/
|
|
696
|
-
/**
|
|
697
|
-
* Get file extension for format
|
|
698
|
-
*/
|
|
699
|
-
function getFormatExtension(format, platform, fixedExtension = false) {
|
|
700
|
-
if (fixedExtension) return format === "cjs" ? ".cjs" : ".mjs";
|
|
701
|
-
switch (format) {
|
|
702
|
-
case "es":
|
|
703
|
-
case "esm":
|
|
704
|
-
case "module": return ".mjs";
|
|
705
|
-
case "cjs":
|
|
706
|
-
case "commonjs": return platform === "node" ? ".cjs" : ".js";
|
|
707
|
-
case "iife":
|
|
708
|
-
case "umd": return ".js";
|
|
709
|
-
default: return ".js";
|
|
710
|
-
}
|
|
711
|
-
}
|
|
988
|
+
//#region src/plugins/node-protocol.ts
|
|
712
989
|
/**
|
|
713
|
-
*
|
|
990
|
+
* Rolldown plugin for Node.js protocol handling
|
|
714
991
|
*/
|
|
715
|
-
|
|
716
|
-
if (!
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
force: true
|
|
725
|
-
});
|
|
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
|
+
};
|
|
726
1001
|
}
|
|
727
|
-
}
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
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
|
+
}
|
|
735
1016
|
}
|
|
736
|
-
}
|
|
1017
|
+
};
|
|
737
1018
|
}
|
|
1019
|
+
function hasShebang(code) {
|
|
1020
|
+
return SHEBANG_RE.test(code);
|
|
1021
|
+
}
|
|
1022
|
+
async function makeExecutable(filePath) {
|
|
1023
|
+
await promises.chmod(filePath, 493).catch(() => {});
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
//#endregion
|
|
1027
|
+
//#region src/builders/bundle.ts
|
|
738
1028
|
async function rolldownBuild(ctx, entry, hooks, config) {
|
|
739
|
-
const entryInput = entry
|
|
1029
|
+
const entryInput = getBundleEntryInput(entry);
|
|
740
1030
|
if (!entryInput) throw new Error("Entry input is required");
|
|
741
1031
|
const inputs = normalizeBundleInputs(entryInput, ctx);
|
|
742
1032
|
const pluginManager = new RobuildPluginManager(config || {}, entry, ctx.pkgDir);
|
|
@@ -754,20 +1044,18 @@ async function rolldownBuild(ctx, entry, hooks, config) {
|
|
|
754
1044
|
outDir: fullOutDir
|
|
755
1045
|
});
|
|
756
1046
|
await pluginManager.executeRobuildBuildStart();
|
|
757
|
-
await cleanOutputDir
|
|
1047
|
+
await cleanOutputDir(ctx.pkgDir, fullOutDir, entry.clean ?? true);
|
|
758
1048
|
if (entry.dtsOnly) {
|
|
759
|
-
|
|
1049
|
+
logger.info("Running in dtsOnly mode - only generating declaration files");
|
|
760
1050
|
entry.dts = entry.dts === false ? true : entry.dts || true;
|
|
761
1051
|
}
|
|
762
1052
|
if (entry.stub) {
|
|
763
1053
|
for (const [distName, srcPath] of Object.entries(inputs)) {
|
|
764
1054
|
const distPath = join(ctx.pkgDir, "dist", `${distName}.mjs`);
|
|
765
1055
|
await mkdir(dirname(distPath), { recursive: true });
|
|
766
|
-
|
|
1056
|
+
logger.log(`${colors.cyan("Stub")} ${colors.green(fmtPath(distPath))}`);
|
|
767
1057
|
const srcContents = await readFile(srcPath, "utf8");
|
|
768
|
-
const
|
|
769
|
-
const exportNames = parsed.module.staticExports.flatMap((e) => e.entries.map((e$1) => e$1.exportName.kind === "Default" ? "default" : e$1.exportName.name));
|
|
770
|
-
const hasDefaultExport = exportNames.includes("default");
|
|
1058
|
+
const hasDefaultExport = parseSync(srcPath, srcContents).module.staticExports.flatMap((e) => e.entries.map((e) => e.exportName.kind === "Default" ? "default" : e.exportName.name)).includes("default");
|
|
771
1059
|
const firstLine = srcContents.split("\n")[0];
|
|
772
1060
|
const hasShebangLine = firstLine.startsWith("#!");
|
|
773
1061
|
await writeFile(distPath, `${hasShebangLine ? `${firstLine}\n` : ""}export * from "${srcPath}";\n${hasDefaultExport ? `export { default } from "${srcPath}";\n` : ""}`, "utf8");
|
|
@@ -776,49 +1064,10 @@ async function rolldownBuild(ctx, entry, hooks, config) {
|
|
|
776
1064
|
}
|
|
777
1065
|
return;
|
|
778
1066
|
}
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
];
|
|
784
|
-
if (entry.noExternal) {
|
|
785
|
-
const escapeRegExp = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
786
|
-
if (typeof entry.noExternal === "function") {
|
|
787
|
-
const predicate = entry.noExternal;
|
|
788
|
-
const depNames = [...Object.keys(ctx.pkg.dependencies || {}), ...Object.keys(ctx.pkg.peerDependencies || {})];
|
|
789
|
-
const excludedNames = /* @__PURE__ */ new Set();
|
|
790
|
-
for (const name of depNames) try {
|
|
791
|
-
if (predicate(name)) excludedNames.add(name);
|
|
792
|
-
} catch {}
|
|
793
|
-
externalDeps = externalDeps.filter((dep) => {
|
|
794
|
-
if (typeof dep === "string") return !excludedNames.has(dep);
|
|
795
|
-
if (dep instanceof RegExp) {
|
|
796
|
-
for (const name of Array.from(excludedNames)) if (dep.source.startsWith(`^${escapeRegExp(name)}/`)) return false;
|
|
797
|
-
return true;
|
|
798
|
-
}
|
|
799
|
-
return true;
|
|
800
|
-
});
|
|
801
|
-
} else if (Array.isArray(entry.noExternal)) {
|
|
802
|
-
const rules = entry.noExternal;
|
|
803
|
-
externalDeps = externalDeps.filter((dep) => {
|
|
804
|
-
for (const rule of rules) if (typeof rule === "string") {
|
|
805
|
-
if (typeof dep === "string") {
|
|
806
|
-
if (dep === rule) return false;
|
|
807
|
-
} else if (dep instanceof RegExp) {
|
|
808
|
-
if (dep.source.startsWith(`^${escapeRegExp(rule)}/`)) return false;
|
|
809
|
-
}
|
|
810
|
-
} else if (rule instanceof RegExp) {
|
|
811
|
-
if (typeof dep === "string") {
|
|
812
|
-
if (rule.test(dep)) return false;
|
|
813
|
-
} else if (dep instanceof RegExp) {
|
|
814
|
-
if (dep.source === rule.source && dep.flags === rule.flags) return false;
|
|
815
|
-
}
|
|
816
|
-
}
|
|
817
|
-
return true;
|
|
818
|
-
});
|
|
819
|
-
}
|
|
820
|
-
}
|
|
821
|
-
if (entry.external) if (typeof entry.external === "function") {} else externalDeps.push(...entry.external);
|
|
1067
|
+
const externalConfig = resolveExternalConfig(ctx, {
|
|
1068
|
+
external: entry.external,
|
|
1069
|
+
noExternal: entry.noExternal
|
|
1070
|
+
});
|
|
822
1071
|
const defineOptions = {};
|
|
823
1072
|
if (entry.env) for (const [key, value] of Object.entries(entry.env)) defineOptions[`process.env.${key}`] = JSON.stringify(value);
|
|
824
1073
|
if (entry.define) for (const [key, value] of Object.entries(entry.define)) defineOptions[key] = value;
|
|
@@ -852,21 +1101,23 @@ async function rolldownBuild(ctx, entry, hooks, config) {
|
|
|
852
1101
|
}
|
|
853
1102
|
rolldownPlugins.push(...pluginManager.getRolldownPlugins());
|
|
854
1103
|
const moduleTypes = {};
|
|
855
|
-
if (entry.loaders) for (const [ext, config
|
|
1104
|
+
if (entry.loaders) for (const [ext, config] of Object.entries(entry.loaders)) moduleTypes[ext] = config.loader;
|
|
856
1105
|
const robuildGeneratedConfig = {
|
|
857
1106
|
cwd: ctx.pkgDir,
|
|
858
1107
|
input: inputs,
|
|
859
1108
|
plugins: rolldownPlugins,
|
|
860
1109
|
platform: platform === "node" ? "node" : "neutral",
|
|
861
|
-
external:
|
|
862
|
-
define: defineOptions,
|
|
1110
|
+
external: externalConfig,
|
|
863
1111
|
resolve: { alias: entry.alias || {} },
|
|
864
|
-
transform: {
|
|
1112
|
+
transform: {
|
|
1113
|
+
target,
|
|
1114
|
+
define: defineOptions
|
|
1115
|
+
},
|
|
865
1116
|
...Object.keys(moduleTypes).length > 0 ? { moduleTypes } : {}
|
|
866
1117
|
};
|
|
867
1118
|
if (entry.treeshake !== void 0) if (typeof entry.treeshake === "boolean") robuildGeneratedConfig.treeshake = entry.treeshake;
|
|
868
1119
|
else robuildGeneratedConfig.treeshake = entry.treeshake;
|
|
869
|
-
const { output: userOutputConfig, plugins: userPlugins
|
|
1120
|
+
const { output: userOutputConfig, plugins: userPlugins, ...userRolldownConfig } = entry.rolldown || {};
|
|
870
1121
|
const baseRolldownConfig = {
|
|
871
1122
|
...robuildGeneratedConfig,
|
|
872
1123
|
...userRolldownConfig,
|
|
@@ -894,7 +1145,10 @@ async function rolldownBuild(ctx, entry, hooks, config) {
|
|
|
894
1145
|
dir: formatOutDir,
|
|
895
1146
|
format,
|
|
896
1147
|
entryFileNames: entryFileName,
|
|
897
|
-
chunkFileNames:
|
|
1148
|
+
chunkFileNames: (chunk) => {
|
|
1149
|
+
if (chunk.name.endsWith(".d") || chunk.name.includes(".d.")) return `[name].mjs`;
|
|
1150
|
+
return `_chunks/[name]-[hash]${extension}`;
|
|
1151
|
+
},
|
|
898
1152
|
minify: entry.minify,
|
|
899
1153
|
name: entry.globalName,
|
|
900
1154
|
banner: resolveChunkAddon(entry.banner, format),
|
|
@@ -938,9 +1192,7 @@ async function rolldownBuild(ctx, entry, hooks, config) {
|
|
|
938
1192
|
const { rename } = await import("node:fs/promises");
|
|
939
1193
|
await rename(finalFilePath, hashedFilePath);
|
|
940
1194
|
try {
|
|
941
|
-
|
|
942
|
-
const mapNew = `${hashedFilePath}.map`;
|
|
943
|
-
await rename(mapOld, mapNew);
|
|
1195
|
+
await rename(`${finalFilePath}.map`, `${hashedFilePath}.map`);
|
|
944
1196
|
} catch {}
|
|
945
1197
|
finalFileName = hashedFileName;
|
|
946
1198
|
finalFilePath = hashedFilePath;
|
|
@@ -958,29 +1210,26 @@ async function rolldownBuild(ctx, entry, hooks, config) {
|
|
|
958
1210
|
}
|
|
959
1211
|
if (entry.copy) await copyFiles(ctx.pkgDir, fullOutDir, entry.copy);
|
|
960
1212
|
await pluginManager.executeRobuildBuildEnd({ allOutputEntries });
|
|
961
|
-
|
|
962
|
-
`${colors.
|
|
963
|
-
colors.dim(
|
|
964
|
-
o.exports.some((e) => e !== "default") ? colors.dim(
|
|
965
|
-
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(", ")}`) : ""
|
|
966
1218
|
].filter(Boolean).join("\n")).join("\n\n")}`);
|
|
967
1219
|
}
|
|
968
1220
|
function normalizeBundleInputs(input, ctx) {
|
|
969
1221
|
const inputs = {};
|
|
970
1222
|
if (typeof input === "object" && !Array.isArray(input)) {
|
|
971
|
-
for (const [name, src] of Object.entries(input)) {
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
});
|
|
982
|
-
inputs[name] = resolvedSrc;
|
|
983
|
-
}
|
|
1223
|
+
for (const [name, src] of Object.entries(input)) inputs[name] = resolveModulePath(src, {
|
|
1224
|
+
from: ctx.pkgDir,
|
|
1225
|
+
extensions: [
|
|
1226
|
+
".ts",
|
|
1227
|
+
".js",
|
|
1228
|
+
".mjs",
|
|
1229
|
+
".cjs",
|
|
1230
|
+
".json"
|
|
1231
|
+
]
|
|
1232
|
+
});
|
|
984
1233
|
return inputs;
|
|
985
1234
|
}
|
|
986
1235
|
for (let src of Array.isArray(input) ? input : [input]) {
|
|
@@ -1004,122 +1253,39 @@ function normalizeBundleInputs(input, ctx) {
|
|
|
1004
1253
|
return inputs;
|
|
1005
1254
|
}
|
|
1006
1255
|
|
|
1007
|
-
//#endregion
|
|
1008
|
-
//#region src/features/extensions.ts
|
|
1009
|
-
/**
|
|
1010
|
-
* Resolve JavaScript output extension
|
|
1011
|
-
*/
|
|
1012
|
-
function resolveJsOutputExtension(format, platform = "node", fixedExtension = false) {
|
|
1013
|
-
if (fixedExtension) return format === "cjs" ? "cjs" : "mjs";
|
|
1014
|
-
switch (format) {
|
|
1015
|
-
case "es": return platform === "browser" ? "js" : "mjs";
|
|
1016
|
-
case "cjs": return platform === "browser" ? "js" : "cjs";
|
|
1017
|
-
case "iife":
|
|
1018
|
-
case "umd": return "js";
|
|
1019
|
-
default: return "js";
|
|
1020
|
-
}
|
|
1021
|
-
}
|
|
1022
|
-
/**
|
|
1023
|
-
* Resolve DTS output extension
|
|
1024
|
-
*/
|
|
1025
|
-
function resolveDtsOutputExtension(format, fixedExtension = false) {
|
|
1026
|
-
if (fixedExtension) return format === "cjs" ? "d.cts" : "d.mts";
|
|
1027
|
-
switch (format) {
|
|
1028
|
-
case "es": return "d.mts";
|
|
1029
|
-
case "cjs": return "d.cts";
|
|
1030
|
-
default: return "d.ts";
|
|
1031
|
-
}
|
|
1032
|
-
}
|
|
1033
|
-
/**
|
|
1034
|
-
* Apply custom output extensions
|
|
1035
|
-
*/
|
|
1036
|
-
function applyOutExtensions(format, outExtensions) {
|
|
1037
|
-
const defaultJs = resolveJsOutputExtension(format);
|
|
1038
|
-
const defaultDts = resolveDtsOutputExtension(format);
|
|
1039
|
-
if (!outExtensions) return {
|
|
1040
|
-
js: defaultJs,
|
|
1041
|
-
dts: defaultDts
|
|
1042
|
-
};
|
|
1043
|
-
const custom = outExtensions(format);
|
|
1044
|
-
return {
|
|
1045
|
-
js: custom.js || defaultJs,
|
|
1046
|
-
dts: custom.dts || defaultDts
|
|
1047
|
-
};
|
|
1048
|
-
}
|
|
1049
|
-
/**
|
|
1050
|
-
* Create filename with proper extension
|
|
1051
|
-
*/
|
|
1052
|
-
function createFilename(basename$1, format, isDts = false, options = {}) {
|
|
1053
|
-
const { platform, fixedExtension, outExtensions } = options;
|
|
1054
|
-
if (outExtensions) {
|
|
1055
|
-
const extensions = applyOutExtensions(format, outExtensions);
|
|
1056
|
-
return `${basename$1}.${isDts ? extensions.dts : extensions.js}`;
|
|
1057
|
-
}
|
|
1058
|
-
if (isDts) return `${basename$1}.${resolveDtsOutputExtension(format, fixedExtension)}`;
|
|
1059
|
-
return `${basename$1}.${resolveJsOutputExtension(format, platform, fixedExtension)}`;
|
|
1060
|
-
}
|
|
1061
|
-
|
|
1062
1256
|
//#endregion
|
|
1063
1257
|
//#region src/builders/transform.ts
|
|
1064
1258
|
/**
|
|
1065
|
-
* Clean output directory for transform entries
|
|
1066
|
-
*/
|
|
1067
|
-
async function cleanOutputDir(projectRoot, outDir, cleanPaths) {
|
|
1068
|
-
if (!cleanPaths) return;
|
|
1069
|
-
const { rm } = await import("node:fs/promises");
|
|
1070
|
-
const { existsSync: existsSync$1 } = await import("node:fs");
|
|
1071
|
-
if (cleanPaths === true) {
|
|
1072
|
-
if (existsSync$1(outDir)) {
|
|
1073
|
-
consola.log(`🧻 Cleaning up ${fmtPath(outDir)}`);
|
|
1074
|
-
await rm(outDir, {
|
|
1075
|
-
recursive: true,
|
|
1076
|
-
force: true
|
|
1077
|
-
});
|
|
1078
|
-
}
|
|
1079
|
-
} else if (Array.isArray(cleanPaths)) for (const path of cleanPaths) {
|
|
1080
|
-
const fullPath = resolve(projectRoot, path);
|
|
1081
|
-
if (existsSync$1(fullPath)) {
|
|
1082
|
-
consola.log(`🧻 Cleaning up ${fmtPath(fullPath)}`);
|
|
1083
|
-
await rm(fullPath, {
|
|
1084
|
-
recursive: true,
|
|
1085
|
-
force: true
|
|
1086
|
-
});
|
|
1087
|
-
}
|
|
1088
|
-
}
|
|
1089
|
-
}
|
|
1090
|
-
/**
|
|
1091
1259
|
* Transform all .ts modules in a directory using oxc-transform.
|
|
1092
1260
|
*/
|
|
1093
1261
|
async function transformDir(ctx, entry) {
|
|
1094
1262
|
if (entry.stub) {
|
|
1095
|
-
|
|
1263
|
+
logger.log(`${colors.cyan("Stub")} ${colors.green(`${fmtPath(entry.outDir)}/`)}`);
|
|
1096
1264
|
await symlink(entry.input, entry.outDir, "junction");
|
|
1097
1265
|
return;
|
|
1098
1266
|
}
|
|
1099
1267
|
if (entry.unbundle) {
|
|
1100
|
-
|
|
1268
|
+
logger.log(`${colors.cyan("Unbundle")} ${colors.green(`${fmtPath(entry.outDir)}/`)}`);
|
|
1101
1269
|
await unbundleTransform(ctx, entry);
|
|
1102
1270
|
return;
|
|
1103
1271
|
}
|
|
1104
|
-
const fullOutDir =
|
|
1272
|
+
const fullOutDir = normalizePath(entry.outDir || "dist", ctx.pkgDir);
|
|
1105
1273
|
await cleanOutputDir(ctx.pkgDir, fullOutDir, entry.clean ?? true);
|
|
1106
|
-
const { statSync
|
|
1274
|
+
const { statSync } = await import("node:fs");
|
|
1107
1275
|
let inputDir = entry.input;
|
|
1108
1276
|
try {
|
|
1109
|
-
|
|
1110
|
-
if (stats.isFile()) {
|
|
1277
|
+
if (statSync(inputDir).isFile()) {
|
|
1111
1278
|
inputDir = dirname(inputDir);
|
|
1112
|
-
|
|
1279
|
+
logger.warn(`Transform input should be a directory, not a file. Using directory: ${fmtPath(inputDir)}`);
|
|
1113
1280
|
}
|
|
1114
1281
|
} catch (error) {
|
|
1115
1282
|
if (error.code !== "ENOENT") throw error;
|
|
1116
1283
|
}
|
|
1117
|
-
const promises
|
|
1284
|
+
const promises = [];
|
|
1118
1285
|
const files = await glob$1("**/*.*", { cwd: inputDir });
|
|
1119
|
-
for await (const entryName of files) promises
|
|
1286
|
+
for await (const entryName of files) promises.push((async () => {
|
|
1120
1287
|
const entryPath = join(inputDir, entryName);
|
|
1121
|
-
|
|
1122
|
-
switch (ext) {
|
|
1288
|
+
switch (extname(entryPath)) {
|
|
1123
1289
|
case ".ts":
|
|
1124
1290
|
case ".tsx":
|
|
1125
1291
|
case ".jsx": {
|
|
@@ -1133,11 +1299,7 @@ async function transformDir(ctx, entry) {
|
|
|
1133
1299
|
let entryDistPath = join(entry.outDir, outputFileName);
|
|
1134
1300
|
await mkdir(dirname(entryDistPath), { recursive: true });
|
|
1135
1301
|
await writeFile(entryDistPath, transformed.code, "utf8");
|
|
1136
|
-
if (entry.sourcemap && transformed.map) {
|
|
1137
|
-
const mapPath = `${entryDistPath}.map`;
|
|
1138
|
-
const mapContent = typeof transformed.map === "string" ? transformed.map : JSON.stringify(transformed.map);
|
|
1139
|
-
await writeFile(mapPath, mapContent, "utf8");
|
|
1140
|
-
}
|
|
1302
|
+
if (entry.sourcemap && transformed.map) await writeFile(`${entryDistPath}.map`, typeof transformed.map === "string" ? transformed.map : JSON.stringify(transformed.map), "utf8");
|
|
1141
1303
|
if (entry.hash && !hasHash(entryDistPath)) {
|
|
1142
1304
|
const hashedPath = addHashToFilename(entryDistPath, transformed.code);
|
|
1143
1305
|
const { rename } = await import("node:fs/promises");
|
|
@@ -1151,8 +1313,7 @@ async function transformDir(ctx, entry) {
|
|
|
1151
1313
|
fixedExtension: entry.fixedExtension,
|
|
1152
1314
|
outExtensions: entry.outExtensions
|
|
1153
1315
|
});
|
|
1154
|
-
|
|
1155
|
-
await writeFile(dtsPath, transformed.declaration, "utf8");
|
|
1316
|
+
await writeFile(join(entry.outDir, dtsFileName), transformed.declaration, "utf8");
|
|
1156
1317
|
}
|
|
1157
1318
|
return entryDistPath;
|
|
1158
1319
|
}
|
|
@@ -1166,9 +1327,9 @@ async function transformDir(ctx, entry) {
|
|
|
1166
1327
|
}
|
|
1167
1328
|
}
|
|
1168
1329
|
})());
|
|
1169
|
-
const writtenFiles = await Promise.all(promises
|
|
1330
|
+
const writtenFiles = await Promise.all(promises);
|
|
1170
1331
|
if (entry.copy) await copyFiles(ctx.pkgDir, fullOutDir, entry.copy);
|
|
1171
|
-
|
|
1332
|
+
logger.log(`\n${colors.cyan("Transform")} ${colors.green(`${fmtPath(entry.outDir)}/`)} ${colors.dim(`(${writtenFiles.length} files)`)}`);
|
|
1172
1333
|
}
|
|
1173
1334
|
/**
|
|
1174
1335
|
* Transform a .ts module using oxc-transform.
|
|
@@ -1176,9 +1337,8 @@ async function transformDir(ctx, entry) {
|
|
|
1176
1337
|
async function transformModule(entryPath, entry) {
|
|
1177
1338
|
let sourceText = await readFile(entryPath, "utf8");
|
|
1178
1339
|
const ext = extname(entryPath);
|
|
1179
|
-
const lang = ext === ".tsx" || ext === ".jsx" ? "tsx" : "ts";
|
|
1180
1340
|
const sourceOptions = {
|
|
1181
|
-
lang,
|
|
1341
|
+
lang: ext === ".tsx" || ext === ".jsx" ? "tsx" : "ts",
|
|
1182
1342
|
sourceType: "module"
|
|
1183
1343
|
};
|
|
1184
1344
|
const parsed = parseSync(entryPath, sourceText, { ...sourceOptions });
|
|
@@ -1254,90 +1414,6 @@ async function transformModule(entryPath, entry) {
|
|
|
1254
1414
|
return transformed;
|
|
1255
1415
|
}
|
|
1256
1416
|
|
|
1257
|
-
//#endregion
|
|
1258
|
-
//#region src/features/logger.ts
|
|
1259
|
-
/**
|
|
1260
|
-
* Logger instance with configurable log level
|
|
1261
|
-
*/
|
|
1262
|
-
var Logger = class {
|
|
1263
|
-
level = "info";
|
|
1264
|
-
warningCount = 0;
|
|
1265
|
-
errorCount = 0;
|
|
1266
|
-
constructor(level = "info") {
|
|
1267
|
-
this.level = level;
|
|
1268
|
-
this.updateConsolaLevel();
|
|
1269
|
-
}
|
|
1270
|
-
setLevel(level) {
|
|
1271
|
-
this.level = level;
|
|
1272
|
-
this.updateConsolaLevel();
|
|
1273
|
-
}
|
|
1274
|
-
updateConsolaLevel() {
|
|
1275
|
-
const levelMap = {
|
|
1276
|
-
silent: 0,
|
|
1277
|
-
error: 1,
|
|
1278
|
-
warn: 2,
|
|
1279
|
-
info: 3,
|
|
1280
|
-
verbose: 4
|
|
1281
|
-
};
|
|
1282
|
-
consola.level = levelMap[this.level];
|
|
1283
|
-
}
|
|
1284
|
-
silent(message, ...args) {
|
|
1285
|
-
console.log(message, ...args);
|
|
1286
|
-
}
|
|
1287
|
-
error(message, ...args) {
|
|
1288
|
-
this.errorCount++;
|
|
1289
|
-
consola.error(message, ...args);
|
|
1290
|
-
}
|
|
1291
|
-
warn(message, ...args) {
|
|
1292
|
-
this.warningCount++;
|
|
1293
|
-
consola.warn(message, ...args);
|
|
1294
|
-
}
|
|
1295
|
-
info(message, ...args) {
|
|
1296
|
-
consola.info(message, ...args);
|
|
1297
|
-
}
|
|
1298
|
-
verbose(message, ...args) {
|
|
1299
|
-
if (this.level === "verbose") consola.debug(message, ...args);
|
|
1300
|
-
}
|
|
1301
|
-
success(message, ...args) {
|
|
1302
|
-
consola.success(message, ...args);
|
|
1303
|
-
}
|
|
1304
|
-
log(message, ...args) {
|
|
1305
|
-
consola.log(message, ...args);
|
|
1306
|
-
}
|
|
1307
|
-
getWarningCount() {
|
|
1308
|
-
return this.warningCount;
|
|
1309
|
-
}
|
|
1310
|
-
getErrorCount() {
|
|
1311
|
-
return this.errorCount;
|
|
1312
|
-
}
|
|
1313
|
-
resetCounts() {
|
|
1314
|
-
this.warningCount = 0;
|
|
1315
|
-
this.errorCount = 0;
|
|
1316
|
-
}
|
|
1317
|
-
shouldFailOnWarnings(failOnWarn) {
|
|
1318
|
-
return failOnWarn && this.warningCount > 0;
|
|
1319
|
-
}
|
|
1320
|
-
};
|
|
1321
|
-
const logger = new Logger();
|
|
1322
|
-
/**
|
|
1323
|
-
* Configure global logger
|
|
1324
|
-
*/
|
|
1325
|
-
function configureLogger(level) {
|
|
1326
|
-
logger.setLevel(level);
|
|
1327
|
-
}
|
|
1328
|
-
/**
|
|
1329
|
-
* Reset warning and error counts
|
|
1330
|
-
*/
|
|
1331
|
-
function resetLogCounts() {
|
|
1332
|
-
logger.resetCounts();
|
|
1333
|
-
}
|
|
1334
|
-
/**
|
|
1335
|
-
* Check if build should fail due to warnings
|
|
1336
|
-
*/
|
|
1337
|
-
function shouldFailOnWarnings(failOnWarn) {
|
|
1338
|
-
return logger.shouldFailOnWarnings(failOnWarn);
|
|
1339
|
-
}
|
|
1340
|
-
|
|
1341
1417
|
//#endregion
|
|
1342
1418
|
//#region src/features/on-success.ts
|
|
1343
1419
|
const execAsync = promisify(exec);
|
|
@@ -1404,8 +1480,7 @@ async function loadViteConfig(cwd) {
|
|
|
1404
1480
|
try {
|
|
1405
1481
|
logger.verbose(`Loading Vite config from: ${configPath}`);
|
|
1406
1482
|
const configModule = await import(configPath);
|
|
1407
|
-
|
|
1408
|
-
return convertViteConfig(viteConfig);
|
|
1483
|
+
return convertViteConfig(configModule.default || configModule);
|
|
1409
1484
|
} catch (error) {
|
|
1410
1485
|
logger.error(`Failed to load Vite config from ${configPath}:`, error);
|
|
1411
1486
|
return {};
|
|
@@ -1468,7 +1543,7 @@ function convertFormats(formats) {
|
|
|
1468
1543
|
*/
|
|
1469
1544
|
function convertTarget(target) {
|
|
1470
1545
|
if (!target) return void 0;
|
|
1471
|
-
|
|
1546
|
+
return {
|
|
1472
1547
|
es2015: "es2015",
|
|
1473
1548
|
es2016: "es2016",
|
|
1474
1549
|
es2017: "es2017",
|
|
@@ -1478,8 +1553,7 @@ function convertTarget(target) {
|
|
|
1478
1553
|
es2021: "es2021",
|
|
1479
1554
|
es2022: "es2022",
|
|
1480
1555
|
esnext: "esnext"
|
|
1481
|
-
};
|
|
1482
|
-
return targetMap[target] || void 0;
|
|
1556
|
+
}[target] || void 0;
|
|
1483
1557
|
}
|
|
1484
1558
|
/**
|
|
1485
1559
|
* Convert Vite external config to robuild external
|
|
@@ -1490,15 +1564,12 @@ function convertExternal(external) {
|
|
|
1490
1564
|
|
|
1491
1565
|
//#endregion
|
|
1492
1566
|
//#region src/watch.ts
|
|
1493
|
-
function normalizePath$1(path, resolveFrom) {
|
|
1494
|
-
return typeof path === "string" && isAbsolute(path) ? path : path instanceof URL ? fileURLToPath(path) : resolve(resolveFrom || ".", path || ".");
|
|
1495
|
-
}
|
|
1496
1567
|
/**
|
|
1497
1568
|
* Perform watch build using rolldown's built-in watch mode
|
|
1498
1569
|
*/
|
|
1499
1570
|
async function performWatchBuild(config, ctx, startTime) {
|
|
1500
|
-
const { performBuild
|
|
1501
|
-
await performBuild
|
|
1571
|
+
const { performBuild } = await import("./build-B-lzI2ff.mjs");
|
|
1572
|
+
await performBuild(config, ctx, startTime);
|
|
1502
1573
|
const bundleEntries = (config.entries || []).filter((entry) => {
|
|
1503
1574
|
if (typeof entry === "string") return !entry.endsWith("/");
|
|
1504
1575
|
return entry.type === "bundle";
|
|
@@ -1517,45 +1588,22 @@ async function performWatchBuild(config, ctx, startTime) {
|
|
|
1517
1588
|
* The watch mode then monitors for file changes and triggers rebuilds.
|
|
1518
1589
|
*/
|
|
1519
1590
|
async function startRolldownWatch(config, ctx, bundleEntries) {
|
|
1520
|
-
logger.info("
|
|
1521
|
-
const { RobuildPluginManager
|
|
1591
|
+
logger.info("Watching for changes...");
|
|
1592
|
+
const { RobuildPluginManager } = await import("./plugin-manager-pCQvlo7q.mjs");
|
|
1522
1593
|
const watchConfigs = [];
|
|
1523
1594
|
for (const rawEntry of bundleEntries) {
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
const [input, outDir] = rawEntry.split(":");
|
|
1527
|
-
entry = {
|
|
1528
|
-
type: "bundle",
|
|
1529
|
-
input,
|
|
1530
|
-
outDir: outDir || "dist"
|
|
1531
|
-
};
|
|
1532
|
-
} else entry = rawEntry;
|
|
1533
|
-
const entryInput = entry.input || entry.entry;
|
|
1595
|
+
const entry = typeof rawEntry === "string" ? parseEntryString(rawEntry) : rawEntry;
|
|
1596
|
+
const entryInput = getBundleEntryInput(entry);
|
|
1534
1597
|
if (!entryInput) {
|
|
1535
1598
|
logger.warn("Skipping entry without input:", entry);
|
|
1536
1599
|
continue;
|
|
1537
1600
|
}
|
|
1538
|
-
|
|
1539
|
-
if (typeof entryInput === "object" && !Array.isArray(entryInput)) {
|
|
1540
|
-
const normalizedObj = {};
|
|
1541
|
-
for (const [key, value] of Object.entries(entryInput)) normalizedObj[key] = normalizePath$1(value, ctx.pkgDir);
|
|
1542
|
-
normalizedInput = normalizedObj;
|
|
1543
|
-
} else if (Array.isArray(entryInput)) normalizedInput = entryInput.map((i) => normalizePath$1(i, ctx.pkgDir));
|
|
1544
|
-
else normalizedInput = normalizePath$1(entryInput, ctx.pkgDir);
|
|
1601
|
+
const normalizedInput = normalizeEntryInput(entryInput, ctx.pkgDir);
|
|
1545
1602
|
const target = entry.target || "es2022";
|
|
1546
1603
|
const platform = entry.platform || "node";
|
|
1547
1604
|
const format = entry.format || "es";
|
|
1548
|
-
const getExtension = (fmt) => {
|
|
1549
|
-
switch (fmt) {
|
|
1550
|
-
case "es": return ".mjs";
|
|
1551
|
-
case "cjs": return ".cjs";
|
|
1552
|
-
case "iife":
|
|
1553
|
-
case "umd": return ".js";
|
|
1554
|
-
default: return ".mjs";
|
|
1555
|
-
}
|
|
1556
|
-
};
|
|
1557
|
-
const extension = getExtension(Array.isArray(format) ? format[0] : format);
|
|
1558
1605
|
const rolldownFormat = Array.isArray(format) ? format[0] : format;
|
|
1606
|
+
const extension = getFormatExtension(rolldownFormat, platform);
|
|
1559
1607
|
const formatMap = {
|
|
1560
1608
|
esm: "es",
|
|
1561
1609
|
cjs: "cjs",
|
|
@@ -1566,8 +1614,11 @@ async function startRolldownWatch(config, ctx, bundleEntries) {
|
|
|
1566
1614
|
if (Array.isArray(normalizedInput)) rolldownInput = normalizedInput[0];
|
|
1567
1615
|
else if (typeof normalizedInput === "object") rolldownInput = normalizedInput;
|
|
1568
1616
|
else rolldownInput = normalizedInput;
|
|
1569
|
-
const
|
|
1570
|
-
const
|
|
1617
|
+
const rolldownPlugins = [...new RobuildPluginManager(config, entry, ctx.pkgDir).getRolldownPlugins(), ...entry.rolldown?.plugins || []];
|
|
1618
|
+
const externalConfig = resolveExternalConfig(ctx, {
|
|
1619
|
+
external: entry.external,
|
|
1620
|
+
noExternal: entry.noExternal
|
|
1621
|
+
});
|
|
1571
1622
|
const watchConfig = {
|
|
1572
1623
|
input: rolldownInput,
|
|
1573
1624
|
output: {
|
|
@@ -1577,6 +1628,7 @@ async function startRolldownWatch(config, ctx, bundleEntries) {
|
|
|
1577
1628
|
sourcemap: entry.sourcemap
|
|
1578
1629
|
},
|
|
1579
1630
|
platform: platform === "node" ? "node" : "neutral",
|
|
1631
|
+
external: externalConfig,
|
|
1580
1632
|
transform: { target },
|
|
1581
1633
|
plugins: rolldownPlugins
|
|
1582
1634
|
};
|
|
@@ -1586,24 +1638,20 @@ async function startRolldownWatch(config, ctx, bundleEntries) {
|
|
|
1586
1638
|
watcher.on("event", (event) => {
|
|
1587
1639
|
switch (event.code) {
|
|
1588
1640
|
case "START":
|
|
1589
|
-
logger.info("
|
|
1590
|
-
break;
|
|
1591
|
-
case "BUNDLE_START":
|
|
1592
|
-
logger.info("📦 Bundling...");
|
|
1593
|
-
break;
|
|
1594
|
-
case "BUNDLE_END":
|
|
1595
|
-
logger.success("✅ Bundle complete");
|
|
1641
|
+
logger.info("Rebuilding...");
|
|
1596
1642
|
break;
|
|
1643
|
+
case "BUNDLE_START": break;
|
|
1644
|
+
case "BUNDLE_END": break;
|
|
1597
1645
|
case "END":
|
|
1598
|
-
logger.success("
|
|
1646
|
+
logger.success("Rebuilt");
|
|
1599
1647
|
break;
|
|
1600
1648
|
case "ERROR":
|
|
1601
|
-
logger.error("
|
|
1649
|
+
logger.error("Build error:", event.error);
|
|
1602
1650
|
break;
|
|
1603
1651
|
}
|
|
1604
1652
|
});
|
|
1605
1653
|
const cleanup = async () => {
|
|
1606
|
-
|
|
1654
|
+
logger.info("Stopping watch mode...");
|
|
1607
1655
|
await watcher.close();
|
|
1608
1656
|
process.exit(0);
|
|
1609
1657
|
};
|
|
@@ -1675,27 +1723,25 @@ async function build(config) {
|
|
|
1675
1723
|
if (config.logLevel) configureLogger(config.logLevel);
|
|
1676
1724
|
resetLogCounts();
|
|
1677
1725
|
const pkgDir = normalizePath(config.cwd);
|
|
1678
|
-
const pkg = await readJSON(join(pkgDir, "package.json")).catch(() => ({}));
|
|
1679
1726
|
const ctx = {
|
|
1680
|
-
pkg,
|
|
1727
|
+
pkg: await readJSON(join(pkgDir, "package.json")).catch(() => ({})),
|
|
1681
1728
|
pkgDir
|
|
1682
1729
|
};
|
|
1683
1730
|
let finalConfig = config;
|
|
1684
1731
|
if (config.fromVite) {
|
|
1685
1732
|
logger.verbose("Loading configuration from Vite config file");
|
|
1686
|
-
const viteConfig = await loadViteConfig(pkgDir);
|
|
1687
1733
|
finalConfig = {
|
|
1688
|
-
...
|
|
1734
|
+
...await loadViteConfig(pkgDir),
|
|
1689
1735
|
...config
|
|
1690
1736
|
};
|
|
1691
1737
|
}
|
|
1692
1738
|
finalConfig = normalizeTsupConfig(finalConfig);
|
|
1693
1739
|
if (finalConfig.watch?.enabled) {
|
|
1694
|
-
logger.info(
|
|
1740
|
+
logger.info(`Watching ${colors.cyan(ctx.pkg.name || "<unnamed>")}`);
|
|
1695
1741
|
await performWatchBuild(finalConfig, ctx, startTime);
|
|
1696
1742
|
return;
|
|
1697
1743
|
}
|
|
1698
|
-
logger.info(
|
|
1744
|
+
logger.info(`Building ${colors.cyan(ctx.pkg.name || "<unnamed>")}`);
|
|
1699
1745
|
await performBuild(finalConfig, ctx, startTime);
|
|
1700
1746
|
}
|
|
1701
1747
|
/**
|
|
@@ -1706,35 +1752,17 @@ async function performBuild(config, ctx, startTime) {
|
|
|
1706
1752
|
const hooks = config.hooks || {};
|
|
1707
1753
|
await hooks.start?.(ctx);
|
|
1708
1754
|
const entries = (config.entries || []).map((rawEntry) => {
|
|
1709
|
-
let entry;
|
|
1710
|
-
if (typeof rawEntry === "string") {
|
|
1711
|
-
const [input, outDir] = rawEntry.split(":");
|
|
1712
|
-
entry = input.endsWith("/") ? {
|
|
1713
|
-
type: "transform",
|
|
1714
|
-
input,
|
|
1715
|
-
outDir
|
|
1716
|
-
} : {
|
|
1717
|
-
type: "bundle",
|
|
1718
|
-
input: input.split(","),
|
|
1719
|
-
outDir
|
|
1720
|
-
};
|
|
1721
|
-
} else entry = rawEntry;
|
|
1755
|
+
let entry = typeof rawEntry === "string" ? parseEntryString(rawEntry) : rawEntry;
|
|
1722
1756
|
if (entry.type === "bundle") entry = inheritConfig(entry, config);
|
|
1723
1757
|
else if (entry.type === "transform") entry = inheritConfig(entry, config);
|
|
1724
|
-
|
|
1725
|
-
if (!hasInput) throw new Error(`Build entry missing \`input\` or \`entry\`: ${JSON.stringify(entry, null, 2)}`);
|
|
1758
|
+
if (!hasValidInput(entry)) throw new Error(`Build entry missing \`input\` or \`entry\`: ${JSON.stringify(entry, null, 2)}`);
|
|
1726
1759
|
entry = { ...entry };
|
|
1727
1760
|
entry.outDir = normalizePath(entry.outDir || "dist", ctx.pkgDir);
|
|
1728
1761
|
if (entry.type === "transform") {
|
|
1729
1762
|
if (entry.input) entry.input = normalizePath(entry.input, ctx.pkgDir);
|
|
1730
1763
|
} else {
|
|
1731
|
-
const entryInput = entry
|
|
1732
|
-
if (entryInput)
|
|
1733
|
-
const normalizedInput = {};
|
|
1734
|
-
for (const [key, value] of Object.entries(entryInput)) normalizedInput[key] = normalizePath(value, ctx.pkgDir);
|
|
1735
|
-
entry.input = normalizedInput;
|
|
1736
|
-
} else if (Array.isArray(entryInput)) entry.input = entryInput.map((p) => normalizePath(p, ctx.pkgDir));
|
|
1737
|
-
else entry.input = normalizePath(entryInput, ctx.pkgDir);
|
|
1764
|
+
const entryInput = getBundleEntryInput(entry);
|
|
1765
|
+
if (entryInput) entry.input = normalizeEntryInput(entryInput, ctx.pkgDir);
|
|
1738
1766
|
}
|
|
1739
1767
|
return entry;
|
|
1740
1768
|
});
|
|
@@ -1745,21 +1773,17 @@ async function performBuild(config, ctx, startTime) {
|
|
|
1745
1773
|
await hooks.end?.(ctx);
|
|
1746
1774
|
if (shouldFailOnWarnings(config.failOnWarn || false)) throw new Error("Build failed due to warnings");
|
|
1747
1775
|
const dirSize = analyzeDir(outDirs);
|
|
1748
|
-
logger.info(colors.dim(`\
|
|
1776
|
+
logger.info(colors.dim(`\nTotal: ${colors.bold(prettyBytes(dirSize.size))} (${dirSize.files} files)`));
|
|
1749
1777
|
const duration = Date.now() - start;
|
|
1750
|
-
logger.success(`\
|
|
1778
|
+
logger.success(`\nBuild succeeded in ${colors.bold(`${duration}ms`)}`);
|
|
1751
1779
|
if (config.onSuccess) {
|
|
1752
1780
|
const buildResult = createBuildResult([], startTime);
|
|
1753
1781
|
await executeOnSuccess(config.onSuccess, buildResult, ctx.pkgDir);
|
|
1754
1782
|
}
|
|
1755
1783
|
}
|
|
1756
|
-
function normalizePath(path, resolveFrom) {
|
|
1757
|
-
return typeof path === "string" && isAbsolute(path) ? path : path instanceof URL ? fileURLToPath(path) : resolve(resolveFrom || ".", path || ".");
|
|
1758
|
-
}
|
|
1759
1784
|
async function readJSON(specifier) {
|
|
1760
|
-
|
|
1761
|
-
return module.default;
|
|
1785
|
+
return (await import(specifier, { with: { type: "json" } })).default;
|
|
1762
1786
|
}
|
|
1763
1787
|
|
|
1764
1788
|
//#endregion
|
|
1765
|
-
export {
|
|
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 };
|