robuild 0.1.0 → 0.1.2

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.
@@ -1,4 +1,4 @@
1
- import { t as RobuildPluginManager } from "./plugin-manager-CwMXjVtp.mjs";
1
+ import { t as RobuildPluginManager } from "./manager-DyYf90Z5.mjs";
2
2
  import { builtinModules } from "node:module";
3
3
  import { basename, dirname, extname, isAbsolute, join, relative, resolve } from "node:path";
4
4
  import { colors } from "consola/utils";
@@ -9,19 +9,19 @@ import { parseSync } from "oxc-parser";
9
9
  import { rolldown, watch } from "rolldown";
10
10
  import { dts } from "rolldown-plugin-dts";
11
11
  import { existsSync, promises, readdirSync, statSync } from "node:fs";
12
- import { consola } from "consola";
13
12
  import { fileURLToPath, pathToFileURL } from "node:url";
14
13
  import { gzipSync } from "node:zlib";
15
14
  import { minify } from "oxc-minify";
16
- import { glob } from "glob";
15
+ import { consola } from "consola";
17
16
  import { createHash } from "node:crypto";
17
+ import { glob } from "glob";
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
24
+ //#region src/core/logger.ts
25
25
  /**
26
26
  * Logger instance with configurable log level
27
27
  */
@@ -110,171 +110,199 @@ function shouldFailOnWarnings(failOnWarn) {
110
110
  }
111
111
 
112
112
  //#endregion
113
- //#region src/features/advanced-build.ts
113
+ //#region src/utils/extensions.ts
114
114
  /**
115
- * Create skip node_modules plugin
115
+ * Get file extension for a given format (with leading dot).
116
+ * This is the unified function used by bundle, watch, and transform modes.
117
+ *
118
+ * @param format - The module format (es, cjs, iife, umd, etc.)
119
+ * @param platform - The target platform
120
+ * @param fixedExtension - Whether to force .cjs/.mjs extensions
121
+ * @returns The file extension with leading dot (e.g., '.mjs', '.cjs', '.js')
116
122
  */
