robuild 0.0.15 → 0.0.17

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.
@@ -0,0 +1,4 @@
1
+ import { build, performBuild } from "./build-omZA_xD-.mjs";
2
+ import "./plugin-manager-w5yRGJRn.mjs";
3
+
4
+ export { performBuild };
@@ -1,3 +1,4 @@
1
+ import { RobuildPluginManager } from "./plugin-manager-w5yRGJRn.mjs";
1
2
  import { builtinModules } from "node:module";
2
3
  import { basename, dirname, extname, isAbsolute, join, relative, resolve } from "node:path";
3
4
  import { fileURLToPath, pathToFileURL } from "node:url";
@@ -138,7 +139,7 @@ function updateImportExtension(importPath, entry) {
138
139
  * Get output extension for unbundle mode
139
140
  */
140
141
  function getUnbundleOutputExtension(inputExt, entry) {
141
- const format = Array.isArray(entry.format) ? entry.format[0] : entry.format || "esm";
142
+ const format = Array.isArray(entry.format) ? entry.format[0] : entry.format || "es";
142
143
  switch (inputExt) {
143
144
  case ".ts":
144
145
  case ".tsx": return format === "cjs" ? ".cjs" : ".mjs";
@@ -160,7 +161,7 @@ function getUnbundleOutputExtension(inputExt, entry) {
160
161
  function resolveChunkAddon(addon, format) {
161
162
  if (!addon) return void 0;
162
163
  if (typeof addon === "string") return addon;
163
- const formatKey = format === "esm" ? "js" : format;
164
+ const formatKey = format === "es" ? "js" : format;
164
165
  return addon[formatKey] || addon.js;
165
166
  }
166
167
  /**
@@ -346,340 +347,6 @@ function hasHash(filename) {
346
347
  return /-[a-f0-9]{8}(?:\.|$)/.test(filename);
347
348
  }
348
349
 
349
- //#endregion
350
- //#region src/features/loaders.ts
351
- /**
352
- * Default loader mappings for common file extensions
353
- */
354
- const DEFAULT_LOADERS = {
355
- ".js": "js",
356
- ".mjs": "js",
357
- ".cjs": "js",
358
- ".jsx": "jsx",
359
- ".ts": "ts",
360
- ".mts": "ts",
361
- ".cts": "ts",
362
- ".tsx": "tsx",
363
- ".json": "json",
364
- ".css": "css",
365
- ".scss": "css",
366
- ".sass": "css",
367
- ".less": "css",
368
- ".styl": "css",
369
- ".txt": "text",
370
- ".md": "text",
371
- ".html": "text",
372
- ".xml": "text",
373
- ".svg": "text",
374
- ".png": "file",
375
- ".jpg": "file",
376
- ".jpeg": "file",
377
- ".gif": "file",
378
- ".webp": "file",
379
- ".ico": "file",
380
- ".woff": "file",
381
- ".woff2": "file",
382
- ".ttf": "file",
383
- ".eot": "file",
384
- ".mp4": "file",
385
- ".webm": "file",
386
- ".wav": "file",
387
- ".mp3": "file",
388
- ".flac": "file",
389
- ".aac": "file",
390
- ".zip": "binary",
391
- ".tar": "binary",
392
- ".gz": "binary",
393
- ".br": "binary"
394
- };
395
- /**
396
- * Get loader type for a file based on its extension
397
- */
398
- function getLoaderForFile(filePath, loaders) {
399
- const ext = extname(filePath).toLowerCase();
400
- if (loaders?.[ext]) return loaders[ext].loader;
401
- return DEFAULT_LOADERS[ext] || "file";
402
- }
403
- /**
404
- * Transform file content based on loader type
405
- */
406
- async function transformWithLoader(filePath, content, loader, options) {
407
- switch (loader) {
408
- case "js":
409
- case "jsx":
410
- case "ts":
411
- case "tsx": return content;
412
- case "json": try {
413
- const parsed = JSON.parse(content);
414
- return `export default ${JSON.stringify(parsed)}`;
415
- } catch {
416
- return `export default ${JSON.stringify(content)}`;
417
- }
418
- case "css": return transformCssContent(content, options);
419
- case "text": return `export default ${JSON.stringify(content)}`;
420
- case "file": return transformFileContent(filePath, options);
421
- case "dataurl": return transformDataUrlContent(filePath, content, options);
422
- case "binary": return transformBinaryContent(filePath, options);
423
- case "empty": return "export default {}";
424
- default: throw new Error(`Unknown loader type: ${loader}`);
425
- }
426
- }
427
- /**
428
- * Transform CSS content
429
- */
430
- function transformCssContent(content, options) {
431
- if (options?.modules) {
432
- const classNames = extractCssClassNames(content);
433
- const moduleExports = classNames.reduce((acc, className) => {
434
- acc[className] = className;
435
- return acc;
436
- }, {});
437
- return `export default ${JSON.stringify(moduleExports)}`;
438
- }
439
- return `export default ${JSON.stringify(content)}`;
440
- }
441
- /**
442
- * Transform file content to URL
443
- */
444
- function transformFileContent(filePath, options) {
445
- const publicPath = options?.publicPath || "/";
446
- const fileName = filePath.split("/").pop() || "file";
447
- const url = `${publicPath}${fileName}`;
448
- return `export default ${JSON.stringify(url)}`;
449
- }
450
- /**
451
- * Transform file content to data URL
452
- */
453
- function transformDataUrlContent(filePath, content, _options) {
454
- const ext = extname(filePath).toLowerCase();
455
- const mimeType = getMimeType(ext);
456
- const base64 = Buffer.from(content).toString("base64");
457
- const dataUrl = `data:${mimeType};base64,${base64}`;
458
- return `export default ${JSON.stringify(dataUrl)}`;
459
- }
460
- /**
461
- * Transform binary file content
462
- */
463
- function transformBinaryContent(filePath, _options) {
464
- const fileName = filePath.split("/").pop() || "binary";
465
- return `export default ${JSON.stringify(fileName)}`;
466
- }
467
- /**
468
- * Extract CSS class names (simplified implementation)
469
- */
470
- function extractCssClassNames(content) {
471
- const classRegex = /\.([a-z_-][\w-]*)/gi;
472
- const matches = content.match(classRegex) || [];
473
- return Array.from(new Set(matches.map((match) => match.slice(1))));
474
- }
475
- /**
476
- * Get MIME type for file extension
477
- */
478
- function getMimeType(ext) {
479
- const mimeTypes = {
480
- ".png": "image/png",
481
- ".jpg": "image/jpeg",
482
- ".jpeg": "image/jpeg",
483
- ".gif": "image/gif",
484
- ".webp": "image/webp",
485
- ".svg": "image/svg+xml",
486
- ".ico": "image/x-icon",
487
- ".woff": "font/woff",
488
- ".woff2": "font/woff2",
489
- ".ttf": "font/ttf",
490
- ".eot": "application/vnd.ms-fontobject",
491
- ".mp4": "video/mp4",
492
- ".webm": "video/webm",
493
- ".wav": "audio/wav",
494
- ".mp3": "audio/mpeg",
495
- ".flac": "audio/flac",
496
- ".aac": "audio/aac",
497
- ".txt": "text/plain",
498
- ".md": "text/markdown",
499
- ".html": "text/html",
500
- ".xml": "application/xml",
501
- ".css": "text/css",
502
- ".js": "application/javascript",
503
- ".json": "application/json"
504
- };
505
- return mimeTypes[ext] || "application/octet-stream";
506
- }
507
- /**
508
- * Create a loader plugin for robuild
509
- */
510
- function createLoaderPlugin(loaders) {
511
- return {
512
- name: "loaders",
513
- load: async (id) => {
514
- const ext = extname(id);
515
- const loader = getLoaderForFile(id, loaders);
516
- if (loader === "js" || loader === "jsx" || loader === "ts" || loader === "tsx") return null;
517
- if (loader === "json" && !loaders?.[ext]) return null;
518
- try {
519
- const content = await readFile(id, "utf-8");
520
- const options = loaders?.[ext]?.options;
521
- return await transformWithLoader(id, content, loader, options);
522
- } catch {
523
- return null;
524
- }
525
- }
526
- };
527
- }
528
-
529
- //#endregion
530
- //#region src/features/plugin-manager.ts
531
- /**
532
- * Simplified plugin manager that leverages rolldown's plugin system
533
- */
534
- var RobuildPluginManager = class {
535
- plugins = [];
536
- context;
537
- constructor(config, entry, pkgDir) {
538
- this.context = {
539
- config,
540
- entry,
541
- pkgDir,
542
- outDir: entry.outDir || "dist",
543
- format: entry.format || "esm",
544
- platform: entry.platform || "node",
545
- target: entry.target || "es2022"
546
- };
547
- this.plugins = this.normalizePlugins(config.plugins || []);
548
- }
549
- /**
550
- * Normalize plugin options to RobuildPlugin instances
551
- */
552
- normalizePlugins(pluginOptions) {
553
- return pluginOptions.map((pluginOption) => this.normalizePlugin(pluginOption));
554
- }
555
- /**
556
- * Normalize a single plugin option
557
- */
558
- normalizePlugin(pluginOption) {
559
- if (typeof pluginOption === "function") return this.normalizePlugin(pluginOption());
560
- if (typeof pluginOption === "object" && pluginOption !== null) {
561
- if (this.isRobuildPlugin(pluginOption)) return pluginOption;
562
- if (this.isRolldownPlugin(pluginOption)) return this.adaptRolldownPlugin(pluginOption);
563
- if (this.isVitePlugin(pluginOption)) return this.adaptVitePlugin(pluginOption);
564
- if (this.isUnplugin(pluginOption)) return this.adaptUnplugin(pluginOption);
565
- return this.adaptRolldownPlugin(pluginOption);
566
- }
567
- throw new Error(`Invalid plugin option: ${typeof pluginOption}`);
568
- }
569
- /**
570
- * Check if plugin is already a RobuildPlugin
571
- */
572
- isRobuildPlugin(plugin) {
573
- return plugin.meta?.robuild === true || plugin.robuildSetup || plugin.robuildBuildStart || plugin.robuildBuildEnd;
574
- }
575
- /**
576
- * Check if plugin is a rolldown/rollup plugin
577
- */
578
- isRolldownPlugin(plugin) {
579
- return plugin.name && (plugin.buildStart || plugin.buildEnd || plugin.resolveId || plugin.load || plugin.transform || plugin.generateBundle || plugin.writeBundle);
580
- }
581
- /**
582
- * Check if plugin is a Vite plugin
583
- */
584
- isVitePlugin(plugin) {
585
- return plugin.config || plugin.configResolved || plugin.configureServer || plugin.meta?.vite === true;
586
- }
587
- /**
588
- * Check if plugin is an Unplugin
589
- */
590
- isUnplugin(plugin) {
591
- return plugin.unplugin === true || plugin.meta?.unplugin === true;
592
- }
593
- /**
594
- * Adapt rolldown plugin to RobuildPlugin
595
- */
596
- adaptRolldownPlugin(plugin) {
597
- return {
598
- ...plugin,
599
- meta: {
600
- ...plugin.meta,
601
- framework: "rolldown",
602
- robuild: true,
603
- rollup: true
604
- }
605
- };
606
- }
607
- /**
608
- * Adapt Vite plugin to RobuildPlugin
609
- */
610
- adaptVitePlugin(plugin) {
611
- return {
612
- ...plugin,
613
- meta: {
614
- ...plugin.meta,
615
- framework: "vite",
616
- robuild: true,
617
- vite: true
618
- }
619
- };
620
- }
621
- /**
622
- * Adapt Unplugin to RobuildPlugin
623
- */
624
- adaptUnplugin(plugin) {
625
- return {
626
- ...plugin,
627
- meta: {
628
- ...plugin.meta,
629
- framework: "unplugin",
630
- robuild: true,
631
- unplugin: true,
632
- rollup: true,
633
- vite: true,
634
- webpack: true,
635
- esbuild: true
636
- }
637
- };
638
- }
639
- /**
640
- * Initialize robuild-specific plugin hooks
641
- */
642
- async initializeRobuildHooks() {
643
- for (const plugin of this.plugins) if (plugin.robuildSetup) await plugin.robuildSetup(this.context);
644
- }
645
- /**
646
- * Execute robuild buildStart hooks
647
- */
648
- async executeRobuildBuildStart() {
649
- for (const plugin of this.plugins) if (plugin.robuildBuildStart) await plugin.robuildBuildStart(this.context);
650
- }
651
- /**
652
- * Execute robuild buildEnd hooks
653
- */
654
- async executeRobuildBuildEnd(result) {
655
- for (const plugin of this.plugins) if (plugin.robuildBuildEnd) await plugin.robuildBuildEnd(this.context, result);
656
- }
657
- /**
658
- * Get rolldown-compatible plugins for direct use
659
- */
660
- getRolldownPlugins() {
661
- return this.plugins.map((plugin) => {
662
- const { robuildSetup, robuildBuildStart, robuildBuildEnd,...rolldownPlugin } = plugin;
663
- return rolldownPlugin;
664
- });
665
- }
666
- /**
667
- * Get all plugins
668
- */
669
- getPlugins() {
670
- return this.plugins;
671
- }
672
- /**
673
- * Update context (useful when build parameters change)
674
- */
675
- updateContext(updates) {
676
- this.context = {
677
- ...this.context,
678
- ...updates
679
- };
680
- }
681
- };
682
-
683
350
  //#endregion
684
351
  //#region src/features/shims.ts
685
352
  /**
@@ -944,9 +611,9 @@ function analyzeDir(dir) {
944
611
  let totalSize$1 = 0;
945
612
  let totalFiles = 0;
946
613
  for (const d of dir) {
947
- const { size, files: files$1 } = analyzeDir(d);
614
+ const { size, files } = analyzeDir(d);
948
615
  totalSize$1 += size;
949
- totalFiles += files$1;
616
+ totalFiles += files;
950
617
  }
951
618
  return {
952
619
  size: totalSize$1,
@@ -954,21 +621,29 @@ function analyzeDir(dir) {
954
621
  };
955
622
  }
956
623
  let totalSize = 0;
957
- const files = readdirSync(dir, {
958
- withFileTypes: true,
959
- recursive: true
960
- });
961
- for (const file of files) {
962
- const fullPath = join(file.parentPath, file.name);
963
- if (file.isFile()) {
964
- const { size } = statSync(fullPath);
965
- totalSize += size;
624
+ try {
625
+ const files = readdirSync(dir, {
626
+ withFileTypes: true,
627
+ recursive: true
628
+ });
629
+ for (const file of files) {
630
+ const fullPath = join(file.parentPath, file.name);
631
+ if (file.isFile()) {
632
+ const { size } = statSync(fullPath);
633
+ totalSize += size;
634
+ }
966
635
  }
636
+ return {
637
+ size: totalSize,
638
+ files: files.length
639
+ };
640
+ } catch (error) {
641
+ if (error.code === "ENOENT" || error.code === "ENOTDIR") return {
642
+ size: 0,
643
+ files: 0
644
+ };
645
+ throw error;
967
646
  }
968
- return {
969
- size: totalSize,
970
- files: files.length
971
- };
972
647
  }
973
648
  async function distSize(dir, entry) {
974
649
  const build$1 = await rolldown({
@@ -979,7 +654,7 @@ async function distSize(dir, entry) {
979
654
  });
980
655
  const { output } = await build$1.generate({ inlineDynamicImports: true });
981
656
  const code = output[0].code;
982
- const { code: minified } = minify(entry, code);
657
+ const { code: minified } = await minify(entry, code);
983
658
  return {
984
659
  size: Buffer.byteLength(code),
985
660
  minSize: Buffer.byteLength(minified),
@@ -1019,25 +694,16 @@ async function sideEffectSize(dir, entry) {
1019
694
  //#endregion
1020
695
  //#region src/builders/bundle.ts
1021
696
  /**
1022
- * Convert OutputFormat to Rolldown ModuleFormat
1023
- */
1024
- function formatToRolldownFormat(format) {
1025
- switch (format) {
1026
- case "esm": return "es";
1027
- case "cjs": return "cjs";
1028
- case "iife": return "iife";
1029
- case "umd": return "umd";
1030
- default: return "es";
1031
- }
1032
- }
1033
- /**
1034
697
  * Get file extension for format
1035
698
  */
1036
699
  function getFormatExtension(format, platform, fixedExtension = false) {
1037
700
  if (fixedExtension) return format === "cjs" ? ".cjs" : ".mjs";
1038
701
  switch (format) {
1039
- case "esm": return ".mjs";
1040
- case "cjs": return platform === "node" ? ".cjs" : ".js";
702
+ case "es":
703
+ case "esm":
704
+ case "module": return ".mjs";
705
+ case "cjs":
706
+ case "commonjs": return platform === "node" ? ".cjs" : ".js";
1041
707
  case "iife":
1042
708
  case "umd": return ".js";
1043
709
  default: return ".js";
@@ -1075,7 +741,7 @@ async function rolldownBuild(ctx, entry, hooks, config) {
1075
741
  const inputs = normalizeBundleInputs(entryInput, ctx);
1076
742
  const pluginManager = new RobuildPluginManager(config || {}, entry, ctx.pkgDir);
1077
743
  await pluginManager.initializeRobuildHooks();
1078
- const formats = Array.isArray(entry.format) ? entry.format : [entry.format || "esm"];
744
+ const formats = Array.isArray(entry.format) ? entry.format : [entry.format || "es"];
1079
745
  const platform = entry.platform || "node";
1080
746
  const target = entry.target || "es2022";
1081
747
  const outDir = entry.outDir || "dist";
@@ -1167,13 +833,6 @@ async function rolldownBuild(ctx, entry, hooks, config) {
1167
833
  }
1168
834
  });
1169
835
  }
1170
- if (entry.loaders) {
1171
- const loaderPlugin = createLoaderPlugin(entry.loaders);
1172
- if (loaderPlugin.load) rolldownPlugins.push({
1173
- name: "loaders",
1174
- load: loaderPlugin.load
1175
- });
1176
- }
1177
836
  if (entry.shims) {
1178
837
  const shimsPlugin = createShimsPlugin(entry.shims);
1179
838
  if (shimsPlugin.transform) rolldownPlugins.push({
@@ -1192,6 +851,8 @@ async function rolldownBuild(ctx, entry, hooks, config) {
1192
851
  });
1193
852
  }
1194
853
  rolldownPlugins.push(...pluginManager.getRolldownPlugins());
854
+ const moduleTypes = {};
855
+ if (entry.loaders) for (const [ext, config$1] of Object.entries(entry.loaders)) moduleTypes[ext] = config$1.loader;
1195
856
  const robuildGeneratedConfig = {
1196
857
  cwd: ctx.pkgDir,
1197
858
  input: inputs,
@@ -1200,7 +861,8 @@ async function rolldownBuild(ctx, entry, hooks, config) {
1200
861
  external: typeof entry.external === "function" ? entry.external : externalDeps,
1201
862
  define: defineOptions,
1202
863
  resolve: { alias: entry.alias || {} },
1203
- transform: { target }
864
+ transform: { target },
865
+ ...Object.keys(moduleTypes).length > 0 ? { moduleTypes } : {}
1204
866
  };
1205
867
  if (entry.treeshake !== void 0) if (typeof entry.treeshake === "boolean") robuildGeneratedConfig.treeshake = entry.treeshake;
1206
868
  else robuildGeneratedConfig.treeshake = entry.treeshake;
@@ -1214,31 +876,23 @@ async function rolldownBuild(ctx, entry, hooks, config) {
1214
876
  const allOutputEntries = [];
1215
877
  const filePathMap = /* @__PURE__ */ new Map();
1216
878
  for (const format of formats) {
1217
- const rolldownFormat = formatToRolldownFormat(format);
1218
879
  const extension = getFormatExtension(format, platform, entry.fixedExtension);
1219
880
  const formatConfig = { ...baseRolldownConfig };
1220
- if (entry.dts !== false && format === "esm") {
881
+ if (entry.dts !== false && (format === "es" || format === "esm" || format === "module")) {
1221
882
  const dtsPlugins = dts({ ...entry.dts });
1222
883
  formatConfig.plugins = [...Array.isArray(formatConfig.plugins) ? formatConfig.plugins : [formatConfig.plugins], ...Array.isArray(dtsPlugins) ? dtsPlugins : [dtsPlugins]];
1223
884
  }
1224
885
  const res = await rolldown(formatConfig);
1225
- let formatOutDir = fullOutDir;
886
+ const formatOutDir = fullOutDir;
1226
887
  let entryFileName = `[name]${extension}`;
1227
888
  if (isMultiFormat) {
1228
- if (format === "cjs") {
1229
- formatOutDir = join(fullOutDir, "cjs");
1230
- entryFileName = `[name].cjs`;
1231
- } else if (format === "iife" || format === "umd") {
1232
- formatOutDir = join(fullOutDir, platform === "browser" ? "browser" : format);
1233
- entryFileName = `[name].js`;
1234
- }
1235
- } else if ((format === "iife" || format === "umd") && platform === "browser") {
1236
- formatOutDir = join(fullOutDir, "browser");
1237
- entryFileName = `[name].js`;
889
+ if (format === "cjs" || format === "commonjs") entryFileName = `[name].cjs`;
890
+ else if (format === "es" || format === "esm" || format === "module") entryFileName = `[name].mjs`;
891
+ else if (format === "iife" || format === "umd") entryFileName = `[name].js`;
1238
892
  }
1239
893
  const robuildOutputConfig = {
1240
894
  dir: formatOutDir,
1241
- format: rolldownFormat,
895
+ format,
1242
896
  entryFileNames: entryFileName,
1243
897
  chunkFileNames: `_chunks/[name]-[hash]${extension}`,
1244
898
  minify: entry.minify,
@@ -1358,7 +1012,7 @@ function normalizeBundleInputs(input, ctx) {
1358
1012
  function resolveJsOutputExtension(format, platform = "node", fixedExtension = false) {
1359
1013
  if (fixedExtension) return format === "cjs" ? "cjs" : "mjs";
1360
1014
  switch (format) {
1361
- case "esm": return platform === "browser" ? "js" : "mjs";
1015
+ case "es": return platform === "browser" ? "js" : "mjs";
1362
1016
  case "cjs": return platform === "browser" ? "js" : "cjs";
1363
1017
  case "iife":
1364
1018
  case "umd": return "js";
@@ -1371,7 +1025,7 @@ function resolveJsOutputExtension(format, platform = "node", fixedExtension = fa
1371
1025
  function resolveDtsOutputExtension(format, fixedExtension = false) {
1372
1026
  if (fixedExtension) return format === "cjs" ? "d.cts" : "d.mts";
1373
1027
  switch (format) {
1374
- case "esm": return "d.mts";
1028
+ case "es": return "d.mts";
1375
1029
  case "cjs": return "d.cts";
1376
1030
  default: return "d.ts";
1377
1031
  }
@@ -1449,15 +1103,29 @@ async function transformDir(ctx, entry) {
1449
1103
  }
1450
1104
  const fullOutDir = resolve(ctx.pkgDir, entry.outDir);
1451
1105
  await cleanOutputDir(ctx.pkgDir, fullOutDir, entry.clean ?? true);
1106
+ const { statSync: statSync$1 } = await import("node:fs");
1107
+ let inputDir = entry.input;
1108
+ try {
1109
+ const stats = statSync$1(inputDir);
1110
+ if (stats.isFile()) {
1111
+ inputDir = dirname(inputDir);
1112
+ consola.warn(`Transform input should be a directory, not a file. Using directory: ${fmtPath(inputDir)}`);
1113
+ }
1114
+ } catch (error) {
1115
+ if (error.code !== "ENOENT") throw error;
1116
+ }
1452
1117
  const promises$1 = [];
1453
- for await (const entryName of await glob$1("**/*.*", { cwd: entry.input })) promises$1.push((async () => {
1454
- const entryPath = join(entry.input, entryName);
1118
+ const files = await glob$1("**/*.*", { cwd: inputDir });
1119
+ for await (const entryName of files) promises$1.push((async () => {
1120
+ const entryPath = join(inputDir, entryName);
1455
1121
  const ext = extname(entryPath);
1456
1122
  switch (ext) {
1457
- case ".ts": {
1123
+ case ".ts":
1124
+ case ".tsx":
1125
+ case ".jsx": {
1458
1126
  const transformed = await transformModule(entryPath, entry);
1459
- const baseName = entryName.replace(/\.ts$/, "");
1460
- const outputFileName = createFilename(baseName, "esm", false, {
1127
+ const baseName = entryName.replace(/\.(ts|tsx|jsx)$/, "");
1128
+ const outputFileName = createFilename(baseName, "es", false, {
1461
1129
  platform: entry.platform,
1462
1130
  fixedExtension: entry.fixedExtension,
1463
1131
  outExtensions: entry.outExtensions
@@ -1465,6 +1133,11 @@ async function transformDir(ctx, entry) {
1465
1133
  let entryDistPath = join(entry.outDir, outputFileName);
1466
1134
  await mkdir(dirname(entryDistPath), { recursive: true });
1467
1135
  await writeFile(entryDistPath, transformed.code, "utf8");
1136
+ if (entry.sourcemap && transformed.map) {
1137
+ const mapPath = `${entryDistPath}.map`;
1138
+ const mapContent = typeof transformed.map === "string" ? transformed.map : JSON.stringify(transformed.map);
1139
+ await writeFile(mapPath, mapContent, "utf8");
1140
+ }
1468
1141
  if (entry.hash && !hasHash(entryDistPath)) {
1469
1142
  const hashedPath = addHashToFilename(entryDistPath, transformed.code);
1470
1143
  const { rename } = await import("node:fs/promises");
@@ -1473,7 +1146,7 @@ async function transformDir(ctx, entry) {
1473
1146
  }
1474
1147
  if (SHEBANG_RE.test(transformed.code)) await makeExecutable(entryDistPath);
1475
1148
  if (transformed.declaration) {
1476
- const dtsFileName = createFilename(baseName, "esm", true, {
1149
+ const dtsFileName = createFilename(baseName, "es", true, {
1477
1150
  platform: entry.platform,
1478
1151
  fixedExtension: entry.fixedExtension,
1479
1152
  outExtensions: entry.outExtensions
@@ -1502,8 +1175,10 @@ async function transformDir(ctx, entry) {
1502
1175
  */
1503
1176
  async function transformModule(entryPath, entry) {
1504
1177
  let sourceText = await readFile(entryPath, "utf8");
1178
+ const ext = extname(entryPath);
1179
+ const lang = ext === ".tsx" || ext === ".jsx" ? "tsx" : "ts";
1505
1180
  const sourceOptions = {
1506
- lang: "ts",
1181
+ lang,
1507
1182
  sourceType: "module"
1508
1183
  };
1509
1184
  const parsed = parseSync(entryPath, sourceText, { ...sourceOptions });
@@ -1517,6 +1192,8 @@ async function transformModule(entryPath, entry) {
1517
1192
  from: pathToFileURL(entryPath),
1518
1193
  extensions: entry.resolve?.extensions ?? [
1519
1194
  ".ts",
1195
+ ".tsx",
1196
+ ".jsx",
1520
1197
  ".js",
1521
1198
  ".mjs",
1522
1199
  ".cjs",
@@ -1540,18 +1217,19 @@ async function transformModule(entryPath, entry) {
1540
1217
  if (updatedStarts.has(req.start)) return;
1541
1218
  updatedStarts.add(req.start);
1542
1219
  const resolvedAbsolute = resolveModulePath(moduleId, resolveOptions);
1543
- const newId = relative(dirname(entryPath), resolvedAbsolute.replace(/\.ts$/, ".mjs"));
1220
+ const newId = relative(dirname(entryPath), resolvedAbsolute.replace(/\.(ts|tsx|jsx)$/, ".mjs"));
1544
1221
  magicString.remove(req.start, req.end);
1545
1222
  magicString.prependLeft(req.start, JSON.stringify(newId.startsWith(".") ? newId : `./${newId}`));
1546
1223
  };
1547
1224
  for (const staticImport of parsed.module.staticImports) rewriteSpecifier(staticImport.moduleRequest);
1548
1225
  for (const staticExport of parsed.module.staticExports) for (const staticExportEntry of staticExport.entries) if (staticExportEntry.moduleRequest) rewriteSpecifier(staticExportEntry.moduleRequest);
1549
1226
  sourceText = magicString.toString();
1550
- const transformed = transform(entryPath, sourceText, {
1227
+ const transformed = await transform(entryPath, sourceText, {
1551
1228
  ...entry.oxc,
1552
1229
  ...sourceOptions,
1553
1230
  cwd: dirname(entryPath),
1554
1231
  target: entry.target || "es2022",
1232
+ sourcemap: !!entry.sourcemap,
1555
1233
  typescript: {
1556
1234
  declaration: { stripInternal: true },
1557
1235
  ...entry.oxc?.typescript
@@ -1565,12 +1243,12 @@ async function transformModule(entryPath, entry) {
1565
1243
  throw error;
1566
1244
  }
1567
1245
  if (entry.minify) {
1568
- const res = minify(entryPath, transformed.code, entry.minify === true ? {} : entry.minify);
1246
+ const res = await minify(entryPath, transformed.code, entry.minify === true ? {} : entry.minify);
1569
1247
  transformed.code = res.code;
1570
1248
  transformed.map = res.map;
1571
1249
  }
1572
- const banner = resolveChunkAddon(entry.banner, "esm");
1573
- const footer = resolveChunkAddon(entry.footer, "esm");
1250
+ const banner = resolveChunkAddon(entry.banner, "es");
1251
+ const footer = resolveChunkAddon(entry.footer, "es");
1574
1252
  transformed.code = addBannerFooter(transformed.code, banner, footer);
1575
1253
  if (entry.nodeProtocol) transformed.code = transformNodeProtocol(transformed.code, entry.nodeProtocol);
1576
1254
  return transformed;
@@ -1778,7 +1456,7 @@ function convertViteConfig(viteConfig) {
1778
1456
  function convertFormats(formats) {
1779
1457
  if (!formats) return void 0;
1780
1458
  const formatMap = {
1781
- es: "esm",
1459
+ es: "es",
1782
1460
  cjs: "cjs",
1783
1461
  umd: "umd",
1784
1462
  iife: "iife"
@@ -1819,13 +1497,13 @@ function normalizePath$1(path, resolveFrom) {
1819
1497
  * Perform watch build using rolldown's built-in watch mode
1820
1498
  */
1821
1499
  async function performWatchBuild(config, ctx, startTime) {
1822
- const { performBuild: performBuild$1 } = await import("./build-yfn0_Gzc.mjs");
1500
+ const { performBuild: performBuild$1 } = await import("./build-S2eglIZn.mjs");
1823
1501
  await performBuild$1(config, ctx, startTime);
1824
1502
  const bundleEntries = (config.entries || []).filter((entry) => {
1825
1503
  if (typeof entry === "string") return !entry.endsWith("/");
1826
1504
  return entry.type === "bundle";
1827
1505
  });
1828
- if (bundleEntries.length > 0) await startRolldownWatch(ctx, bundleEntries);
1506
+ if (bundleEntries.length > 0) await startRolldownWatch(config, ctx, bundleEntries);
1829
1507
  else {
1830
1508
  logger.warn("Transform-only watch mode not yet implemented with rolldown");
1831
1509
  return new Promise(() => {});
@@ -1833,9 +1511,14 @@ async function performWatchBuild(config, ctx, startTime) {
1833
1511
  }
1834
1512
  /**
1835
1513
  * Start rolldown watch mode for bundle entries
1514
+ *
1515
+ * Note: Watch mode currently uses simplified rolldown configuration.
1516
+ * For full feature parity with build mode, the initial build is performed first.
1517
+ * The watch mode then monitors for file changes and triggers rebuilds.
1836
1518
  */
1837
- async function startRolldownWatch(ctx, bundleEntries) {
1519
+ async function startRolldownWatch(config, ctx, bundleEntries) {
1838
1520
  logger.info("🚧 Using rolldown built-in watch mode...");
1521
+ const { RobuildPluginManager: RobuildPluginManager$1 } = await import("./plugin-manager-WN1-NA--.mjs");
1839
1522
  const watchConfigs = [];
1840
1523
  for (const rawEntry of bundleEntries) {
1841
1524
  let entry;
@@ -1847,13 +1530,55 @@ async function startRolldownWatch(ctx, bundleEntries) {
1847
1530
  outDir: outDir || "dist"
1848
1531
  };
1849
1532
  } else entry = rawEntry;
1850
- entry.input = Array.isArray(entry.input) ? entry.input.map((i) => normalizePath$1(i, ctx.pkgDir)) : normalizePath$1(entry.input, ctx.pkgDir);
1533
+ const entryInput = entry.input || entry.entry;
1534
+ if (!entryInput) {
1535
+ logger.warn("Skipping entry without input:", entry);
1536
+ continue;
1537
+ }
1538
+ let normalizedInput;
1539
+ if (typeof entryInput === "object" && !Array.isArray(entryInput)) {
1540
+ const normalizedObj = {};
1541
+ for (const [key, value] of Object.entries(entryInput)) normalizedObj[key] = normalizePath$1(value, ctx.pkgDir);
1542
+ normalizedInput = normalizedObj;
1543
+ } else if (Array.isArray(entryInput)) normalizedInput = entryInput.map((i) => normalizePath$1(i, ctx.pkgDir));
1544
+ else normalizedInput = normalizePath$1(entryInput, ctx.pkgDir);
1545
+ const target = entry.target || "es2022";
1546
+ const platform = entry.platform || "node";
1547
+ const format = entry.format || "es";
1548
+ const getExtension = (fmt) => {
1549
+ switch (fmt) {
1550
+ case "es": return ".mjs";
1551
+ case "cjs": return ".cjs";
1552
+ case "iife":
1553
+ case "umd": return ".js";
1554
+ default: return ".mjs";
1555
+ }
1556
+ };
1557
+ const extension = getExtension(Array.isArray(format) ? format[0] : format);
1558
+ const rolldownFormat = Array.isArray(format) ? format[0] : format;
1559
+ const formatMap = {
1560
+ esm: "es",
1561
+ cjs: "cjs",
1562
+ iife: "iife",
1563
+ umd: "umd"
1564
+ };
1565
+ let rolldownInput;
1566
+ if (Array.isArray(normalizedInput)) rolldownInput = normalizedInput[0];
1567
+ else if (typeof normalizedInput === "object") rolldownInput = normalizedInput;
1568
+ else rolldownInput = normalizedInput;
1569
+ const pluginManager = new RobuildPluginManager$1(config, entry, ctx.pkgDir);
1570
+ const rolldownPlugins = [...pluginManager.getRolldownPlugins(), ...entry.rolldown?.plugins || []];
1851
1571
  const watchConfig = {
1852
- input: Array.isArray(entry.input) ? entry.input[0] : entry.input,
1572
+ input: rolldownInput,
1853
1573
  output: {
1854
1574
  dir: entry.outDir,
1855
- format: "esm"
1856
- }
1575
+ format: formatMap[rolldownFormat] || "es",
1576
+ entryFileNames: `[name]${extension}`,
1577
+ sourcemap: entry.sourcemap
1578
+ },
1579
+ platform: platform === "node" ? "node" : "neutral",
1580
+ transform: { target },
1581
+ plugins: rolldownPlugins
1857
1582
  };
1858
1583
  watchConfigs.push(watchConfig);
1859
1584
  }
@@ -1890,34 +1615,51 @@ async function startRolldownWatch(ctx, bundleEntries) {
1890
1615
  //#endregion
1891
1616
  //#region src/build.ts
1892
1617
  /**
1618
+ * Shared configuration fields between BuildConfig and BuildEntry
1619
+ */
1620
+ const SHARED_CONFIG_FIELDS = [
1621
+ "format",
1622
+ "outDir",
1623
+ "platform",
1624
+ "target",
1625
+ "minify",
1626
+ "dts",
1627
+ "dtsOnly",
1628
+ "splitting",
1629
+ "treeshake",
1630
+ "sourcemap",
1631
+ "external",
1632
+ "noExternal",
1633
+ "env",
1634
+ "alias",
1635
+ "banner",
1636
+ "footer",
1637
+ "shims",
1638
+ "rolldown",
1639
+ "loaders"
1640
+ ];
1641
+ /**
1642
+ * Inherit configuration from parent config to entry
1643
+ * Only inherits fields that are not already set in the entry
1644
+ */
1645
+ function inheritConfig(entry, config, additionalMappings) {
1646
+ const result = { ...entry };
1647
+ for (const field of SHARED_CONFIG_FIELDS) if (result[field] === void 0 && config[field] !== void 0) result[field] = config[field];
1648
+ if (additionalMappings) {
1649
+ for (const [configKey, entryKey] of Object.entries(additionalMappings)) if (result[entryKey] === void 0 && config[configKey] !== void 0) result[entryKey] = config[configKey];
1650
+ }
1651
+ return result;
1652
+ }
1653
+ /**
1893
1654
  * Normalize tsup-style config to entries-based config
1894
1655
  */
1895
1656
  function normalizeTsupConfig(config) {
1896
1657
  if (config.entries && config.entries.length > 0) return config;
1897
1658
  if (config.entry) {
1898
- const entry = {
1659
+ const entry = inheritConfig({
1899
1660
  type: "bundle",
1900
- entry: config.entry,
1901
- format: config.format,
1902
- outDir: config.outDir,
1903
- platform: config.platform,
1904
- target: config.target,
1905
- globalName: config.name,
1906
- minify: config.minify,
1907
- dts: config.dts,
1908
- dtsOnly: config.dtsOnly,
1909
- splitting: config.splitting,
1910
- treeshake: config.treeshake,
1911
- sourcemap: config.sourcemap,
1912
- external: config.external,
1913
- noExternal: config.noExternal,
1914
- env: config.env,
1915
- alias: config.alias,
1916
- banner: config.banner,
1917
- footer: config.footer,
1918
- shims: config.shims,
1919
- rolldown: config.rolldown
1920
- };
1661
+ entry: config.entry
1662
+ }, config, { name: "globalName" });
1921
1663
  return {
1922
1664
  ...config,
1923
1665
  entries: [entry]
@@ -1977,17 +1719,23 @@ async function performBuild(config, ctx, startTime) {
1977
1719
  outDir
1978
1720
  };
1979
1721
  } else entry = rawEntry;
1722
+ if (entry.type === "bundle") entry = inheritConfig(entry, config);
1723
+ else if (entry.type === "transform") entry = inheritConfig(entry, config);
1980
1724
  const hasInput = entry.type === "transform" ? !!entry.input : !!(entry.input || entry.entry);
1981
1725
  if (!hasInput) throw new Error(`Build entry missing \`input\` or \`entry\`: ${JSON.stringify(entry, null, 2)}`);
1982
1726
  entry = { ...entry };
1983
1727
  entry.outDir = normalizePath(entry.outDir || "dist", ctx.pkgDir);
1984
- const entryInput = entry.input || entry.entry;
1985
- if (entryInput) if (typeof entryInput === "object" && !Array.isArray(entryInput)) {
1986
- const normalizedInput = {};
1987
- for (const [key, value] of Object.entries(entryInput)) normalizedInput[key] = normalizePath(value, ctx.pkgDir);
1988
- entry.input = normalizedInput;
1989
- } else if (Array.isArray(entryInput)) entry.input = entryInput.map((p) => normalizePath(p, ctx.pkgDir));
1990
- else entry.input = normalizePath(entryInput, ctx.pkgDir);
1728
+ if (entry.type === "transform") {
1729
+ if (entry.input) entry.input = normalizePath(entry.input, ctx.pkgDir);
1730
+ } else {
1731
+ const entryInput = entry.input || entry.entry;
1732
+ if (entryInput) if (typeof entryInput === "object" && !Array.isArray(entryInput)) {
1733
+ const normalizedInput = {};
1734
+ for (const [key, value] of Object.entries(entryInput)) normalizedInput[key] = normalizePath(value, ctx.pkgDir);
1735
+ entry.input = normalizedInput;
1736
+ } else if (Array.isArray(entryInput)) entry.input = entryInput.map((p) => normalizePath(p, ctx.pkgDir));
1737
+ else entry.input = normalizePath(entryInput, ctx.pkgDir);
1738
+ }
1991
1739
  return entry;
1992
1740
  });
1993
1741
  await hooks.entries?.(entries, ctx);
@@ -1,12 +1,18 @@
1
1
  import { ResolveOptions } from "exsolve";
2
- import { InputOptions, MinifyOptions, OutputOptions, Plugin, RolldownBuild, RolldownPluginOption } from "rolldown";
2
+ import { InputOptions, MinifyOptions, ModuleFormat, ModuleType, OutputOptions, Plugin, RolldownBuild, RolldownPluginOption } from "rolldown";
3
3
  import { Options } from "rolldown-plugin-dts";
4
4
  import { MinifyOptions as MinifyOptions$1 } from "oxc-minify";
5
5
  import { TransformOptions } from "oxc-transform";
6
6
 
7
7
  //#region src/types.d.ts
8
- type OutputFormat = 'esm' | 'cjs' | 'iife' | 'umd';
8
+
9
+ /**
10
+ * Target platform
11
+ */
9
12
  type Platform = 'browser' | 'node' | 'neutral';
13
+ /**
14
+ * Target ES version
15
+ */
10
16
  type Target = 'es5' | 'es2015' | 'es2016' | 'es2017' | 'es2018' | 'es2019' | 'es2020' | 'es2021' | 'es2022' | 'esnext';
11
17
  interface CopyEntry {
12
18
  from: string;
@@ -14,11 +20,28 @@ interface CopyEntry {
14
20
  }
15
21
  type CopyOptions = Array<string | CopyEntry>;
16
22
  type ChunkAddon = string | Record<string, string>;
17
- type OutExtensionFactory = (format: OutputFormat) => {
23
+ type OutExtensionFactory = (format: ModuleFormat) => {
18
24
  js?: string;
19
25
  dts?: string;
20
26
  };
21
- type LoaderType = 'js' | 'jsx' | 'ts' | 'tsx' | 'json' | 'css' | 'text' | 'binary' | 'file' | 'dataurl' | 'empty';
27
+ /**
28
+ * Loader types for robuild.
29
+ *
30
+ * Rolldown native types:
31
+ * - 'js', 'jsx', 'ts', 'tsx' - JavaScript/TypeScript files
32
+ * - 'json' - JSON files
33
+ * - 'text' - Text files (imported as string)
34
+ * - 'base64' - Files imported as base64 data URL
35
+ * - 'file' - Files imported as file path (copied to output)
36
+ * - 'empty' - Empty module
37
+ * - 'binary' - Binary files
38
+ * - 'css' - CSS files
39
+ * - 'asset' - Asset files (Rolldown decides between file/base64 based on size)
40
+ *
41
+ * Robuild extensions:
42
+ * - 'dataurl' - Alias for 'base64'
43
+ */
44
+ type LoaderType = ModuleType | 'dataurl';
22
45
  interface LoaderConfig {
23
46
  loader: LoaderType;
24
47
  options?: Record<string, any>;
@@ -69,9 +92,15 @@ interface _BuildEntry {
69
92
  /**
70
93
  * Output format(s) for the build.
71
94
  *
72
- * Defaults to `['esm']` if not provided.
95
+ * Uses Rolldown's ModuleFormat:
96
+ * - 'es' / 'esm' / 'module': ES modules (default)
97
+ * - 'cjs' / 'commonjs': CommonJS
98
+ * - 'iife': Immediately Invoked Function Expression
99
+ * - 'umd': Universal Module Definition
100
+ *
101
+ * @default ['es']
73
102
  */
74
- format?: OutputFormat | OutputFormat[];
103
+ format?: ModuleFormat | ModuleFormat[];
75
104
  /**
76
105
  * Target platform for the build.
77
106
  *
@@ -172,6 +201,18 @@ interface _BuildEntry {
172
201
  noExternal?: (string | RegExp)[] | ((id: string, importer?: string) => boolean);
173
202
  /**
174
203
  * File type loaders configuration.
204
+ *
205
+ * Maps file extensions to loader types. Uses Rolldown's native moduleTypes.
206
+ *
207
+ * @example
208
+ * ```ts
209
+ * loaders: {
210
+ * '.png': { loader: 'asset' }, // Auto base64 for small files, file path for large
211
+ * '.jpg': { loader: 'file' }, // Always emit as file
212
+ * '.svg': { loader: 'text' }, // Import as string
213
+ * '.woff': { loader: 'base64' }, // Import as data URL
214
+ * }
215
+ * ```
175
216
  */
176
217
  loaders?: Record<string, LoaderConfig>;
177
218
  /**
@@ -354,7 +395,7 @@ interface RobuildPluginContext {
354
395
  entry: BuildEntry;
355
396
  pkgDir: string;
356
397
  outDir: string;
357
- format: OutputFormat | OutputFormat[];
398
+ format: ModuleFormat | ModuleFormat[];
358
399
  platform: Platform;
359
400
  target: string;
360
401
  }
@@ -452,7 +493,7 @@ type LogLevel = 'silent' | 'error' | 'warn' | 'info' | 'verbose';
452
493
  type OnSuccessCallback = string | ((result: BuildResult) => void | Promise<void>);
453
494
  interface BuildResult {
454
495
  entries: Array<{
455
- format: OutputFormat;
496
+ format: ModuleFormat;
456
497
  name: string;
457
498
  exports: string[];
458
499
  deps: string[];
@@ -482,7 +523,7 @@ interface BuildConfig {
482
523
  * ```ts
483
524
  * {
484
525
  * entry: ['src/index.ts', 'src/cli.ts'],
485
- * format: ['esm', 'cjs'],
526
+ * format: ['es', 'cjs'],
486
527
  * dts: true
487
528
  * }
488
529
  * ```
@@ -491,9 +532,9 @@ interface BuildConfig {
491
532
  /**
492
533
  * Output format(s) for tsup-style configuration.
493
534
  *
494
- * @default ['esm']
535
+ * @default ['es']
495
536
  */
496
- format?: OutputFormat | OutputFormat[];
537
+ format?: ModuleFormat | ModuleFormat[];
497
538
  /**
498
539
  * Output directory for tsup-style configuration.
499
540
  *
@@ -552,6 +593,12 @@ interface BuildConfig {
552
593
  * @default false
553
594
  */
554
595
  sourcemap?: boolean | 'inline' | 'hidden';
596
+ /**
597
+ * File type loaders configuration (tsup-style).
598
+ *
599
+ * @see _BuildEntry.loaders
600
+ */
601
+ loaders?: Record<string, LoaderConfig>;
555
602
  /**
556
603
  * External dependencies (tsup-style).
557
604
  */
@@ -1,7 +1,7 @@
1
1
  //#region package.json
2
2
  var name = "robuild";
3
3
  var type = "module";
4
- var version = "0.0.15";
4
+ var version = "0.0.17";
5
5
  var packageManager = "pnpm@10.11.1";
6
6
  var description = "Zero-config ESM/TS package builder. Powered by Rolldown and Oxc";
7
7
  var license = "MIT";
@@ -24,6 +24,9 @@ var scripts = {
24
24
  "release": "pnpm test && changelogen --release && npm publish && git push --follow-tags",
25
25
  "test": "vitest run",
26
26
  "test:watch": "vitest",
27
+ "test:coverage": "vitest run --coverage",
28
+ "test:coverage:watch": "vitest --coverage",
29
+ "test:ui": "vitest --ui",
27
30
  "test:types": "tsc --noEmit --skipLibCheck src/**/*.ts",
28
31
  "docs:dev": "vitepress dev docs",
29
32
  "docs:build": "vitepress build docs",
@@ -35,15 +38,14 @@ var dependencies = {
35
38
  "cac": "^6.7.14",
36
39
  "chokidar": "^3.0.3",
37
40
  "consola": "^3.4.2",
38
- "defu": "^6.1.4",
39
41
  "exsolve": "^1.0.5",
40
42
  "glob": "^11.0.3",
41
43
  "js-yaml": "^4.1.0",
42
44
  "magic-string": "^0.30.17",
43
45
  "minimatch": "^10.0.3",
44
- "oxc-minify": "^0.89.0",
45
- "oxc-parser": "^0.89.0",
46
- "oxc-transform": "^0.89.0",
46
+ "oxc-minify": "^0.98.0",
47
+ "oxc-parser": "^0.98.0",
48
+ "oxc-transform": "^0.98.0",
47
49
  "pretty-bytes": "^7.0.1",
48
50
  "rolldown": "1.0.0-beta.30",
49
51
  "rolldown-plugin-dts": "^0.16.5",
@@ -0,0 +1,3 @@
1
+ import { RobuildPluginManager } from "./plugin-manager-w5yRGJRn.mjs";
2
+
3
+ export { RobuildPluginManager };
@@ -0,0 +1,155 @@
1
+ //#region src/features/plugin-manager.ts
2
+ /**
3
+ * Simplified plugin manager that leverages rolldown's plugin system
4
+ */
5
+ var RobuildPluginManager = class {
6
+ plugins = [];
7
+ context;
8
+ constructor(config, entry, pkgDir) {
9
+ this.context = {
10
+ config,
11
+ entry,
12
+ pkgDir,
13
+ outDir: entry.outDir || "dist",
14
+ format: entry.format || "es",
15
+ platform: entry.platform || "node",
16
+ target: entry.target || "es2022"
17
+ };
18
+ this.plugins = this.normalizePlugins(config.plugins || []);
19
+ }
20
+ /**
21
+ * Normalize plugin options to RobuildPlugin instances
22
+ */
23
+ normalizePlugins(pluginOptions) {
24
+ return pluginOptions.map((pluginOption) => this.normalizePlugin(pluginOption));
25
+ }
26
+ /**
27
+ * Normalize a single plugin option
28
+ */
29
+ normalizePlugin(pluginOption) {
30
+ if (typeof pluginOption === "function") return this.normalizePlugin(pluginOption());
31
+ if (typeof pluginOption === "object" && pluginOption !== null) {
32
+ if (this.isRobuildPlugin(pluginOption)) return pluginOption;
33
+ if (this.isRolldownPlugin(pluginOption)) return this.adaptRolldownPlugin(pluginOption);
34
+ if (this.isVitePlugin(pluginOption)) return this.adaptVitePlugin(pluginOption);
35
+ if (this.isUnplugin(pluginOption)) return this.adaptUnplugin(pluginOption);
36
+ return this.adaptRolldownPlugin(pluginOption);
37
+ }
38
+ throw new Error(`Invalid plugin option: ${typeof pluginOption}`);
39
+ }
40
+ /**
41
+ * Check if plugin is already a RobuildPlugin
42
+ */
43
+ isRobuildPlugin(plugin) {
44
+ return plugin.meta?.robuild === true || plugin.robuildSetup || plugin.robuildBuildStart || plugin.robuildBuildEnd;
45
+ }
46
+ /**
47
+ * Check if plugin is a rolldown/rollup plugin
48
+ */
49
+ isRolldownPlugin(plugin) {
50
+ return plugin.name && (plugin.buildStart || plugin.buildEnd || plugin.resolveId || plugin.load || plugin.transform || plugin.generateBundle || plugin.writeBundle);
51
+ }
52
+ /**
53
+ * Check if plugin is a Vite plugin
54
+ */
55
+ isVitePlugin(plugin) {
56
+ return plugin.config || plugin.configResolved || plugin.configureServer || plugin.meta?.vite === true;
57
+ }
58
+ /**
59
+ * Check if plugin is an Unplugin
60
+ */
61
+ isUnplugin(plugin) {
62
+ return plugin.unplugin === true || plugin.meta?.unplugin === true;
63
+ }
64
+ /**
65
+ * Adapt rolldown plugin to RobuildPlugin
66
+ */
67
+ adaptRolldownPlugin(plugin) {
68
+ return {
69
+ ...plugin,
70
+ meta: {
71
+ ...plugin.meta,
72
+ framework: "rolldown",
73
+ robuild: true,
74
+ rollup: true
75
+ }
76
+ };
77
+ }
78
+ /**
79
+ * Adapt Vite plugin to RobuildPlugin
80
+ */
81
+ adaptVitePlugin(plugin) {
82
+ return {
83
+ ...plugin,
84
+ meta: {
85
+ ...plugin.meta,
86
+ framework: "vite",
87
+ robuild: true,
88
+ vite: true
89
+ }
90
+ };
91
+ }
92
+ /**
93
+ * Adapt Unplugin to RobuildPlugin
94
+ */
95
+ adaptUnplugin(plugin) {
96
+ return {
97
+ ...plugin,
98
+ meta: {
99
+ ...plugin.meta,
100
+ framework: "unplugin",
101
+ robuild: true,
102
+ unplugin: true,
103
+ rollup: true,
104
+ vite: true,
105
+ webpack: true,
106
+ esbuild: true
107
+ }
108
+ };
109
+ }
110
+ /**
111
+ * Initialize robuild-specific plugin hooks
112
+ */
113
+ async initializeRobuildHooks() {
114
+ for (const plugin of this.plugins) if (plugin.robuildSetup) await plugin.robuildSetup(this.context);
115
+ }
116
+ /**
117
+ * Execute robuild buildStart hooks
118
+ */
119
+ async executeRobuildBuildStart() {
120
+ for (const plugin of this.plugins) if (plugin.robuildBuildStart) await plugin.robuildBuildStart(this.context);
121
+ }
122
+ /**
123
+ * Execute robuild buildEnd hooks
124
+ */
125
+ async executeRobuildBuildEnd(result) {
126
+ for (const plugin of this.plugins) if (plugin.robuildBuildEnd) await plugin.robuildBuildEnd(this.context, result);
127
+ }
128
+ /**
129
+ * Get rolldown-compatible plugins for direct use
130
+ */
131
+ getRolldownPlugins() {
132
+ return this.plugins.map((plugin) => {
133
+ const { robuildSetup, robuildBuildStart, robuildBuildEnd,...rolldownPlugin } = plugin;
134
+ return rolldownPlugin;
135
+ });
136
+ }
137
+ /**
138
+ * Get all plugins
139
+ */
140
+ getPlugins() {
141
+ return this.plugins;
142
+ }
143
+ /**
144
+ * Update context (useful when build parameters change)
145
+ */
146
+ updateContext(updates) {
147
+ this.context = {
148
+ ...this.context,
149
+ ...updates
150
+ };
151
+ }
152
+ };
153
+
154
+ //#endregion
155
+ export { RobuildPluginManager };
package/dist/cli.mjs CHANGED
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { build } from "./_chunks/build-BzBhuQnI.mjs";
2
+ import { build } from "./_chunks/build-omZA_xD-.mjs";
3
+ import "./_chunks/plugin-manager-w5yRGJRn.mjs";
3
4
  import { colors } from "consola/utils";
4
5
  import { consola } from "consola";
5
6
  import process from "node:process";
package/dist/config.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- import { defineConfig } from "./_chunks/config-_iCJoeRz.mjs";
1
+ import { defineConfig } from "./_chunks/config-2CRkKJ3l.mjs";
2
2
  export { defineConfig };
package/dist/config.mjs CHANGED
@@ -1,3 +1,3 @@
1
- import { defineConfig } from "./_chunks/config-C1aXyI1S.mjs";
1
+ import { defineConfig } from "./_chunks/config-BsKCDKT5.mjs";
2
2
 
3
3
  export { defineConfig };
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { BuildConfig, BuildEntry, BundleEntry, RobuildPlugin, TransformEntry, defineConfig } from "./_chunks/config-_iCJoeRz.mjs";
1
+ import { BuildConfig, BuildEntry, BundleEntry, RobuildPlugin, TransformEntry, defineConfig } from "./_chunks/config-2CRkKJ3l.mjs";
2
2
  import { Plugin } from "rolldown";
3
3
 
4
4
  //#region src/build.d.ts
@@ -14,12 +14,6 @@ declare function build(config: BuildConfig): Promise<void>;
14
14
  */
15
15
  declare function combinePlugins(name: string, plugins: RobuildPlugin[]): RobuildPlugin;
16
16
  //#endregion
17
- //#region src/plugins/css.d.ts
18
- /**
19
- * Built-in plugin for CSS imports
20
- */
21
- declare function cssPlugin(): RobuildPlugin;
22
- //#endregion
23
17
  //#region src/plugins/node-polyfills.d.ts
24
18
  /**
25
19
  * Built-in plugin for Node.js polyfills
@@ -56,4 +50,4 @@ declare function urlPlugin(extensions?: string[]): RobuildPlugin;
56
50
  */
57
51
  declare function virtualPlugin(modules: Record<string, string>): RobuildPlugin;
58
52
  //#endregion
59
- export { type BuildConfig, type BuildEntry, type BundleEntry, type RobuildPlugin, SHEBANG_RE, type TransformEntry, build, combinePlugins, cssPlugin, defineConfig, hasShebang, makeExecutable, nodePolyfillsPlugin, nodeProtocolPlugin, shebangPlugin, textPlugin, urlPlugin, virtualPlugin };
53
+ export { type BuildConfig, type BuildEntry, type BundleEntry, type RobuildPlugin, SHEBANG_RE, type TransformEntry, build, combinePlugins, defineConfig, hasShebang, makeExecutable, nodePolyfillsPlugin, nodeProtocolPlugin, shebangPlugin, textPlugin, urlPlugin, virtualPlugin };
package/dist/index.mjs CHANGED
@@ -1,5 +1,6 @@
1
- import { SHEBANG_RE, build, hasShebang, makeExecutable, nodeProtocolPlugin, shebangPlugin } from "./_chunks/build-BzBhuQnI.mjs";
2
- import { defineConfig } from "./_chunks/config-C1aXyI1S.mjs";
1
+ import { SHEBANG_RE, build, hasShebang, makeExecutable, nodeProtocolPlugin, shebangPlugin } from "./_chunks/build-omZA_xD-.mjs";
2
+ import "./_chunks/plugin-manager-w5yRGJRn.mjs";
3
+ import { defineConfig } from "./_chunks/config-BsKCDKT5.mjs";
3
4
 
4
5
  //#region src/features/plugin-utils.ts
5
6
  /**
@@ -93,36 +94,6 @@ function combinePlugins(name, plugins) {
93
94
  return combinedPlugin;
94
95
  }
95
96
 
96
- //#endregion
97
- //#region src/plugins/css.ts
98
- /**
99
- * Built-in plugin for CSS imports
100
- */
101
- function cssPlugin() {
102
- return {
103
- name: "css",
104
- load: async (id) => {
105
- if (id.endsWith(".css")) try {
106
- const { readFile } = await import("node:fs/promises");
107
- const content = await readFile(id, "utf-8");
108
- return `
109
- const css = ${JSON.stringify(content)};
110
- if (typeof document !== 'undefined') {
111
- const style = document.createElement('style');
112
- style.textContent = css;
113
- document.head.appendChild(style);
114
- }
115
- export default css;
116
- `;
117
- } catch (error) {
118
- console.error(`Failed to load CSS file ${id}:`, error);
119
- return null;
120
- }
121
- return null;
122
- }
123
- };
124
- }
125
-
126
97
  //#endregion
127
98
  //#region src/plugins/node-polyfills.ts
128
99
  /**
@@ -217,4 +188,4 @@ function virtualPlugin(modules) {
217
188
  }
218
189
 
219
190
  //#endregion
220
- export { SHEBANG_RE, build, combinePlugins, cssPlugin, defineConfig, hasShebang, makeExecutable, nodePolyfillsPlugin, nodeProtocolPlugin, shebangPlugin, textPlugin, urlPlugin, virtualPlugin };
191
+ export { SHEBANG_RE, build, combinePlugins, defineConfig, hasShebang, makeExecutable, nodePolyfillsPlugin, nodeProtocolPlugin, shebangPlugin, textPlugin, urlPlugin, virtualPlugin };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "robuild",
3
3
  "type": "module",
4
- "version": "0.0.15",
4
+ "version": "0.0.17",
5
5
  "packageManager": "pnpm@10.11.1",
6
6
  "description": "Zero-config ESM/TS package builder. Powered by Rolldown and Oxc",
7
7
  "license": "MIT",
@@ -26,6 +26,9 @@
26
26
  "release": "pnpm test && changelogen --release && npm publish && git push --follow-tags",
27
27
  "test": "vitest run",
28
28
  "test:watch": "vitest",
29
+ "test:coverage": "vitest run --coverage",
30
+ "test:coverage:watch": "vitest --coverage",
31
+ "test:ui": "vitest --ui",
29
32
  "test:types": "tsc --noEmit --skipLibCheck src/**/*.ts",
30
33
  "docs:dev": "vitepress dev docs",
31
34
  "docs:build": "vitepress build docs",
@@ -37,15 +40,14 @@
37
40
  "cac": "^6.7.14",
38
41
  "chokidar": "^3.0.3",
39
42
  "consola": "^3.4.2",
40
- "defu": "^6.1.4",
41
43
  "exsolve": "^1.0.5",
42
44
  "glob": "^11.0.3",
43
45
  "js-yaml": "^4.1.0",
44
46
  "magic-string": "^0.30.17",
45
47
  "minimatch": "^10.0.3",
46
- "oxc-minify": "^0.89.0",
47
- "oxc-parser": "^0.89.0",
48
- "oxc-transform": "^0.89.0",
48
+ "oxc-minify": "^0.98.0",
49
+ "oxc-parser": "^0.98.0",
50
+ "oxc-transform": "^0.98.0",
49
51
  "pretty-bytes": "^7.0.1",
50
52
  "rolldown": "1.0.0-beta.30",
51
53
  "rolldown-plugin-dts": "^0.16.5",
@@ -1,3 +0,0 @@
1
- import { build, performBuild } from "./build-BzBhuQnI.mjs";
2
-
3
- export { performBuild };