robuild 0.0.20 → 0.1.1

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.
@@ -334,7 +362,7 @@ async function distSize(dir, entry) {
334
362
  plugins: [],
335
363
  platform: "neutral",
336
364
  external: (id) => id[0] !== "." && !id.startsWith(dir)
337
- })).generate({ inlineDynamicImports: true });
365
+ })).generate({ codeSplitting: false });
338
366
  const code = output[0].code;
339
367
  const { code: minified } = await minify(entry, code);
340
368
  return {
@@ -361,212 +389,77 @@ async function sideEffectSize(dir, entry) {
361
389
  if (id === "#entry") return `import * as _lib from "${join(dir, entry)}";`;
362
390
  }
363
391
  }]
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
-
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";
392
+ })).generate({ codeSplitting: false });
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.
@@ -648,7 +541,36 @@ function resolveExternalConfig(ctx, options) {
648
541
  }
649
542
 
650
543
  //#endregion
651
- //#region src/features/glob-import.ts
544
+ //#region src/plugins/builtin/glob-import.ts
545
+ /**
546
+ * Core transform logic for glob imports
547
+ */
548
+ async function transformGlobImportCode(code, id, options) {
549
+ const { patterns, asUrls, eager } = options;
550
+ const globImportRegex = /import\.meta\.glob\s*\(\s*(['"`])(.*?)\1\s*(?:,\s*(\{[^}]*\})\s*)?\)/g;
551
+ let match;
552
+ let hasGlobImports = false;
553
+ let transformedCode = code;
554
+ while ((match = globImportRegex.exec(code)) !== null) {
555
+ hasGlobImports = true;
556
+ const [fullMatch, , pattern, optionsStr] = match;
557
+ let globOptions = {};
558
+ if (optionsStr) try {
559
+ globOptions = parseGlobOptions(optionsStr);
560
+ } catch {
561
+ logger.warn("Failed to parse glob options:", optionsStr);
562
+ }
563
+ const isEager = globOptions.eager ?? eager;
564
+ const isAsUrls = globOptions.as === "url" || asUrls;
565
+ try {
566
+ const replacement = await generateGlobImport(pattern, id, isEager, isAsUrls, patterns);
567
+ transformedCode = transformedCode.replace(fullMatch, replacement);
568
+ } catch (error) {
569
+ logger.error(`Failed to process glob import ${pattern}:`, error);
570
+ }
571
+ }
572
+ return hasGlobImports ? transformedCode : null;
573
+ }
652
574
  /**
653
575
  * Create a glob import plugin for robuild
654
576
  */
@@ -657,30 +579,12 @@ function createGlobImportPlugin(options = {}) {
657
579
  if (!enabled) return { name: "glob-import-disabled" };
658
580
  return {
659
581
  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;
582
+ transform: async (code, id, _meta) => {
583
+ return transformGlobImportCode(code, id, {
584
+ patterns,
585
+ asUrls,
586
+ eager
587
+ });
684
588
  }
685
589
  };
686
590
  }
@@ -753,33 +657,54 @@ function parseGlobOptions(optionsStr) {
753
657
  if (asMatch) options.as = asMatch[1];
754
658
  return options;
755
659
  }
756
-
757
- //#endregion
758
- //#region src/features/hash.ts
759
660
  /**
760
- * Generate content hash for filename
661
+ * Check if code contains glob imports
761
662
  */
762
- function generateContentHash(content, length = 8) {
763
- return createHash("sha256").update(content).digest("hex").slice(0, length);
663
+ function hasGlobImports(code) {
664
+ return /import\.meta\.glob\s*\(/.test(code);
764
665
  }
666
+
667
+ //#endregion
668
+ //#region src/plugins/builtin/node-protocol.ts
765
669
  /**
766
- * Add hash to filename
670
+ * Rolldown plugin for Node.js protocol handling
767
671
  */
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)}`;
672
+ function nodeProtocolPlugin(nodeProtocol) {
673
+ if (!nodeProtocol) return { name: "node-protocol-noop" };
674
+ return {
675
+ name: "node-protocol",
676
+ renderChunk(code) {
677
+ return {
678
+ code: transformNodeProtocol(code, nodeProtocol),
679
+ map: null
680
+ };
681
+ }
682
+ };
773
683
  }
774
- /**
775
- * Check if filename already has hash
776
- */
777
- function hasHash(filename) {
778
- return /-[a-f0-9]{8}(?:\.|$)/.test(filename);
684
+
685
+ //#endregion
686
+ //#region src/plugins/builtin/shebang.ts
687
+ const SHEBANG_RE = /^#![^\n]*/;
688
+ function shebangPlugin() {
689
+ return {
690
+ name: "robuild-shebang",
691
+ async writeBundle(options, bundle) {
692
+ for (const [fileName, output] of Object.entries(bundle)) {
693
+ if (output.type !== "chunk") continue;
694
+ if (hasShebang(output.code)) await makeExecutable(resolve(options.dir, fileName));
695
+ }
696
+ }
697
+ };
698
+ }
699
+ function hasShebang(code) {
700
+ return SHEBANG_RE.test(code);
701
+ }
702
+ async function makeExecutable(filePath) {
703
+ await promises.chmod(filePath, 493).catch(() => {});
779
704
  }
780
705
 
781
706
  //#endregion
782
- //#region src/features/shims.ts
707
+ //#region src/plugins/builtin/shims.ts
783
708
  /**
784
709
  * Default shims configuration
785
710
  */
@@ -893,134 +818,155 @@ function createShimsPlugin(config = true) {
893
818
  }
894
819
  };
895
820
  }
896
-
897
- //#endregion
898
- //#region src/features/node-protocol.ts
899
821
  /**
900
- * Node.js built-in modules that support the node: protocol
822
+ * Create browser-specific shims plugin
901
823
  */
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
- ]);
824
+ function createBrowserShimsPlugin() {
825
+ return {
826
+ name: "browser-shims",
827
+ transform: async (code, id) => {
828
+ if (!/\.(?:js|mjs|jsx|tsx?)$/.test(id)) return null;
829
+ if (detectShimNeeds(code).needsEnv) return `${PROCESS_ENV_SHIM}\n${code}`;
830
+ return null;
831
+ }
832
+ };
833
+ }
946
834
  /**
947
- * Check if a module is a Node.js built-in module
835
+ * Create Node.js-specific shims plugin
948
836
  */
949
- function isNodeBuiltin(id) {
950
- const cleanId = id.startsWith("node:") ? id.slice(5) : id;
951
- return NODE_BUILTIN_MODULES.has(cleanId);
837
+ function createNodeShimsPlugin() {
838
+ return {
839
+ name: "node-shims",
840
+ transform: async (code, id) => {
841
+ if (!/\.mjs$/.test(id) && !/\.js$/.test(id)) return null;
842
+ const needs = detectShimNeeds(code);
843
+ const shims = [];
844
+ if (needs.needsDirname || needs.needsRequire) shims.push(NODE_GLOBALS_SHIM);
845
+ if (needs.needsExports) shims.push(MODULE_EXPORTS_SHIM);
846
+ if (shims.length === 0) return null;
847
+ return `${shims.join("\n")}\n${code}`;
848
+ }
849
+ };
952
850
  }
851
+
852
+ //#endregion
853
+ //#region src/plugins/builtin/skip-node-modules.ts
953
854
  /**
954
- * Add node: prefix to built-in modules
855
+ * Create skip node_modules plugin
955
856
  */
956
- function addNodeProtocol(id) {
957
- if (id.startsWith("node:")) return id;
958
- if (isNodeBuiltin(id)) return `node:${id}`;
959
- return id;
857
+ function createSkipNodeModulesPlugin(options) {
858
+ const noExternalPatterns = options?.noExternal || [];
859
+ const shouldInline = (id) => {
860
+ for (const pattern of noExternalPatterns) if (typeof pattern === "string") {
861
+ if (id === pattern || id.startsWith(`${pattern}/`)) return true;
862
+ } else if (pattern instanceof RegExp) {
863
+ if (pattern.test(id)) return true;
864
+ }
865
+ return false;
866
+ };
867
+ return {
868
+ name: "skip-node-modules",
869
+ resolveId: async (id, importer) => {
870
+ if (shouldInline(id)) return null;
871
+ if (!importer) return null;
872
+ if (id.includes("node_modules") || !id.startsWith(".") && !id.startsWith("/") && !id.startsWith("\\")) return {
873
+ id,
874
+ external: true
875
+ };
876
+ return null;
877
+ }
878
+ };
960
879
  }
880
+
881
+ //#endregion
882
+ //#region src/transforms/banner.ts
961
883
  /**
962
- * Remove node: prefix from modules
884
+ * Resolve banner/footer addon for specific format
963
885
  */
964
- function stripNodeProtocol(id) {
965
- if (id.startsWith("node:")) return id.slice(5);
966
- return id;
886
+ function resolveChunkAddon(addon, format) {
887
+ if (!addon) return;
888
+ if (typeof addon === "string") return addon;
889
+ return addon[format === "es" ? "js" : format] || addon.js;
967
890
  }
968
891
  /**
969
- * Process module ID based on nodeProtocol setting
892
+ * Add banner to content
970
893
  */
971
- function processNodeProtocol(id, nodeProtocol) {
972
- if (nodeProtocol === "strip") return stripNodeProtocol(id);
973
- if (nodeProtocol === true) return addNodeProtocol(id);
974
- return id;
894
+ function addBanner(content, banner) {
895
+ if (!banner) return content;
896
+ return `${banner}\n${content}`;
975
897
  }
976
898
  /**
977
- * Transform import/export statements to handle node protocol
899
+ * Add footer to content
978
900
  */
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
- });
901
+ function addFooter(content, footer) {
902
+ if (!footer) return content;
903
+ return `${content}\n${footer}`;
904
+ }
905
+ /**
906
+ * Add both banner and footer to content
907
+ */
908
+ function addBannerFooter(content, banner, footer) {
909
+ let result = content;
910
+ result = addBanner(result, banner);
911
+ result = addFooter(result, footer);
912
+ return result;
985
913
  }
986
914
 
987
915
  //#endregion
988
- //#region src/plugins/node-protocol.ts
916
+ //#region src/transforms/clean.ts
989
917
  /**
990
- * Rolldown plugin for Node.js protocol handling
918
+ * Clean output directory or specific paths.
919
+ * Used by both bundle and transform builders.
920
+ *
921
+ * @param projectRoot - The project root directory
922
+ * @param outDir - The output directory to clean
923
+ * @param cleanPaths - true to clean outDir, or array of specific paths to clean
991
924
  */
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
- };
925
+ async function cleanOutputDir(projectRoot, outDir, cleanPaths) {
926
+ if (!cleanPaths) return;
927
+ if (cleanPaths === true) {
928
+ if (existsSync(outDir)) {
929
+ logger.log(colors.dim(`Cleaning ${fmtPath(outDir)}`));
930
+ await rm(outDir, {
931
+ recursive: true,
932
+ force: true
933
+ });
1001
934
  }
1002
- };
935
+ } else if (Array.isArray(cleanPaths)) for (const path of cleanPaths) {
936
+ const fullPath = resolve(projectRoot, path);
937
+ if (existsSync(fullPath)) {
938
+ logger.log(colors.dim(`Cleaning ${fmtPath(fullPath)}`));
939
+ await rm(fullPath, {
940
+ recursive: true,
941
+ force: true
942
+ });
943
+ }
944
+ }
1003
945
  }
1004
946
 
1005
947
  //#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
- }
948
+ //#region src/transforms/copy.ts
949
+ /**
950
+ * Copy files to output directory
951
+ */
952
+ async function copyFiles(cwd, outDir, copyOptions) {
953
+ if (!copyOptions || copyOptions.length === 0) return;
954
+ logger.verbose("Copying files...");
955
+ await Promise.all(copyOptions.map(async (entry) => {
956
+ const from = typeof entry === "string" ? entry : entry.from;
957
+ const to = typeof entry === "string" ? resolve(outDir, basename(from)) : resolve(cwd, entry.to);
958
+ const fromPath = resolve(cwd, from);
959
+ try {
960
+ await cp(fromPath, to, {
961
+ recursive: true,
962
+ force: true
963
+ });
964
+ logger.verbose(` ${from} → ${to}`);
965
+ } catch (error) {
966
+ logger.warn(`Failed to copy ${from} to ${to}:`, error);
1016
967
  }
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(() => {});
968
+ }));
969
+ logger.verbose("Files copied successfully");
1024
970
  }
1025
971
 
1026
972
  //#endregion
@@ -1253,6 +1199,110 @@ function normalizeBundleInputs(input, ctx) {
1253
1199
  return inputs;
1254
1200
  }
1255
1201
 
1202
+ //#endregion
1203
+ //#region src/builders/unbundle.ts
1204
+ /**
1205
+ * Unbundle mode: preserve file structure without bundling
1206
+ */
1207
+ async function unbundleTransform(ctx, entry) {
1208
+ await processDirectoryUnbundled(isAbsolute(entry.input) ? entry.input : join(ctx.pkgDir, entry.input), join(ctx.pkgDir, entry.outDir || "dist"), entry);
1209
+ }
1210
+ /**
1211
+ * Process directory in unbundle mode
1212
+ */
1213
+ async function processDirectoryUnbundled(inputDir, outputDir, entry) {
1214
+ const entries = await readdir(inputDir, { withFileTypes: true });
1215
+ for (const dirEntry of entries) {
1216
+ const inputPath = join(inputDir, dirEntry.name);
1217
+ const outputPath = join(outputDir, dirEntry.name);
1218
+ if (dirEntry.isDirectory()) {
1219
+ if (entry.skipNodeModules && dirEntry.name === "node_modules") continue;
1220
+ await mkdir(dirname(outputPath), { recursive: true });
1221
+ await processDirectoryUnbundled(inputPath, outputPath, entry);
1222
+ } else if (dirEntry.isFile()) await processFileUnbundled(inputPath, outputPath, entry);
1223
+ }
1224
+ }
1225
+ /**
1226
+ * Process individual file in unbundle mode
1227
+ */
1228
+ async function processFileUnbundled(inputPath, outputPath, entry) {
1229
+ const ext = extname(inputPath);
1230
+ if (![
1231
+ ".js",
1232
+ ".ts",
1233
+ ".jsx",
1234
+ ".tsx",
1235
+ ".mjs",
1236
+ ".mts",
1237
+ ".cjs",
1238
+ ".cts"
1239
+ ].includes(ext)) return;
1240
+ try {
1241
+ const transformedContent = transformImportsForUnbundle(await readFile(inputPath, "utf-8"), inputPath, entry);
1242
+ const outputExt = getUnbundleOutputExtension(ext, entry);
1243
+ const finalOutputPath = outputPath.replace(ext, outputExt);
1244
+ await mkdir(dirname(finalOutputPath), { recursive: true });
1245
+ await writeFile(finalOutputPath, transformedContent, "utf-8");
1246
+ } catch (error) {
1247
+ logger.warn(`Failed to process file ${inputPath}:`, error);
1248
+ }
1249
+ }
1250
+ /**
1251
+ * Transform imports for unbundle mode
1252
+ */
1253
+ function transformImportsForUnbundle(content, _filePath, entry) {
1254
+ let transformedContent = content;
1255
+ transformedContent = transformedContent.replace(/from\s+['"]([^'"]+)['"]/g, (match, importPath) => {
1256
+ if (importPath.startsWith(".")) {
1257
+ const newImportPath = updateImportExtension(importPath, entry);
1258
+ return match.replace(importPath, newImportPath);
1259
+ }
1260
+ return match;
1261
+ });
1262
+ transformedContent = transformedContent.replace(/require\s*\(\s*['"]([^'"]+)['"]\s*\)/g, (match, importPath) => {
1263
+ if (importPath.startsWith(".")) {
1264
+ const newImportPath = updateImportExtension(importPath, entry);
1265
+ return match.replace(importPath, newImportPath);
1266
+ }
1267
+ return match;
1268
+ });
1269
+ return transformedContent;
1270
+ }
1271
+ /**
1272
+ * Update import extension for unbundle mode
1273
+ */
1274
+ function updateImportExtension(importPath, entry) {
1275
+ const ext = extname(importPath);
1276
+ if (!ext) return `${importPath}.js`;
1277
+ if ([
1278
+ ".ts",
1279
+ ".tsx",
1280
+ ".mts",
1281
+ ".cts"
1282
+ ].includes(ext)) {
1283
+ const newExt = getUnbundleOutputExtension(ext, entry);
1284
+ return importPath.replace(ext, newExt);
1285
+ }
1286
+ return importPath;
1287
+ }
1288
+ /**
1289
+ * Get output extension for unbundle mode
1290
+ */
1291
+ function getUnbundleOutputExtension(inputExt, entry) {
1292
+ const format = Array.isArray(entry.format) ? entry.format[0] : entry.format || "es";
1293
+ switch (inputExt) {
1294
+ case ".ts":
1295
+ case ".tsx": return format === "cjs" ? ".cjs" : ".mjs";
1296
+ case ".mts": return ".mjs";
1297
+ case ".cts": return ".cjs";
1298
+ case ".js":
1299
+ case ".jsx": return format === "cjs" ? ".cjs" : ".mjs";
1300
+ case ".mjs": return ".mjs";
1301
+ case ".cjs": return ".cjs";
1302
+ default: return ".js";
1303
+ }
1304
+ }
1305
+
1256
1306
  //#endregion
1257
1307
  //#region src/builders/transform.ts
1258
1308
  /**
@@ -1415,44 +1465,7 @@ async function transformModule(entryPath, entry) {
1415
1465
  }
1416
1466
 
1417
1467
  //#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
1468
+ //#region src/config/vite-config.ts
1456
1469
  /**
1457
1470
  * Load Vite configuration and convert to robuild config
1458
1471
  */
@@ -1562,13 +1575,50 @@ function convertExternal(external) {
1562
1575
  return external;
1563
1576
  }
1564
1577
 
1578
+ //#endregion
1579
+ //#region src/transforms/on-success.ts
1580
+ const execAsync = promisify(exec);
1581
+ /**
1582
+ * Execute onSuccess callback after successful build
1583
+ */
1584
+ async function executeOnSuccess(onSuccess, result, cwd) {
1585
+ if (!onSuccess) return;
1586
+ try {
1587
+ if (typeof onSuccess === "string") {
1588
+ logger.verbose(`Executing onSuccess command: ${onSuccess}`);
1589
+ const { stdout, stderr } = await execAsync(onSuccess, { cwd });
1590
+ if (stdout) logger.verbose(`onSuccess stdout: ${stdout.trim()}`);
1591
+ if (stderr) logger.warn(`onSuccess stderr: ${stderr.trim()}`);
1592
+ } else {
1593
+ logger.verbose("Executing onSuccess callback function");
1594
+ await onSuccess(result);
1595
+ }
1596
+ logger.verbose("onSuccess callback completed successfully");
1597
+ } catch (error) {
1598
+ logger.error("onSuccess callback failed:", error);
1599
+ throw error;
1600
+ }
1601
+ }
1602
+ /**
1603
+ * Create build result object
1604
+ */
1605
+ function createBuildResult(entries, startTime) {
1606
+ return {
1607
+ entries: entries.map((entry) => ({
1608
+ ...entry,
1609
+ format: entry.format
1610
+ })),
1611
+ duration: Date.now() - startTime
1612
+ };
1613
+ }
1614
+
1565
1615
  //#endregion
1566
1616
  //#region src/watch.ts
1567
1617
  /**
1568
1618
  * Perform watch build using rolldown's built-in watch mode
1569
1619
  */
1570
1620
  async function performWatchBuild(config, ctx, startTime) {
1571
- const { performBuild } = await import("./build-B-lzI2ff.mjs");
1621
+ const { performBuild } = await import("./build-BKisdK3B.mjs");
1572
1622
  await performBuild(config, ctx, startTime);
1573
1623
  const bundleEntries = (config.entries || []).filter((entry) => {
1574
1624
  if (typeof entry === "string") return !entry.endsWith("/");
@@ -1589,7 +1639,7 @@ async function performWatchBuild(config, ctx, startTime) {
1589
1639
  */
1590
1640
  async function startRolldownWatch(config, ctx, bundleEntries) {
1591
1641
  logger.info("Watching for changes...");
1592
- const { RobuildPluginManager } = await import("./plugin-manager-pCQvlo7q.mjs");
1642
+ const { RobuildPluginManager } = await import("./manager-CnmjrU85.mjs");
1593
1643
  const watchConfigs = [];
1594
1644
  for (const rawEntry of bundleEntries) {
1595
1645
  const entry = typeof rawEntry === "string" ? parseEntryString(rawEntry) : rawEntry;
@@ -1684,7 +1734,8 @@ const SHARED_CONFIG_FIELDS = [
1684
1734
  "footer",
1685
1735
  "shims",
1686
1736
  "rolldown",
1687
- "loaders"
1737
+ "loaders",
1738
+ "clean"
1688
1739
  ];
1689
1740
  /**
1690
1741
  * Inherit configuration from parent config to entry
@@ -1786,4 +1837,4 @@ async function readJSON(specifier) {
1786
1837
  }
1787
1838
 
1788
1839
  //#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 };
1840
+ 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 };