117
- function createSkipNodeModulesPlugin(options) {
118
- const noExternalPatterns = options?.noExternal || [];
119
- const shouldInline = (id) => {
120
- for (const pattern of noExternalPatterns) if (typeof pattern === "string") {
121
- if (id === pattern || id.startsWith(`${pattern}/`)) return true;
122
- } else if (pattern instanceof RegExp) {
123
- if (pattern.test(id)) return true;
124
- }
125
- return false;
126
- };
127
- return {
128
- name: "skip-node-modules",
129
- resolveId: async (id, importer) => {
130
- if (shouldInline(id)) return null;
131
- if (!importer) return null;
132
- if (id.includes("node_modules") || !id.startsWith(".") && !id.startsWith("/") && !id.startsWith("\\")) return {
133
- id,
134
- external: true
135
- };
136
- return null;
137
- }
138
- };
123
+ function getFormatExtension(format, platform = "node", fixedExtension = false) {
124
+ if (fixedExtension) return format === "cjs" || format === "commonjs" ? ".cjs" : ".mjs";
125
+ switch (format) {
126
+ case "es":
127
+ case "esm":
128
+ case "module": return ".mjs";
129
+ case "cjs":
130
+ case "commonjs": return platform === "node" ? ".cjs" : ".js";
131
+ case "iife":
132
+ case "umd": return ".js";
133
+ default: return ".js";
134
+ }
139
135
  }
140
136
  /**
141
- * Unbundle mode: preserve file structure without bundling
137
+ * Resolve JavaScript output extension (without leading dot).
138
+ * @deprecated Use getFormatExtension() instead for consistency
142
139
  */
143
- async function unbundleTransform(ctx, entry) {
144
- await processDirectoryUnbundled(isAbsolute(entry.input) ? entry.input : join(ctx.pkgDir, entry.input), join(ctx.pkgDir, entry.outDir || "dist"), entry);
140
+ function resolveJsOutputExtension(format, platform = "node", fixedExtension = false) {
141
+ if (fixedExtension) return format === "cjs" ? "cjs" : "mjs";
142
+ switch (format) {
143
+ case "es": return platform === "browser" ? "js" : "mjs";
144
+ case "cjs": return platform === "browser" ? "js" : "cjs";
145
+ case "iife":
146
+ case "umd": return "js";
147
+ default: return "js";
148
+ }
145
149
  }
146
150
  /**
147
- * Process directory in unbundle mode
151
+ * Resolve DTS output extension
148
152
  */
149
- async function processDirectoryUnbundled(inputDir, outputDir, entry) {
150
- const entries = await readdir(inputDir, { withFileTypes: true });
151
- for (const dirEntry of entries) {
152
- const inputPath = join(inputDir, dirEntry.name);
153
- const outputPath = join(outputDir, dirEntry.name);
154
- if (dirEntry.isDirectory()) {
155
- if (entry.skipNodeModules && dirEntry.name === "node_modules") continue;
156
- await mkdir(dirname(outputPath), { recursive: true });
157
- await processDirectoryUnbundled(inputPath, outputPath, entry);
158
- } else if (dirEntry.isFile()) await processFileUnbundled(inputPath, outputPath, entry);
153
+ function resolveDtsOutputExtension(format, fixedExtension = false) {
154
+ if (fixedExtension) return format === "cjs" ? "d.cts" : "d.mts";
155
+ switch (format) {
156
+ case "es": return "d.mts";
157
+ case "cjs": return "d.cts";
158
+ default: return "d.ts";
159
159
  }
160
160
  }
161
161
  /**
162
- * Process individual file in unbundle mode
162
+ * Apply custom output extensions
163
163
  */
164
- async function processFileUnbundled(inputPath, outputPath, entry) {
165
- const ext = extname(inputPath);
166
- if (![
167
- ".js",
168
- ".ts",
169
- ".jsx",
170
- ".tsx",
171
- ".mjs",
172
- ".mts",
173
- ".cjs",
174
- ".cts"
175
- ].includes(ext)) return;
176
- try {
177
- const transformedContent = transformImportsForUnbundle(await readFile(inputPath, "utf-8"), inputPath, entry);
178
- const outputExt = getUnbundleOutputExtension(ext, entry);
179
- const finalOutputPath = outputPath.replace(ext, outputExt);
180
- await mkdir(dirname(finalOutputPath), { recursive: true });
181
- await writeFile(finalOutputPath, transformedContent, "utf-8");
182
- } catch (error) {
183
- logger.warn(`Failed to process file ${inputPath}:`, error);
164
+ function applyOutExtensions(format, outExtensions) {
165
+ const defaultJs = resolveJsOutputExtension(format);
166
+ const defaultDts = resolveDtsOutputExtension(format);
167
+ if (!outExtensions) return {
168
+ js: defaultJs,
169
+ dts: defaultDts
170
+ };
171
+ const custom = outExtensions(format);
172
+ return {
173
+ js: custom.js || defaultJs,
174
+ dts: custom.dts || defaultDts
175
+ };
176
+ }
177
+ /**
178
+ * Create filename with proper extension
179
+ */
180
+ function createFilename(basename, format, isDts = false, options = {}) {
181
+ const { platform, fixedExtension, outExtensions } = options;
182
+ if (outExtensions) {
183
+ const extensions = applyOutExtensions(format, outExtensions);
184
+ return `${basename}.${isDts ? extensions.dts : extensions.js}`;
184
185
  }
186
+ if (isDts) return `${basename}.${resolveDtsOutputExtension(format, fixedExtension)}`;
187
+ return `${basename}.${resolveJsOutputExtension(format, platform, fixedExtension)}`;
185
188
  }
189
+
190
+ //#endregion
191
+ //#region src/utils/hash.ts
186
192
  /**
187
- * Transform imports for unbundle mode
193
+ * Generate content hash for filename
188
194
  */
189
- function transformImportsForUnbundle(content, _filePath, entry) {
190
- let transformedContent = content;
191
- transformedContent = transformedContent.replace(/from\s+['"]([^'"]+)['"]/g, (match, importPath) => {
192
- if (importPath.startsWith(".")) {
193
- const newImportPath = updateImportExtension(importPath, entry);
194
- return match.replace(importPath, newImportPath);
195
- }
196
- return match;
197
- });
198
- transformedContent = transformedContent.replace(/require\s*\(\s*['"]([^'"]+)['"]\s*\)/g, (match, importPath) => {
199
- if (importPath.startsWith(".")) {
200
- const newImportPath = updateImportExtension(importPath, entry);
201
- return match.replace(importPath, newImportPath);
202
- }
203
- return match;
204
- });
205
- return transformedContent;
195
+ function generateContentHash(content, length = 8) {
196
+ return createHash("sha256").update(content).digest("hex").slice(0, length);
206
197
  }
207
198
  /**
208
- * Update import extension for unbundle mode
199
+ * Add hash to filename
209
200
  */
210
- function updateImportExtension(importPath, entry) {
211
- const ext = extname(importPath);
212
- if (!ext) return `${importPath}.js`;
213
- if ([
214
- ".ts",
215
- ".tsx",
216
- ".mts",
217
- ".cts"
218
- ].includes(ext)) {
219
- const newExt = getUnbundleOutputExtension(ext, entry);
220
- return importPath.replace(ext, newExt);
221
- }
222
- return importPath;
201
+ function addHashToFilename(filename, content, hashLength = 8) {
202
+ const hash = generateContentHash(content, hashLength);
203
+ const dotIndex = filename.lastIndexOf(".");
204
+ if (dotIndex === -1) return `${filename}-${hash}`;
205
+ return `${filename.slice(0, dotIndex)}-${hash}${filename.slice(dotIndex)}`;
223
206
  }
224
207
  /**
225
- * Get output extension for unbundle mode
208
+ * Check if filename already has hash
226
209
  */
227
- function getUnbundleOutputExtension(inputExt, entry) {
228
- const format = Array.isArray(entry.format) ? entry.format[0] : entry.format || "es";
229
- switch (inputExt) {
230
- case ".ts":
231
- case ".tsx": return format === "cjs" ? ".cjs" : ".mjs";
232
- case ".mts": return ".mjs";
233
- case ".cts": return ".cjs";
234
- case ".js":
235
- case ".jsx": return format === "cjs" ? ".cjs" : ".mjs";
236
- case ".mjs": return ".mjs";
237
- case ".cjs": return ".cjs";
238
- default: return ".js";
239
- }
210
+ function hasHash(filename) {
211
+ return /-[a-f0-9]{8}(?:\.|$)/.test(filename);
240
212
  }
241
213
 
242
214
  //#endregion
243
- //#region src/features/banner.ts
215
+ //#region src/utils/node-protocol.ts
244
216
  /**
245
- * Resolve banner/footer addon for specific format
217
+ * Node.js built-in modules that support the node: protocol
246
218
  */
247
- function resolveChunkAddon(addon, format) {
248
- if (!addon) return;
249
- if (typeof addon === "string") return addon;
250
- return addon[format === "es" ? "js" : format] || addon.js;
219
+ const NODE_BUILTIN_MODULES = new Set([
220
+ "assert",
221
+ "async_hooks",
222
+ "buffer",
223
+ "child_process",
224
+ "cluster",
225
+ "console",
226
+ "constants",
227
+ "crypto",
228
+ "dgram",
229
+ "diagnostics_channel",
230
+ "dns",
231
+ "domain",
232
+ "events",
233
+ "fs",
234
+ "http",
235
+ "http2",
236
+ "https",
237
+ "inspector",
238
+ "module",
239
+ "net",
240
+ "os",
241
+ "path",
242
+ "perf_hooks",
243
+ "process",
244
+ "punycode",
245
+ "querystring",
246
+ "readline",
247
+ "repl",
248
+ "stream",
249
+ "string_decoder",
250
+ "sys",
251
+ "timers",
252
+ "tls",
253
+ "trace_events",
254
+ "tty",
255
+ "url",
256
+ "util",
257
+ "v8",
258
+ "vm",
259
+ "wasi",
260
+ "worker_threads",
261
+ "zlib"
262
+ ]);
263
+ /**
264
+ * Check if a module is a Node.js built-in module
265
+ */
266
+ function isNodeBuiltin(id) {
267
+ const cleanId = id.startsWith("node:") ? id.slice(5) : id;
268
+ return NODE_BUILTIN_MODULES.has(cleanId);
251
269
  }
252
270
  /**
253
- * Add banner to content
271
+ * Add node: prefix to built-in modules
254
272
  */
255
- function addBanner(content, banner) {
256
- if (!banner) return content;
257
- return `${banner}\n${content}`;
273
+ function addNodeProtocol(id) {
274
+ if (id.startsWith("node:")) return id;
275
+ if (isNodeBuiltin(id)) return `node:${id}`;
276
+ return id;
258
277
  }
259
278
  /**
260
- * Add footer to content
279
+ * Remove node: prefix from modules
261
280
  */
262
- function addFooter(content, footer) {
263
- if (!footer) return content;
264
- return `${content}\n${footer}`;
281
+ function stripNodeProtocol(id) {
282
+ if (id.startsWith("node:")) return id.slice(5);
283
+ return id;
265
284
  }
266
285
  /**
267
- * Add both banner and footer to content
286
+ * Process module ID based on nodeProtocol setting
268
287
  */
269
- function addBannerFooter(content, banner, footer) {
270
- let result = content;
271
- result = addBanner(result, banner);
272
- result = addFooter(result, footer);
273
- return result;
288
+ function processNodeProtocol(id, nodeProtocol) {
289
+ if (nodeProtocol === "strip") return stripNodeProtocol(id);
290
+ if (nodeProtocol === true) return addNodeProtocol(id);
291
+ return id;
292
+ }
293
+ /**
294
+ * Transform import/export statements to handle node protocol
295
+ */
296
+ function transformNodeProtocol(code, nodeProtocol) {
297
+ if (!nodeProtocol) return code;
298
+ return code.replace(/(?:import|export)(?:\s[^'"]*)?\s['"]([^'"]+)['"]/g, (match, moduleId) => {
299
+ const processedId = processNodeProtocol(moduleId, nodeProtocol);
300
+ return match.replace(moduleId, processedId);
301
+ });
274
302
  }
275
303
 
276
304
  //#endregion
277
- //#region src/utils.ts
305
+ //#region src/utils/index.ts
278
306
  /**
279
307
  * Normalize a path to an absolute path.
280
308
  * Handles string paths, URL objects, and undefined values.
@@ -362,219 +390,85 @@ async function sideEffectSize(dir, entry) {
362
390
  }
363
391
  }]
364
392
  })).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
-
406
- //#endregion
407
- //#region src/features/copy.ts
408
- /**
409
- * Copy files to output directory
410
- */
411
- async function copyFiles(cwd, outDir, copyOptions) {
412
- if (!copyOptions || copyOptions.length === 0) return;
413
- logger.verbose("Copying files...");
414
- await Promise.all(copyOptions.map(async (entry) => {
415
- const from = typeof entry === "string" ? entry : entry.from;
416
- const to = typeof entry === "string" ? resolve(outDir, basename(from)) : resolve(cwd, entry.to);
417
- const fromPath = resolve(cwd, from);
418
- try {
419
- await cp(fromPath, to, {
420
- recursive: true,
421
- force: true
422
- });
423
- logger.verbose(` ${from} → ${to}`);
424
- } catch (error) {
425
- logger.warn(`Failed to copy ${from} to ${to}:`, error);
426
- }
427
- }));
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";
393
+ if (process.env.INSPECT_BUILD) {
394
+ logger.debug("---------[side effects]---------");
395
+ logger.debug(entry);
396
+ logger.debug(output[0].code);
397
+ logger.debug("-------------------------------");
537
398
  }
399
+ return Buffer.byteLength(output[0].code.trim());
538
400
  }
401
+
402
+ //#endregion
403
+ //#region src/config/entry-resolver.ts
539
404
  /**
540
- * Apply custom output extensions
405
+ * Parse a string entry format like "src/index.ts:dist" or "src/:dist"
406
+ *
407
+ * @param rawEntry - The raw string entry
408
+ * @returns Parsed entry object
541
409
  */
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
410
+ function parseEntryString(rawEntry) {
411
+ const [input, outDir] = rawEntry.split(":");
412
+ if (input.endsWith("/")) return {
413
+ type: "transform",
414
+ input,
415
+ outDir: outDir || "dist"
548
416
  };
549
- const custom = outExtensions(format);
550
417
  return {
551
- js: custom.js || defaultJs,
552
- dts: custom.dts || defaultDts
418
+ type: "bundle",
419
+ input: input.includes(",") ? input.split(",") : input,
420
+ outDir: outDir || "dist"
553
421
  };
554
422
  }
555
423
  /**
556
- * Create filename with proper extension
424
+ * Normalize entry input paths to absolute paths.
425
+ * Handles string, array, and object (named entries) formats.
426
+ *
427
+ * @param entryInput - The entry input (string, array, or object)
428
+ * @param pkgDir - The package directory to resolve paths from
429
+ * @returns Normalized input
557
430
  */
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}`;
431
+ function normalizeEntryInput(entryInput, pkgDir) {
432
+ if (typeof entryInput === "object" && !Array.isArray(entryInput)) {
433
+ const normalizedInput = {};
434
+ for (const [key, value] of Object.entries(entryInput)) normalizedInput[key] = normalizePath(value, pkgDir);
435
+ return normalizedInput;
563
436
  }
564
- if (isDts) return `${basename}.${resolveDtsOutputExtension(format, fixedExtension)}`;
565
- return `${basename}.${resolveJsOutputExtension(format, platform, fixedExtension)}`;
437
+ if (Array.isArray(entryInput)) return entryInput.map((p) => normalizePath(p, pkgDir));
438
+ return normalizePath(entryInput, pkgDir);
439
+ }
440
+ /**
441
+ * Get the entry input from a BundleEntry, supporting both 'input' and 'entry' fields.
442
+ * This provides tsup compatibility.
443
+ *
444
+ * @param entry - The bundle entry
445
+ * @returns The entry input or undefined
446
+ */
447
+ function getBundleEntryInput(entry) {
448
+ return entry.input || entry.entry;
449
+ }
450
+ /**
451
+ * Check if an entry has valid input.
452
+ *
453
+ * @param entry - The entry to check
454
+ * @returns true if the entry has valid input
455
+ */
456
+ function hasValidInput(entry) {
457
+ if (entry.type === "transform") return !!entry.input;
458
+ return !!getBundleEntryInput(entry);
566
459
  }
567
460
 
568
461
  //#endregion
569
- //#region src/features/external.ts
462
+ //#region src/config/external.ts
570
463
  /**
571
464
  * Build external dependencies list from package.json dependencies and peerDependencies.
572
465
  * This is the shared logic used by both bundle and watch modes.
573
466
  */
574
467
  function buildExternalDeps(ctx) {
468
+ const excludedBuiltins = new Set(["module"]);
575
469
  return [
576
- ...builtinModules,
577
- ...builtinModules.map((m) => `node:${m}`),
470
+ ...builtinModules.filter((m) => !excludedBuiltins.has(m)),
471
+ ...builtinModules.filter((m) => !excludedBuiltins.has(m)).map((m) => `node:${m}`),
578
472
  ...[...Object.keys(ctx.pkg.dependencies || {}), ...Object.keys(ctx.pkg.peerDependencies || {})].flatMap((p) => [p, new RegExp(`^${p}/`)])
579
473
  ];
580
474
  }
@@ -648,7 +542,36 @@ function resolveExternalConfig(ctx, options) {
648
542
  }
649
543
 
650
544
  //#endregion
651
- //#region src/features/glob-import.ts
545
+ //#region src/plugins/builtin/glob-import.ts
546
+ /**
547
+ * Core transform logic for glob imports
548
+ */
549
+ async function transformGlobImportCode(code, id, options) {
550
+ const { patterns, asUrls, eager } = options;
551
+ const globImportRegex = /import\.meta\.glob\s*\(\s*(['"`])(.*?)\1\s*(?:,\s*(\{[^}]*\})\s*)?\)/g;
552
+ let match;
553
+ let hasGlobImports = false;
554
+ let transformedCode = code;
555
+ while ((match = globImportRegex.exec(code)) !== null) {
556
+ hasGlobImports = true;
557
+ const [fullMatch, , pattern, optionsStr] = match;
558
+ let globOptions = {};
559
+ if (optionsStr) try {
560
+ globOptions = parseGlobOptions(optionsStr);
561
+ } catch {
562
+ logger.warn("Failed to parse glob options:", optionsStr);
563
+ }
564
+ const isEager = globOptions.eager ?? eager;
565
+ const isAsUrls = globOptions.as === "url" || asUrls;
566
+ try {
567
+ const replacement = await generateGlobImport(pattern, id, isEager, isAsUrls, patterns);
568
+ transformedCode = transformedCode.replace(fullMatch, replacement);
569
+ } catch (error) {
570
+ logger.error(`Failed to process glob import ${pattern}:`, error);
571
+ }
572
+ }
573
+ return hasGlobImports ? transformedCode : null;
574
+ }
652
575
  /**
653
576
  * Create a glob import plugin for robuild
654
577
  */
@@ -657,30 +580,12 @@ function createGlobImportPlugin(options = {}) {
657
580
  if (!enabled) return { name: "glob-import-disabled" };
658
581
  return {
659
582
  name: "glob-import",
660
- transform: async (code, id) => {
661
- const globImportRegex = /import\.meta\.glob\s*\(\s*(['"`])(.*?)\1\s*(?:,\s*(\{[^}]*\})\s*)?\)/g;
662
- let match;
663
- let hasGlobImports = false;
664
- let transformedCode = code;
665
- while ((match = globImportRegex.exec(code)) !== null) {
666
- hasGlobImports = true;
667
- const [fullMatch, , pattern, optionsStr] = match;
668
- let globOptions = {};
669
- if (optionsStr) try {
670
- globOptions = parseGlobOptions(optionsStr);
671
- } catch {
672
- logger.warn("Failed to parse glob options:", optionsStr);
673
- }
674
- const isEager = globOptions.eager ?? eager;
675
- const isAsUrls = globOptions.as === "url" || asUrls;
676
- try {
677
- const replacement = await generateGlobImport(pattern, id, isEager, isAsUrls, patterns);
678
- transformedCode = transformedCode.replace(fullMatch, replacement);
679
- } catch (error) {
680
- logger.error(`Failed to process glob import ${pattern}:`, error);
681
- }
682
- }
683
- return hasGlobImports ? transformedCode : null;
583
+ transform: async (code, id, _meta) => {
584
+ return transformGlobImportCode(code, id, {
585
+ patterns,
586
+ asUrls,
587
+ eager
588
+ });
684
589
  }
685
590
  };
686
591
  }
@@ -753,33 +658,54 @@ function parseGlobOptions(optionsStr) {
753
658
  if (asMatch) options.as = asMatch[1];
754
659
  return options;
755
660
  }
756
-
757
- //#endregion
758
- //#region src/features/hash.ts
759
661
  /**
760
- * Generate content hash for filename
662
+ * Check if code contains glob imports
761
663
  */
762
- function generateContentHash(content, length = 8) {
763
- return createHash("sha256").update(content).digest("hex").slice(0, length);
664
+ function hasGlobImports(code) {
665
+ return /import\.meta\.glob\s*\(/.test(code);
764
666
  }
667
+
668
+ //#endregion
669
+ //#region src/plugins/builtin/node-protocol.ts
765
670
  /**
766
- * Add hash to filename
671
+ * Rolldown plugin for Node.js protocol handling
767
672
  */
768
- function addHashToFilename(filename, content, hashLength = 8) {
769
- const hash = generateContentHash(content, hashLength);
770
- const dotIndex = filename.lastIndexOf(".");
771
- if (dotIndex === -1) return `${filename}-${hash}`;
772
- return `${filename.slice(0, dotIndex)}-${hash}${filename.slice(dotIndex)}`;
673
+ function nodeProtocolPlugin(nodeProtocol) {
674
+ if (!nodeProtocol) return { name: "node-protocol-noop" };
675
+ return {
676
+ name: "node-protocol",
677
+ renderChunk(code) {
678
+ return {
679
+ code: transformNodeProtocol(code, nodeProtocol),
680
+ map: null
681
+ };
682
+ }
683
+ };
773
684
  }
774
- /**
775
- * Check if filename already has hash
776
- */
777
- function hasHash(filename) {
778
- return /-[a-f0-9]{8}(?:\.|$)/.test(filename);
685
+
686
+ //#endregion
687
+ //#region src/plugins/builtin/shebang.ts
688
+ const SHEBANG_RE = /^#![^\n]*/;
689
+ function shebangPlugin() {
690
+ return {
691
+ name: "robuild-shebang",
692
+ async writeBundle(options, bundle) {
693
+ for (const [fileName, output] of Object.entries(bundle)) {
694
+ if (output.type !== "chunk") continue;
695
+ if (hasShebang(output.code)) await makeExecutable(resolve(options.dir, fileName));
696
+ }
697
+ }
698
+ };
699
+ }
700
+ function hasShebang(code) {
701
+ return SHEBANG_RE.test(code);
702
+ }
703
+ async function makeExecutable(filePath) {
704
+ await promises.chmod(filePath, 493).catch(() => {});
779
705
  }
780
706
 
781
707
  //#endregion
782
- //#region src/features/shims.ts
708
+ //#region src/plugins/builtin/shims.ts
783
709
  /**
784
710
  * Default shims configuration
785
711
  */
@@ -893,134 +819,155 @@ function createShimsPlugin(config = true) {
893
819
  }
894
820
  };
895
821
  }
896
-
897
- //#endregion
898
- //#region src/features/node-protocol.ts
899
822
  /**
900
- * Node.js built-in modules that support the node: protocol
823
+ * Create browser-specific shims plugin
901
824
  */
902
- const NODE_BUILTIN_MODULES = new Set([
903
- "assert",
904
- "async_hooks",
905
- "buffer",
906
- "child_process",
907
- "cluster",
908
- "console",
909
- "constants",
910
- "crypto",
911
- "dgram",
912
- "diagnostics_channel",
913
- "dns",
914
- "domain",
915
- "events",
916
- "fs",
917
- "http",
918
- "http2",
919
- "https",
920
- "inspector",
921
- "module",
922
- "net",
923
- "os",
924
- "path",
925
- "perf_hooks",
926
- "process",
927
- "punycode",
928
- "querystring",
929
- "readline",
930
- "repl",
931
- "stream",
932
- "string_decoder",
933
- "sys",
934
- "timers",
935
- "tls",
936
- "trace_events",
937
- "tty",
938
- "url",
939
- "util",
940
- "v8",
941
- "vm",
942
- "wasi",
943
- "worker_threads",
944
- "zlib"
945
- ]);
825
+ function createBrowserShimsPlugin() {
826
+ return {
827
+ name: "browser-shims",
828
+ transform: async (code, id) => {
829
+ if (!/\.(?:js|mjs|jsx|tsx?)$/.test(id)) return null;
830
+ if (detectShimNeeds(code).needsEnv) return `${PROCESS_ENV_SHIM}\n${code}`;
831
+ return null;
832
+ }
833
+ };
834
+ }
946
835
  /**
947
- * Check if a module is a Node.js built-in module
836
+ * Create Node.js-specific shims plugin
948
837
  */
949
- function isNodeBuiltin(id) {
950
- const cleanId = id.startsWith("node:") ? id.slice(5) : id;
951
- return NODE_BUILTIN_MODULES.has(cleanId);
838
+ function createNodeShimsPlugin() {
839
+ return {
840
+ name: "node-shims",
841
+ transform: async (code, id) => {
842
+ if (!/\.mjs$/.test(id) && !/\.js$/.test(id)) return null;
843
+ const needs = detectShimNeeds(code);
844
+ const shims = [];
845
+ if (needs.needsDirname || needs.needsRequire) shims.push(NODE_GLOBALS_SHIM);
846
+ if (needs.needsExports) shims.push(MODULE_EXPORTS_SHIM);
847
+ if (shims.length === 0) return null;
848
+ return `${shims.join("\n")}\n${code}`;
849
+ }
850
+ };
952
851
  }
852
+
853
+ //#endregion
854
+ //#region src/plugins/builtin/skip-node-modules.ts
953
855
  /**
954
- * Add node: prefix to built-in modules
856
+ * Create skip node_modules plugin
955
857
  */
956
- function addNodeProtocol(id) {
957
- if (id.startsWith("node:")) return id;
958
- if (isNodeBuiltin(id)) return `node:${id}`;
959
- return id;
858
+ function createSkipNodeModulesPlugin(options) {
859
+ const noExternalPatterns = options?.noExternal || [];
860
+ const shouldInline = (id) => {
861
+ for (const pattern of noExternalPatterns) if (typeof pattern === "string") {
862
+ if (id === pattern || id.startsWith(`${pattern}/`)) return true;
863
+ } else if (pattern instanceof RegExp) {
864
+ if (pattern.test(id)) return true;
865
+ }
866
+ return false;
867
+ };
868
+ return {
869
+ name: "skip-node-modules",
870
+ resolveId: async (id, importer) => {
871
+ if (shouldInline(id)) return null;
872
+ if (!importer) return null;
873
+ if (id.includes("node_modules") || !id.startsWith(".") && !id.startsWith("/") && !id.startsWith("\\")) return {
874
+ id,
875
+ external: true
876
+ };
877
+ return null;
878
+ }
879
+ };
960
880
  }
881
+
882
+ //#endregion
883
+ //#region src/transforms/banner.ts
961
884
  /**
962
- * Remove node: prefix from modules
885
+ * Resolve banner/footer addon for specific format
963
886
  */
964
- function stripNodeProtocol(id) {
965
- if (id.startsWith("node:")) return id.slice(5);
966
- return id;
887
+ function resolveChunkAddon(addon, format) {
888
+ if (!addon) return;
889
+ if (typeof addon === "string") return addon;
890
+ return addon[format === "es" ? "js" : format] || addon.js;
967
891
  }
968
892
  /**
969
- * Process module ID based on nodeProtocol setting
893
+ * Add banner to content
970
894
  */
971
- function processNodeProtocol(id, nodeProtocol) {
972
- if (nodeProtocol === "strip") return stripNodeProtocol(id);
973
- if (nodeProtocol === true) return addNodeProtocol(id);
974
- return id;
895
+ function addBanner(content, banner) {
896
+ if (!banner) return content;
897
+ return `${banner}\n${content}`;
975
898
  }
976
899
  /**
977
- * Transform import/export statements to handle node protocol
900
+ * Add footer to content
978
901
  */
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
- });
902
+ function addFooter(content, footer) {
903
+ if (!footer) return content;
904
+ return `${content}\n${footer}`;
905
+ }
906
+ /**
907
+ * Add both banner and footer to content
908
+ */
909
+ function addBannerFooter(content, banner, footer) {
910
+ let result = content;
911
+ result = addBanner(result, banner);
912
+ result = addFooter(result, footer);
913
+ return result;
985
914
  }
986
915
 
987
916
  //#endregion
988
- //#region src/plugins/node-protocol.ts
917
+ //#region src/transforms/clean.ts
989
918
  /**
990
- * Rolldown plugin for Node.js protocol handling
919
+ * Clean output directory or specific paths.
920
+ * Used by both bundle and transform builders.
921
+ *
922
+ * @param projectRoot - The project root directory
923
+ * @param outDir - The output directory to clean
924
+ * @param cleanPaths - true to clean outDir, or array of specific paths to clean
991
925
  */
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
- };
926
+ async function cleanOutputDir(projectRoot, outDir, cleanPaths) {
927
+ if (!cleanPaths) return;
928
+ if (cleanPaths === true) {
929
+ if (existsSync(outDir)) {
930
+ logger.log(colors.dim(`Cleaning ${fmtPath(outDir)}`));
931
+ await rm(outDir, {
932
+ recursive: true,
933
+ force: true
934
+ });
1001
935
  }
1002
- };
936
+ } else if (Array.isArray(cleanPaths)) for (const path of cleanPaths) {
937
+ const fullPath = resolve(projectRoot, path);
938
+ if (existsSync(fullPath)) {
939
+ logger.log(colors.dim(`Cleaning ${fmtPath(fullPath)}`));
940
+ await rm(fullPath, {
941
+ recursive: true,
942
+ force: true
943
+ });
944
+ }
945
+ }
1003
946
  }
1004
947
 
1005
948
  //#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
- }
949
+ //#region src/transforms/copy.ts
950
+ /**
951
+ * Copy files to output directory
952
+ */
953
+ async function copyFiles(cwd, outDir, copyOptions) {
954
+ if (!copyOptions || copyOptions.length === 0) return;
955
+ logger.verbose("Copying files...");
956
+ await Promise.all(copyOptions.map(async (entry) => {
957
+ const from = typeof entry === "string" ? entry : entry.from;
958
+ const to = typeof entry === "string" ? resolve(outDir, basename(from)) : resolve(cwd, entry.to);
959
+ const fromPath = resolve(cwd, from);
960
+ try {
961
+ await cp(fromPath, to, {
962
+ recursive: true,
963
+ force: true
964
+ });
965
+ logger.verbose(` ${from} → ${to}`);
966
+ } catch (error) {
967
+ logger.warn(`Failed to copy ${from} to ${to}:`, error);
1016
968
  }
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(() => {});
969
+ }));
970
+ logger.verbose("Files copied successfully");
1024
971
  }
1025
972
 
1026
973
  //#endregion
@@ -1253,6 +1200,110 @@ function normalizeBundleInputs(input, ctx) {
1253
1200
  return inputs;
1254
1201
  }
1255
1202
 
1203
+ //#endregion
1204
+ //#region src/builders/unbundle.ts
1205
+ /**
1206
+ * Unbundle mode: preserve file structure without bundling
1207
+ */
1208
+ async function unbundleTransform(ctx, entry) {
1209
+ await processDirectoryUnbundled(isAbsolute(entry.input) ? entry.input : join(ctx.pkgDir, entry.input), join(ctx.pkgDir, entry.outDir || "dist"), entry);
1210
+ }
1211
+ /**
1212
+ * Process directory in unbundle mode
1213
+ */
1214
+ async function processDirectoryUnbundled(inputDir, outputDir, entry) {
1215
+ const entries = await readdir(inputDir, { withFileTypes: true });
1216
+ for (const dirEntry of entries) {
1217
+ const inputPath = join(inputDir, dirEntry.name);
1218
+ const outputPath = join(outputDir, dirEntry.name);
1219
+ if (dirEntry.isDirectory()) {
1220
+ if (entry.skipNodeModules && dirEntry.name === "node_modules") continue;
1221
+ await mkdir(dirname(outputPath), { recursive: true });
1222
+ await processDirectoryUnbundled(inputPath, outputPath, entry);
1223
+ } else if (dirEntry.isFile()) await processFileUnbundled(inputPath, outputPath, entry);
1224
+ }
1225
+ }
1226
+ /**
1227
+ * Process individual file in unbundle mode
1228
+ */
1229
+ async function processFileUnbundled(inputPath, outputPath, entry) {
1230
+ const ext = extname(inputPath);
1231
+ if (![
1232
+ ".js",
1233
+ ".ts",
1234
+ ".jsx",
1235
+ ".tsx",
1236
+ ".mjs",
1237
+ ".mts",
1238
+ ".cjs",
1239
+ ".cts"
1240
+ ].includes(ext)) return;
1241
+ try {
1242
+ const transformedContent = transformImportsForUnbundle(await readFile(inputPath, "utf-8"), inputPath, entry);
1243
+ const outputExt = getUnbundleOutputExtension(ext, entry);
1244
+ const finalOutputPath = outputPath.replace(ext, outputExt);
1245
+ await mkdir(dirname(finalOutputPath), { recursive: true });
1246
+ await writeFile(finalOutputPath, transformedContent, "utf-8");
1247
+ } catch (error) {
1248
+ logger.warn(`Failed to process file ${inputPath}:`, error);
1249
+ }
1250
+ }
1251
+ /**
1252
+ * Transform imports for unbundle mode
1253
+ */
1254
+ function transformImportsForUnbundle(content, _filePath, entry) {
1255
+ let transformedContent = content;
1256
+ transformedContent = transformedContent.replace(/from\s+['"]([^'"]+)['"]/g, (match, importPath) => {
1257
+ if (importPath.startsWith(".")) {
1258
+ const newImportPath = updateImportExtension(importPath, entry);
1259
+ return match.replace(importPath, newImportPath);
1260
+ }
1261
+ return match;
1262
+ });
1263
+ transformedContent = transformedContent.replace(/require\s*\(\s*['"]([^'"]+)['"]\s*\)/g, (match, importPath) => {
1264
+ if (importPath.startsWith(".")) {
1265
+ const newImportPath = updateImportExtension(importPath, entry);
1266
+ return match.replace(importPath, newImportPath);
1267
+ }
1268
+ return match;
1269
+ });
1270
+ return transformedContent;
1271
+ }
1272
+ /**
1273
+ * Update import extension for unbundle mode
1274
+ */
1275
+ function updateImportExtension(importPath, entry) {
1276
+ const ext = extname(importPath);
1277
+ if (!ext) return `${importPath}.js`;
1278
+ if ([
1279
+ ".ts",
1280
+ ".tsx",
1281
+ ".mts",
1282
+ ".cts"
1283
+ ].includes(ext)) {
1284
+ const newExt = getUnbundleOutputExtension(ext, entry);
1285
+ return importPath.replace(ext, newExt);
1286
+ }
1287
+ return importPath;
1288
+ }
1289
+ /**
1290
+ * Get output extension for unbundle mode
1291
+ */
1292
+ function getUnbundleOutputExtension(inputExt, entry) {
1293
+ const format = Array.isArray(entry.format) ? entry.format[0] : entry.format || "es";
1294
+ switch (inputExt) {
1295
+ case ".ts":
1296
+ case ".tsx": return format === "cjs" ? ".cjs" : ".mjs";
1297
+ case ".mts": return ".mjs";
1298
+ case ".cts": return ".cjs";
1299
+ case ".js":
1300
+ case ".jsx": return format === "cjs" ? ".cjs" : ".mjs";
1301
+ case ".mjs": return ".mjs";
1302
+ case ".cjs": return ".cjs";
1303
+ default: return ".js";
1304
+ }
1305
+ }
1306
+
1256
1307
  //#endregion
1257
1308
  //#region src/builders/transform.ts
1258
1309
  /**
@@ -1415,44 +1466,7 @@ async function transformModule(entryPath, entry) {
1415
1466
  }
1416
1467
 
1417
1468
  //#endregion
1418
- //#region src/features/on-success.ts
1419
- const execAsync = promisify(exec);
1420
- /**
1421
- * Execute onSuccess callback after successful build
1422
- */
1423
- async function executeOnSuccess(onSuccess, result, cwd) {
1424
- if (!onSuccess) return;
1425
- try {
1426
- if (typeof onSuccess === "string") {
1427
- logger.verbose(`Executing onSuccess command: ${onSuccess}`);
1428
- const { stdout, stderr } = await execAsync(onSuccess, { cwd });
1429
- if (stdout) logger.verbose(`onSuccess stdout: ${stdout.trim()}`);
1430
- if (stderr) logger.warn(`onSuccess stderr: ${stderr.trim()}`);
1431
- } else {
1432
- logger.verbose("Executing onSuccess callback function");
1433
- await onSuccess(result);
1434
- }
1435
- logger.verbose("onSuccess callback completed successfully");
1436
- } catch (error) {
1437
- logger.error("onSuccess callback failed:", error);
1438
- throw error;
1439
- }
1440
- }
1441
- /**
1442
- * Create build result object
1443
- */
1444
- function createBuildResult(entries, startTime) {
1445
- return {
1446
- entries: entries.map((entry) => ({
1447
- ...entry,
1448
- format: entry.format
1449
- })),
1450
- duration: Date.now() - startTime
1451
- };
1452
- }
1453
-
1454
- //#endregion
1455
- //#region src/features/vite-config.ts
1469
+ //#region src/config/vite-config.ts
1456
1470
  /**
1457
1471
  * Load Vite configuration and convert to robuild config
1458
1472
  */
@@ -1562,13 +1576,50 @@ function convertExternal(external) {
1562
1576
  return external;
1563
1577
  }
1564
1578
 
1579
+ //#endregion
1580
+ //#region src/transforms/on-success.ts
1581
+ const execAsync = promisify(exec);
1582
+ /**
1583
+ * Execute onSuccess callback after successful build
1584
+ */
1585
+ async function executeOnSuccess(onSuccess, result, cwd) {
1586
+ if (!onSuccess) return;
1587
+ try {
1588
+ if (typeof onSuccess === "string") {
1589
+ logger.verbose(`Executing onSuccess command: ${onSuccess}`);
1590
+ const { stdout, stderr } = await execAsync(onSuccess, { cwd });
1591
+ if (stdout) logger.verbose(`onSuccess stdout: ${stdout.trim()}`);
1592
+ if (stderr) logger.warn(`onSuccess stderr: ${stderr.trim()}`);
1593
+ } else {
1594
+ logger.verbose("Executing onSuccess callback function");
1595
+ await onSuccess(result);
1596
+ }
1597
+ logger.verbose("onSuccess callback completed successfully");
1598
+ } catch (error) {
1599
+ logger.error("onSuccess callback failed:", error);
1600
+ throw error;
1601
+ }
1602
+ }
1603
+ /**
1604
+ * Create build result object
1605
+ */
1606
+ function createBuildResult(entries, startTime) {
1607
+ return {
1608
+ entries: entries.map((entry) => ({
1609
+ ...entry,
1610
+ format: entry.format
1611
+ })),
1612
+ duration: Date.now() - startTime
1613
+ };
1614
+ }
1615
+
1565
1616
  //#endregion
1566
1617
  //#region src/watch.ts
1567
1618
  /**
1568
1619
  * Perform watch build using rolldown's built-in watch mode
1569
1620
  */
1570
1621
  async function performWatchBuild(config, ctx, startTime) {
1571
- const { performBuild } = await import("./build-tpynh1ZI.mjs");
1622
+ const { performBuild } = await import("./build-DsVOIGdc.mjs");
1572
1623
  await performBuild(config, ctx, startTime);
1573
1624
  const bundleEntries = (config.entries || []).filter((entry) => {
1574
1625
  if (typeof entry === "string") return !entry.endsWith("/");
@@ -1589,7 +1640,7 @@ async function performWatchBuild(config, ctx, startTime) {
1589
1640
  */
1590
1641
  async function startRolldownWatch(config, ctx, bundleEntries) {
1591
1642
  logger.info("Watching for changes...");
1592
- const { RobuildPluginManager } = await import("./plugin-manager-pCQvlo7q.mjs");
1643
+ const { RobuildPluginManager } = await import("./manager-CnmjrU85.mjs");
1593
1644
  const watchConfigs = [];
1594
1645
  for (const rawEntry of bundleEntries) {
1595
1646
  const entry = typeof rawEntry === "string" ? parseEntryString(rawEntry) : rawEntry;
@@ -1684,7 +1735,8 @@ const SHARED_CONFIG_FIELDS = [
1684
1735
  "footer",
1685
1736
  "shims",
1686
1737
  "rolldown",
1687
- "loaders"
1738
+ "loaders",
1739
+ "clean"
1688
1740
  ];
1689
1741
  /**
1690
1742
  * Inherit configuration from parent config to entry
@@ -1786,4 +1838,4 @@ async function readJSON(specifier) {
1786
1838
  }
1787
1839
 
1788
1840
  //#endregion
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 };
1841
+ export { createBrowserShimsPlugin as a, SHEBANG_RE as c, shebangPlugin as d, nodeProtocolPlugin as f, logger as g, configureLogger as h, DEFAULT_SHIMS_CONFIG as i, hasShebang as l, hasGlobImports as m, performBuild as n, createNodeShimsPlugin as o, createGlobImportPlugin as p, createSkipNodeModulesPlugin as r, createShimsPlugin as s, build as t, makeExecutable as u };