tsdown 0.10.1 → 0.11.0-beta.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.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  <img src="./docs/public/og-image.svg" alt="tsdown" width="100%" /><br>
2
2
 
3
- # tsdown [![npm](https://img.shields.io/npm/v/tsdown.svg)](https://npmjs.com/package/tsdown) [![Unit Test](https://github.com/rolldown/tsdown/actions/workflows/tests.yml/badge.svg)](https://github.com/rolldown/tsdown/actions/workflows/tests.yml) [![JSR](https://jsr.io/badges/@sxzz/tsdown)](https://jsr.io/@sxzz/tsdown)
3
+ # tsdown [![npm](https://img.shields.io/npm/v/tsdown.svg)](https://npmjs.com/package/tsdown) [![Unit Test](https://github.com/rolldown/tsdown/actions/workflows/tests.yml/badge.svg)](https://github.com/rolldown/tsdown/actions/workflows/tests.yml) [![JSR](https://jsr.io/badges/@sxzz/tsdown)](https://jsr.io/@sxzz/tsdown) [![tsdown-starter-stackblitz](https://developer.stackblitz.com/img/open_in_stackblitz_small.svg)](https://stackblitz.com/github/rolldown/tsdown-starter-stackblitz)
4
4
 
5
5
  ✨ The elegant bundler for libraries powered by [Rolldown](https://github.com/rolldown/rolldown).
6
6
 
@@ -1,9 +1,12 @@
1
- import { UserConfig, UserConfigFn } from "./options.d--a1aWVL6.js";
1
+ import { UserConfig, UserConfigFn } from "./options.d-BLasdguL.js";
2
2
 
3
3
  //#region src/config.d.ts
4
4
  /**
5
5
  * Defines the configuration for tsdown.
6
6
  */
7
+ /**
8
+ * Defines the configuration for tsdown.
9
+ */
7
10
  declare function defineConfig(options: UserConfig): UserConfig;
8
11
  declare function defineConfig(options: UserConfigFn): UserConfigFn;
9
12
 
package/dist/config.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- import { UserConfig, UserConfigFn } from "./options.d--a1aWVL6.js";
2
- import { defineConfig$1 as defineConfig } from "./config.d-D3EdptPL.js";
1
+ import { UserConfig, UserConfigFn } from "./options.d-BLasdguL.js";
2
+ import { defineConfig$1 as defineConfig } from "./config.d-2sS1Su5e.js";
3
3
  export { UserConfig, UserConfigFn, defineConfig };
@@ -1,16 +1,3 @@
1
- import process from "node:process";
2
- import { consola } from "consola";
3
-
4
- //#region src/utils/logger.ts
5
- /**
6
- * Logger instance
7
- */
8
- const logger = consola.withTag("tsdown");
9
- function setSilent(silent) {
10
- if (!("CONSOLA_LEVEL" in process.env)) logger.level = silent ? 0 : 3;
11
- }
12
-
13
- //#endregion
14
1
  //#region src/utils/general.ts
15
2
  function toArray(val, defaultValue) {
16
3
  if (Array.isArray(val)) return val;
@@ -35,4 +22,4 @@ function debounce(fn, wait) {
35
22
  const noop = (v) => v;
36
23
 
37
24
  //#endregion
38
- export { debounce, logger, noop, resolveComma, setSilent, toArray };
25
+ export { debounce, noop, resolveComma, toArray };
package/dist/index.d.ts CHANGED
@@ -1,21 +1,22 @@
1
- import { BuildContext, Options, ResolvedOptions, TsdownHooks, UserConfig } from "./options.d--a1aWVL6.js";
2
- import { defineConfig$1 as defineConfig } from "./config.d-D3EdptPL.js";
3
- import { ConsolaInstance } from "consola";
1
+ import { BuildContext, Options, ResolvedOptions, TsdownHooks, UserConfig } from "./options.d-BLasdguL.js";
2
+ import { defineConfig$1 as defineConfig } from "./config.d-2sS1Su5e.js";
4
3
 
5
4
  //#region src/utils/logger.d.ts
6
- /**
7
- * Logger instance
8
- */
9
- declare const logger: ConsolaInstance;
10
-
11
- //#endregion
5
+ declare class Logger {
6
+ silent: boolean;
7
+ setSilent(value: boolean): void;
8
+ info(...args: any[]): void;
9
+ warn(...args: any[]): void;
10
+ error(...args: any[]): void;
11
+ success(...args: any[]): void;
12
+ }
13
+ declare const logger: Logger; //#endregion
12
14
  //#region src/index.d.ts
13
15
  /**
14
16
  * Build with tsdown.
15
17
  */
16
18
  declare function build(userOptions?: Options): Promise<void>;
17
19
  declare const pkgRoot: string;
18
-
19
20
  /**
20
21
  * Build a single configuration, without watch and shortcuts features.
21
22
  *
package/dist/index.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import { defineConfig } from "./config-CpIe1Ud_.js";
2
- import { ExternalPlugin, ReportPlugin, ShebangPlugin, fsExists, fsRemove, getPackageType, lowestCommonAncestor, normalizeFormat, prettyFormat, readPackageJson } from "./plugins-DX6CtlR1.js";
3
- import { debounce, logger, resolveComma, setSilent, toArray } from "./general-C06aMSSY.js";
2
+ import { ExternalPlugin, NodeProtocolPlugin, ReportPlugin, ShebangPlugin, fsCopy, fsRemove, fsStat, getPackageType, lowestCommonAncestor, normalizeFormat, prettyFormat, readPackageJson } from "./plugins-xuho_Cqn.js";
3
+ import { logger } from "./logger-DKXLpcNj.js";
4
+ import { debounce, resolveComma, toArray } from "./general-nv5tYplM.js";
4
5
  import path from "node:path";
5
6
  import process from "node:process";
6
- import { fileURLToPath, pathToFileURL } from "node:url";
7
7
  import { blue, bold, dim, green, underline } from "ansis";
8
8
  import Debug from "debug";
9
9
  import { build as build$1 } from "rolldown";
@@ -12,25 +12,32 @@ import { exec } from "tinyexec";
12
12
  import { glob } from "tinyglobby";
13
13
  import { stat } from "node:fs/promises";
14
14
  import { createHooks } from "hookable";
15
- import LightningCSS from "unplugin-lightningcss/rolldown";
16
15
  import readline from "node:readline";
16
+ import { pathToFileURL } from "node:url";
17
17
  import { loadConfig } from "unconfig";
18
+ import minVersion from "semver/ranges/min-version";
18
19
  import { up } from "empathic/find";
19
20
 
20
21
  //#region src/features/clean.ts
21
22
  const debug$3 = Debug("tsdown:clean");
23
+ const RE_LAST_SLASH = /[/\\]$/;
22
24
  async function cleanOutDir(configs) {
23
25
  const removes = new Set();
24
26
  for (const config of configs) {
25
27
  if (!config.clean.length) continue;
26
28
  const files = await glob(config.clean, {
27
29
  cwd: config.cwd,
28
- absolute: true
30
+ absolute: true,
31
+ onlyFiles: false
29
32
  });
30
- for (const file of files) removes.add(file);
33
+ const normalizedOutDir = config.outDir.replace(RE_LAST_SLASH, "");
34
+ for (const file of files) {
35
+ const normalizedFile = file.replace(RE_LAST_SLASH, "");
36
+ if (normalizedFile !== normalizedOutDir) removes.add(file);
37
+ }
31
38
  }
32
39
  if (!removes.size) return;
33
- logger.info("Cleaning %d files", removes.size);
40
+ logger.info(`Cleaning ${removes.size} files`);
34
41
  await Promise.all([...removes].map(async (file) => {
35
42
  debug$3("Removing", file);
36
43
  await fsRemove(file);
@@ -43,6 +50,21 @@ function resolveClean(clean, outDir) {
43
50
  return clean;
44
51
  }
45
52
 
53
+ //#endregion
54
+ //#region src/features/copy.ts
55
+ async function copy(options) {
56
+ if (!options.copy) return;
57
+ const copy$1 = typeof options.copy === "function" ? await options.copy(options) : options.copy;
58
+ await Promise.all(toArray(copy$1).map((dir) => {
59
+ const from = typeof dir === "string" ? dir : dir.from;
60
+ const to = typeof dir === "string" ? path.resolve(options.outDir, path.basename(from)) : dir.to;
61
+ return cp$1(options.cwd, from, to);
62
+ }));
63
+ }
64
+ function cp$1(cwd, from, to) {
65
+ return fsCopy(path.resolve(cwd, from), path.resolve(cwd, to));
66
+ }
67
+
46
68
  //#endregion
47
69
  //#region src/features/hooks.ts
48
70
  async function createHooks$1(options, pkg) {
@@ -103,10 +125,12 @@ function parseVersion(version) {
103
125
 
104
126
  //#endregion
105
127
  //#region src/features/lightningcss.ts
106
- function LightningCSSPlugin(options) {
128
+ async function LightningCSSPlugin(options) {
129
+ const LightningCSS = await import("unplugin-lightningcss/rolldown").catch(() => void 0);
130
+ if (!LightningCSS) return;
107
131
  const targets = options.target && esbuildTargetToLightningCSS(options.target);
108
132
  if (!targets) return;
109
- return LightningCSS({ options: { targets } });
133
+ return LightningCSS.default({ options: { targets } });
110
134
  }
111
135
 
112
136
  //#endregion
@@ -145,17 +169,22 @@ function createChunkFilename(basename, jsExtension, dtsExtension) {
145
169
  //#endregion
146
170
  //#region src/features/publint.ts
147
171
  const debug$2 = Debug("tsdown:publint");
148
- async function publint(pkg, options) {
172
+ async function publint(options) {
173
+ if (!options.publint) return;
174
+ if (!options.pkg) {
175
+ logger.warn("publint is enabled but package.json is not found");
176
+ return;
177
+ }
149
178
  debug$2("Running publint");
150
179
  const { publint: publint$1 } = await import("publint");
151
180
  const { formatMessage } = await import("publint/utils");
152
- const { messages } = await publint$1(options);
181
+ const { messages } = await publint$1(options.publint === true ? {} : options.publint);
153
182
  debug$2("Found %d issues", messages.length);
154
183
  if (!messages.length) logger.success("No publint issues found");
155
184
  let hasError = false;
156
185
  for (const message of messages) {
157
186
  hasError ||= message.type === "error";
158
- const formattedMessage = formatMessage(message, pkg);
187
+ const formattedMessage = formatMessage(message, options.pkg);
159
188
  const logType = {
160
189
  error: "error",
161
190
  warning: "warn",
@@ -237,7 +266,7 @@ function shortcuts(restart) {
237
266
  const endsWithPackageJson = /[\\/]package\.json$/;
238
267
  async function watchBuild(options, configFile, rebuild, restart) {
239
268
  const cwd = process.cwd();
240
- if (typeof options.watch === "boolean" && options.outDir === cwd) throw new Error("Watch is enabled, but output directory is the same as the current working directory.Please specify a different watch directory using `watch` option,or set `outDir` to a different directory.");
269
+ if (typeof options.watch === "boolean" && options.outDir === cwd) throw new Error(`Watch is enabled, but output directory is the same as the current working directory.Please specify a different watch directory using ${blue`watch`} option,or set ${blue`outDir`} to a different directory.`);
241
270
  const files = toArray(typeof options.watch === "boolean" ? cwd : options.watch);
242
271
  logger.info(`Watching for changes in ${files.join(", ")}`);
243
272
  if (configFile) files.push(configFile);
@@ -285,26 +314,46 @@ async function toObjectEntry(entry, cwd) {
285
314
  }));
286
315
  }
287
316
 
317
+ //#endregion
318
+ //#region src/features/target.ts
319
+ function resolveTarget(target, pkg) {
320
+ if (!target) {
321
+ const pkgTarget = resolvePackageTarget(pkg);
322
+ if (pkgTarget) target = pkgTarget;
323
+ else return;
324
+ }
325
+ return resolveComma(toArray(target));
326
+ }
327
+ function resolvePackageTarget(pkg) {
328
+ const nodeVersion = pkg?.engines?.node;
329
+ if (!nodeVersion) return;
330
+ const nodeMinVersion = minVersion(nodeVersion);
331
+ if (!nodeMinVersion) return;
332
+ if (nodeMinVersion.version === "0.0.0") return;
333
+ return `node${nodeMinVersion.version}`;
334
+ }
335
+
288
336
  //#endregion
289
337
  //#region src/features/tsconfig.ts
290
338
  function findTsconfig(cwd, name = "tsconfig.json") {
291
339
  return up(name, { cwd }) || false;
292
340
  }
293
341
  async function resolveTsconfig(tsconfig, cwd) {
342
+ const original = tsconfig;
294
343
  if (tsconfig !== false) {
295
344
  if (tsconfig === true || tsconfig == null) {
296
- const isSet = tsconfig;
297
345
  tsconfig = findTsconfig(cwd);
298
- if (isSet && !tsconfig) logger.warn(`No tsconfig found in \`${cwd}\``);
346
+ if (original && !tsconfig) logger.warn(`No tsconfig found in ${blue(cwd)}`);
299
347
  } else {
300
348
  const tsconfigPath = path.resolve(cwd, tsconfig);
301
- if (await fsExists(tsconfigPath)) tsconfig = tsconfigPath;
302
- else if (tsconfig.includes("\\") || tsconfig.includes("/")) {
303
- logger.warn(`tsconfig \`${tsconfig}\` doesn't exist`);
304
- tsconfig = false;
349
+ const stat$1 = await fsStat(tsconfigPath);
350
+ if (stat$1?.isFile()) tsconfig = tsconfigPath;
351
+ else if (stat$1?.isDirectory()) {
352
+ tsconfig = findTsconfig(tsconfigPath);
353
+ if (!tsconfig) logger.warn(`No tsconfig found in ${blue(tsconfigPath)}`);
305
354
  } else {
306
355
  tsconfig = findTsconfig(cwd, tsconfig);
307
- if (!tsconfig) logger.warn(`No \`${tsconfig}\` found in \`${cwd}\``);
356
+ if (!tsconfig) logger.warn(`tsconfig ${blue(original)} doesn't exist`);
308
357
  }
309
358
  }
310
359
  if (tsconfig) logger.info(`Using tsconfig: ${underline(path.relative(cwd, tsconfig))}`);
@@ -325,7 +374,7 @@ async function resolveOptions(options) {
325
374
  ...subConfig,
326
375
  ...options
327
376
  };
328
- let { entry, format = ["es"], plugins = [], clean = true, silent = false, treeshake = true, platform = "node", outDir = "dist", sourcemap = false, dts, unused = false, watch = false, shims = false, skipNodeModulesBundle = false, publint: publint$1 = false, fromVite, alias, tsconfig, report = true, target, env = {} } = subOptions;
377
+ let { entry, format = ["es"], plugins = [], clean = true, silent = false, treeshake = true, platform = "node", outDir = "dist", sourcemap = false, dts, unused = false, watch = false, shims = false, skipNodeModulesBundle = false, publint: publint$1 = false, fromVite, alias, tsconfig, report = true, target, env = {}, copy: copy$1, publicDir } = subOptions;
329
378
  outDir = path.resolve(outDir);
330
379
  entry = await resolveEntry(entry, cwd);
331
380
  clean = resolveClean(clean, outDir);
@@ -333,6 +382,9 @@ async function resolveOptions(options) {
333
382
  if (dts == null) dts = !!(pkg?.types || pkg?.typings);
334
383
  tsconfig = await resolveTsconfig(tsconfig, cwd);
335
384
  if (publint$1 === true) publint$1 = {};
385
+ target = resolveTarget(target, pkg);
386
+ if (publicDir) if (copy$1) throw new TypeError("`publicDir` is deprecated. Cannot be used with `copy`");
387
+ else logger.warn(`${blue`publicDir`} is deprecated. Use ${blue`copy`} instead.`);
336
388
  if (fromVite) {
337
389
  const viteUserConfig = await loadViteConfig(fromVite === true ? "vite" : fromVite, cwd);
338
390
  if (viteUserConfig) {
@@ -347,7 +399,7 @@ async function resolveOptions(options) {
347
399
  entry,
348
400
  plugins,
349
401
  format: normalizeFormat(format),
350
- target: target ? resolveComma(toArray(target)) : void 0,
402
+ target,
351
403
  outDir,
352
404
  clean,
353
405
  silent,
@@ -365,7 +417,8 @@ async function resolveOptions(options) {
365
417
  tsconfig,
366
418
  cwd,
367
419
  env,
368
- pkg
420
+ pkg,
421
+ copy: publicDir || copy$1
369
422
  };
370
423
  return config;
371
424
  }));
@@ -475,7 +528,7 @@ const debug = Debug("tsdown:main");
475
528
  * Build with tsdown.
476
529
  */
477
530
  async function build(userOptions = {}) {
478
- if (typeof userOptions.silent === "boolean") setSilent(userOptions.silent);
531
+ if (typeof userOptions.silent === "boolean") logger.setSilent(userOptions.silent);
479
532
  debug("Loading config");
480
533
  const { configs, file: configFile } = await resolveOptions(userOptions);
481
534
  if (configFile) {
@@ -503,8 +556,7 @@ async function build(userOptions = {}) {
503
556
  build(userOptions);
504
557
  }
505
558
  }
506
- const dirname$1 = path.dirname(fileURLToPath(import.meta.url));
507
- const pkgRoot = path.resolve(dirname$1, "..");
559
+ const pkgRoot = path.resolve(import.meta.dirname, "..");
508
560
  /**
509
561
  * Build a single configuration, without watch and shortcuts features.
510
562
  *
@@ -546,9 +598,9 @@ async function buildSingle(config, clean) {
546
598
  }
547
599
  }));
548
600
  if (hasErrors) return;
601
+ await publint(config);
602
+ await copy(config);
549
603
  await hooks.callHook("build:done", context);
550
- if (config.publint) if (config.pkg) await publint(config.pkg, config.publint === true ? {} : config.publint);
551
- else logger.warn("publint is enabled but package.json is not found");
552
604
  logger.success(`${first ? "Build" : "Rebuild"} complete in ${green(`${Math.round(performance.now() - startTime)}ms`)}`);
553
605
  if (typeof onSuccess === "string") {
554
606
  const p = exec(onSuccess, [], { nodeOptions: {
@@ -563,7 +615,7 @@ async function buildSingle(config, clean) {
563
615
  }
564
616
  }
565
617
  async function getBuildOptions(config, format, cjsDts) {
566
- const { entry, external, plugins: userPlugins, outDir, platform, alias, treeshake, sourcemap, dts, minify, unused, target, define, shims, tsconfig, cwd, report, env } = config;
618
+ const { entry, external, plugins: userPlugins, outDir, platform, alias, treeshake, sourcemap, dts, minify, unused, target, define, shims, tsconfig, cwd, report, env, removeNodeProtocol } = config;
567
619
  const plugins = [];
568
620
  if (config.pkg || config.skipNodeModulesBundle) plugins.push(ExternalPlugin(config));
569
621
  if (dts) {
@@ -590,13 +642,14 @@ async function getBuildOptions(config, format, cjsDts) {
590
642
  }));
591
643
  plugins.push(ShebangPlugin(cwd));
592
644
  }
593
- if (report && logger.level >= 3) plugins.push(ReportPlugin(report, cwd, cjsDts));
645
+ if (report && !logger.silent) plugins.push(ReportPlugin(report, cwd, cjsDts));
594
646
  if (target) plugins.push(
595
647
  // Use Lightning CSS to handle CSS input. This is a temporary solution
596
648
  // until Rolldown supports CSS syntax lowering natively.
597
- LightningCSSPlugin({ target })
649
+ await LightningCSSPlugin({ target })
598
650
  );
599
651
  plugins.push(userPlugins);
652
+ if (removeNodeProtocol) plugins.push(NodeProtocolPlugin());
600
653
  const inputOptions = await mergeUserOptions({
601
654
  input: entry,
602
655
  cwd,
@@ -0,0 +1,25 @@
1
+ import { bgRed, bgYellow, blue, green } from "ansis";
2
+
3
+ //#region src/utils/logger.ts
4
+ var Logger = class {
5
+ silent = false;
6
+ setSilent(value) {
7
+ this.silent = value;
8
+ }
9
+ info(...args) {
10
+ if (!this.silent) console.info(blue`ℹ`, ...args);
11
+ }
12
+ warn(...args) {
13
+ if (!this.silent) console.warn("\n", bgYellow` WARN `, ...args, "\n");
14
+ }
15
+ error(...args) {
16
+ if (!this.silent) console.error("\n", bgRed` ERROR `, ...args, "\n");
17
+ }
18
+ success(...args) {
19
+ if (!this.silent) console.info(green`✔`, ...args);
20
+ }
21
+ };
22
+ const logger = new Logger();
23
+
24
+ //#endregion
25
+ export { logger };
@@ -1,17 +1,25 @@
1
- import { version } from "./package-DfgxaSyP.js";
1
+ import { logger } from "./logger-DKXLpcNj.js";
2
+ import { version } from "./package-BqZXvp6d.js";
2
3
  import process from "node:process";
3
- import { green, underline } from "ansis";
4
+ import { bold, green, underline } from "ansis";
4
5
  import { readFile, unlink, writeFile } from "node:fs/promises";
5
- import consola$1 from "consola";
6
6
  import { existsSync } from "node:fs";
7
+ import { createInterface } from "node:readline/promises";
7
8
 
8
9
  //#region src/migrate.ts
9
10
  async function migrate({ cwd, dryRun }) {
10
- if (dryRun) consola$1.info("Dry run enabled. No changes were made.");
11
+ if (dryRun) logger.info("Dry run enabled. No changes were made.");
11
12
  else {
12
- const confirm = await consola$1.prompt(`Before proceeding, review the migration guide at ${underline`https://tsdown.dev/guide/migrate-from-tsup`}, as this process will modify your files.\nUncommitted changes will be lost. Use the ${green`--dry-run`} flag to preview changes without applying them.\n\nContinue?`, { type: "confirm" });
13
+ const rl = createInterface({
14
+ input: process.stdin,
15
+ output: process.stdout
16
+ });
17
+ logger.warn(`\n\nBefore proceeding, review the migration guide at ${underline`https://tsdown.dev/guide/migrate-from-tsup`}, as this process will modify your files.\nUncommitted changes will be lost. Use the ${green`--dry-run`} flag to preview changes without applying them.`);
18
+ const input = await rl.question(bold`Continue? (Y/n) `);
19
+ rl.close();
20
+ const confirm = input.toLowerCase() === "y" || input === "";
13
21
  if (!confirm) {
14
- consola$1.error("Migration cancelled.");
22
+ logger.error("Migration cancelled.");
15
23
  process.exitCode = 1;
16
24
  return;
17
25
  }
@@ -19,15 +27,15 @@ async function migrate({ cwd, dryRun }) {
19
27
  if (cwd) process.chdir(cwd);
20
28
  let migrated = await migratePackageJson(dryRun);
21
29
  if (await migrateTsupConfig(dryRun)) migrated = true;
22
- if (migrated) consola$1.success("Migration completed. Remember to run install command with your package manager.");
30
+ if (migrated) logger.success("Migration completed. Remember to run install command with your package manager.");
23
31
  else {
24
- consola$1.error("No migration performed.");
32
+ logger.error("No migration performed.");
25
33
  process.exitCode = 1;
26
34
  }
27
35
  }
28
36
  async function migratePackageJson(dryRun) {
29
37
  if (!existsSync("package.json")) {
30
- consola$1.error("No package.json found");
38
+ logger.error("No package.json found");
31
39
  return false;
32
40
  }
33
41
  const pkgRaw = await readFile("package.json", "utf-8");
@@ -35,44 +43,44 @@ async function migratePackageJson(dryRun) {
35
43
  const semver = `^${version}`;
36
44
  let found = false;
37
45
  if (pkg.dependencies?.tsup) {
38
- consola$1.info("Migrating `dependencies` to tsdown.");
46
+ logger.info("Migrating `dependencies` to tsdown.");
39
47
  found = true;
40
48
  pkg.dependencies = renameKey(pkg.dependencies, "tsup", "tsdown", semver);
41
49
  }
42
50
  if (pkg.devDependencies?.tsup) {
43
- consola$1.info("Migrating `devDependencies` to tsdown.");
51
+ logger.info("Migrating `devDependencies` to tsdown.");
44
52
  found = true;
45
53
  pkg.devDependencies = renameKey(pkg.devDependencies, "tsup", "tsdown", semver);
46
54
  }
47
55
  if (pkg.peerDependencies?.tsup) {
48
- consola$1.info("Migrating `peerDependencies` to tsdown.");
56
+ logger.info("Migrating `peerDependencies` to tsdown.");
49
57
  found = true;
50
58
  pkg.peerDependencies = renameKey(pkg.peerDependencies, "tsup", "tsdown", "*");
51
59
  }
52
60
  if (pkg.scripts) {
53
61
  for (const key of Object.keys(pkg.scripts)) if (pkg.scripts[key].includes("tsup")) {
54
- consola$1.info(`Migrating \`${key}\` script to tsdown`);
62
+ logger.info(`Migrating \`${key}\` script to tsdown`);
55
63
  found = true;
56
64
  pkg.scripts[key] = pkg.scripts[key].replaceAll(/tsup(?:-node)?/g, "tsdown");
57
65
  }
58
66
  }
59
67
  if (pkg.tsup) {
60
- consola$1.info("Migrating `tsup` field in package.json to `tsdown`.");
68
+ logger.info("Migrating `tsup` field in package.json to `tsdown`.");
61
69
  found = true;
62
70
  pkg = renameKey(pkg, "tsup", "tsdown");
63
71
  }
64
72
  if (!found) {
65
- consola$1.warn("No tsup-related fields found in package.json");
73
+ logger.warn("No tsup-related fields found in package.json");
66
74
  return false;
67
75
  }
68
76
  const pkgStr = `${JSON.stringify(pkg, null, 2)}\n`;
69
77
  if (dryRun) {
70
78
  const { createPatch } = await import("diff");
71
- consola$1.info("[dry-run] package.json:");
79
+ logger.info("[dry-run] package.json:");
72
80
  console.info(createPatch("package.json", pkgRaw, pkgStr));
73
81
  } else {
74
82
  await writeFile("package.json", pkgStr);
75
- consola$1.success("Migrated `package.json`");
83
+ logger.success("Migrated `package.json`");
76
84
  }
77
85
  return true;
78
86
  }
@@ -89,22 +97,22 @@ async function migrateTsupConfig(dryRun) {
89
97
  let found = false;
90
98
  for (const file of TSUP_FILES) {
91
99
  if (!existsSync(file)) continue;
92
- consola$1.info(`Found \`${file}\``);
100
+ logger.info(`Found \`${file}\``);
93
101
  found = true;
94
102
  const tsupConfigRaw = await readFile(file, "utf-8");
95
103
  const tsupConfig = tsupConfigRaw.replaceAll(/\btsup\b/g, "tsdown").replaceAll(/\bTSUP\b/g, "TSDOWN");
96
104
  const renamed = file.replaceAll("tsup", "tsdown");
97
105
  if (dryRun) {
98
106
  const { createTwoFilesPatch } = await import("diff");
99
- consola$1.info(`[dry-run] ${file} -> ${renamed}:`);
107
+ logger.info(`[dry-run] ${file} -> ${renamed}:`);
100
108
  console.info(createTwoFilesPatch(file, renamed, tsupConfigRaw, tsupConfig));
101
109
  } else {
102
110
  await writeFile(renamed, tsupConfig, "utf8");
103
111
  await unlink(file);
104
- consola$1.success(`Migrated \`${file}\` to \`${renamed}\``);
112
+ logger.success(`Migrated \`${file}\` to \`${renamed}\``);
105
113
  }
106
114
  }
107
- if (!found) consola$1.warn("No tsup config found");
115
+ if (!found) logger.warn("No tsup config found");
108
116
  return found;
109
117
  }
110
118
  function renameKey(obj, oldKey, newKey, newValue) {
@@ -5,6 +5,22 @@ import { Options as Options$1 } from "rolldown-plugin-dts";
5
5
  import { Options as Options$2 } from "unplugin-unused";
6
6
  import { PackageJson } from "pkg-types";
7
7
 
8
+ //#region src/utils/types.d.ts
9
+ type Overwrite<T, U> = Omit<T, keyof U> & U;
10
+ type Awaitable<T> = T | Promise<T>;
11
+ type MarkPartial<T, K extends keyof T> = Omit<Required<T>, K> & Partial<Pick<T, K>>;
12
+ type Arrayable<T> = T | T[];
13
+
14
+ //#endregion
15
+ //#region src/features/copy.d.ts
16
+ interface CopyEntry {
17
+ from: string;
18
+ to: string;
19
+ }
20
+ type CopyOptions = Arrayable<string | CopyEntry>;
21
+ type CopyOptionsFn = (options: ResolvedOptions) => Awaitable<CopyOptions>;
22
+
23
+ //#endregion
8
24
  //#region src/features/hooks.d.ts
9
25
  interface BuildContext {
10
26
  options: ResolvedOptions;
@@ -14,7 +30,6 @@ interface BuildContext {
14
30
  interface RolldownContext {
15
31
  buildOptions: BuildOptions;
16
32
  }
17
-
18
33
  /**
19
34
  * Hooks for tsdown.
20
35
  */
@@ -35,7 +50,9 @@ interface TsdownHooks {
35
50
  * Use this hook for cleanup or post-processing tasks.
36
51
  */
37
52
  "build:done": (ctx: BuildContext) => void | Promise<void>;
38
- } //#endregion
53
+ }
54
+
55
+ //#endregion
39
56
  //#region src/utils/package.d.ts
40
57
  type PackageType = "module" | "commonjs" | undefined;
41
58
 
@@ -71,19 +88,11 @@ interface ReportOptions {
71
88
  }
72
89
  declare function ReportPlugin(options: ReportOptions, cwd: string, cjsDts?: boolean): Plugin;
73
90
 
74
- //#endregion
75
- //#region src/utils/types.d.ts
76
- type Overwrite<T, U> = Omit<T, keyof U> & U;
77
- type Awaitable<T> = T | Promise<T>;
78
- type MarkPartial<T, K extends keyof T> = Omit<Required<T>, K> & Partial<Pick<T, K>>;
79
- type Arrayable<T> = T | T[];
80
-
81
91
  //#endregion
82
92
  //#region src/options.d.ts
83
93
  type Sourcemap = boolean | "inline" | "hidden";
84
94
  type Format = Exclude<ModuleFormat, "experimental-app">;
85
95
  type NormalizedFormat = Exclude<InternalModuleFormat, "app">;
86
-
87
96
  /**
88
97
  * Options for tsdown.
89
98
  */
@@ -110,6 +119,28 @@ interface Options$3 {
110
119
  clean?: boolean | string[];
111
120
  /** @default false */
112
121
  minify?: boolean | "dce-only" | MinifyOptions;
122
+ /**
123
+ * Specifies the compilation target environment(s).
124
+ *
125
+ * Determines the JavaScript version or runtime(s) for which the code should be compiled.
126
+ * If not set, defaults to the value of `engines.node` in your project's `package.json`.
127
+ *
128
+ * Accepts a single target (e.g., `'es2020'`, `'node18'`) or an array of targets.
129
+ *
130
+ * @see {@link https://tsdown.dev/guide/target#supported-targets} for a list of valid targets and more details.
131
+ *
132
+ * @example
133
+ * ```jsonc
134
+ * // Target a single environment
135
+ * { "target": "node18" }
136
+ * ```
137
+ *
138
+ * @example
139
+ * ```jsonc
140
+ * // Target multiple environments
141
+ * { "target": ["node18", "es2020"] }
142
+ * ```
143
+ */
113
144
  target?: string | string[];
114
145
  define?: Record<string, string>;
115
146
  /** @default false */
@@ -141,7 +172,7 @@ interface Options$3 {
141
172
  */
142
173
  onSuccess?: string | ((config: ResolvedOptions) => void | Promise<void>);
143
174
  /**
144
- * Skip bundling node_modules.
175
+ * Skip bundling `node_modules`.
145
176
  */
146
177
  skipNodeModulesBundle?: boolean;
147
178
  /**
@@ -183,15 +214,39 @@ interface Options$3 {
183
214
  * ```
184
215
  */
185
216
  env?: Record<string, any>;
217
+ /**
218
+ * @deprecated Alias for `copy`, will be removed in the future.
219
+ */
220
+ publicDir?: CopyOptions | CopyOptionsFn;
221
+ /**
222
+ * Copy files to another directory.
223
+ * @example
224
+ * ```ts
225
+ * [
226
+ * 'src/assets',
227
+ * { from: 'src/assets', to: 'dist/assets' },
228
+ * ]
229
+ * ```
230
+ */
231
+ copy?: CopyOptions | CopyOptionsFn;
186
232
  hooks?: Partial<TsdownHooks> | ((hooks: Hookable<TsdownHooks>) => Awaitable<void>);
233
+ /**
234
+ * If enabled, strips the `node:` protocol prefix from import source.
235
+ *
236
+ * @default false
237
+ *
238
+ * @example
239
+ * // With removeNodeProtocol enabled:
240
+ * import('node:fs'); // becomes import('fs')
241
+ */
242
+ removeNodeProtocol?: boolean;
187
243
  }
188
-
189
244
  /**
190
245
  * Options without specifying config file path.
191
246
  */
192
247
  type UserConfig = Arrayable<Omit<Options$3, "config">>;
193
248
  type UserConfigFn = (cliOptions: Options$3) => Awaitable<UserConfig>;
194
- type ResolvedOptions = Omit<Overwrite<MarkPartial<Options$3, "globalName" | "inputOptions" | "outputOptions" | "minify" | "define" | "alias" | "external" | "noExternal" | "onSuccess" | "fixedExtension" | "outExtensions" | "hooks">, {
249
+ type ResolvedOptions = Omit<Overwrite<MarkPartial<Omit<Options$3, "publicDir">, "globalName" | "inputOptions" | "outputOptions" | "minify" | "define" | "alias" | "external" | "noExternal" | "onSuccess" | "fixedExtension" | "outExtensions" | "hooks" | "removeNodeProtocol" | "copy">, {
195
250
  format: NormalizedFormat[];
196
251
  target?: string[];
197
252
  clean: string[];
@@ -0,0 +1,5 @@
1
+ //#region package.json
2
+ var version = "0.11.0-beta.1";
3
+
4
+ //#endregion
5
+ export { version };
@@ -1,8 +1,9 @@
1
- import { logger, noop, resolveComma, toArray } from "./general-C06aMSSY.js";
1
+ import { logger } from "./logger-DKXLpcNj.js";
2
+ import { noop, resolveComma, toArray } from "./general-nv5tYplM.js";
2
3
  import path, { dirname, normalize, sep } from "node:path";
3
4
  import { blue, bold, dim, green, underline, yellow } from "ansis";
4
5
  import Debug from "debug";
5
- import { access, chmod, readFile, rm } from "node:fs/promises";
6
+ import { access, chmod, cp, readFile, rm, stat } from "node:fs/promises";
6
7
  import { up } from "empathic/package";
7
8
  import { Buffer } from "node:buffer";
8
9
  import { promisify } from "node:util";
@@ -12,12 +13,21 @@ import { brotliCompress, gzip } from "node:zlib";
12
13
  function fsExists(path$1) {
13
14
  return access(path$1).then(() => true, () => false);
14
15
  }
16
+ function fsStat(path$1) {
17
+ return stat(path$1).catch(() => null);
18
+ }
15
19
  function fsRemove(path$1) {
16
20
  return rm(path$1, {
17
21
  force: true,
18
22
  recursive: true
19
23
  }).catch(() => {});
20
24
  }
25
+ function fsCopy(from, to) {
26
+ return cp(from, to, {
27
+ recursive: true,
28
+ force: true
29
+ });
30
+ }
21
31
  function lowestCommonAncestor(...filepaths) {
22
32
  if (filepaths.length === 0) return "";
23
33
  if (filepaths.length === 1) return dirname(filepaths[0]);
@@ -77,6 +87,28 @@ function getProductionDeps(pkg) {
77
87
  return new Set([...Object.keys(pkg.dependencies || {}), ...Object.keys(pkg.peerDependencies || {})]);
78
88
  }
79
89
 
90
+ //#endregion
91
+ //#region src/features/node-protocol.ts
92
+ /**
93
+ * The `node:` protocol was added in Node.js v14.18.0.
94
+ * @see https://nodejs.org/api/esm.html#node-imports
95
+ */
96
+ function NodeProtocolPlugin() {
97
+ return {
98
+ name: "tsdown:node-protocol",
99
+ resolveId: {
100
+ filter: { id: /^node:/ },
101
+ handler(id) {
102
+ return {
103
+ id: id.slice(5),
104
+ external: true,
105
+ moduleSideEffects: false
106
+ };
107
+ }
108
+ }
109
+ };
110
+ }
111
+
80
112
  //#endregion
81
113
  //#region src/utils/package.ts
82
114
  const debug$1 = Debug("tsdown:package");
@@ -222,4 +254,4 @@ function ShebangPlugin(cwd) {
222
254
  }
223
255
 
224
256
  //#endregion
225
- export { ExternalPlugin, ReportPlugin, ShebangPlugin, fsExists, fsRemove, getPackageType, lowestCommonAncestor, normalizeFormat, prettyFormat, readPackageJson };
257
+ export { ExternalPlugin, NodeProtocolPlugin, ReportPlugin, ShebangPlugin, fsCopy, fsRemove, fsStat, getPackageType, lowestCommonAncestor, normalizeFormat, prettyFormat, readPackageJson };
package/dist/plugins.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { ReportPlugin$1 as ReportPlugin, ResolvedOptions } from "./options.d--a1aWVL6.js";
1
+ import { ReportPlugin$1 as ReportPlugin, ResolvedOptions } from "./options.d-BLasdguL.js";
2
2
  import { Plugin } from "rolldown";
3
3
  import { PackageJson } from "pkg-types";
4
4
 
@@ -10,4 +10,12 @@ declare function ExternalPlugin(options: ResolvedOptions): Plugin;
10
10
  declare function ShebangPlugin(cwd: string): Plugin;
11
11
 
12
12
  //#endregion
13
- export { ExternalPlugin, ReportPlugin, ShebangPlugin };
13
+ //#region src/features/node-protocol.d.ts
14
+ /**
15
+ * The `node:` protocol was added in Node.js v14.18.0.
16
+ * @see https://nodejs.org/api/esm.html#node-imports
17
+ */
18
+ declare function NodeProtocolPlugin(): Plugin;
19
+
20
+ //#endregion
21
+ export { ExternalPlugin, NodeProtocolPlugin, ReportPlugin, ShebangPlugin };
package/dist/plugins.js CHANGED
@@ -1,4 +1,5 @@
1
- import { ExternalPlugin, ReportPlugin, ShebangPlugin } from "./plugins-DX6CtlR1.js";
2
- import "./general-C06aMSSY.js";
1
+ import { ExternalPlugin, NodeProtocolPlugin, ReportPlugin, ShebangPlugin } from "./plugins-xuho_Cqn.js";
2
+ import "./logger-DKXLpcNj.js";
3
+ import "./general-nv5tYplM.js";
3
4
 
4
- export { ExternalPlugin, ReportPlugin, ShebangPlugin };
5
+ export { ExternalPlugin, NodeProtocolPlugin, ReportPlugin, ShebangPlugin };
package/dist/run.js CHANGED
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env node
2
- import { logger, resolveComma, setSilent, toArray } from "./general-C06aMSSY.js";
3
- import { version } from "./package-DfgxaSyP.js";
2
+ import { logger } from "./logger-DKXLpcNj.js";
3
+ import { resolveComma, toArray } from "./general-nv5tYplM.js";
4
+ import { version } from "./package-BqZXvp6d.js";
4
5
  import process from "node:process";
5
6
  import { dim } from "ansis";
6
7
  import Debug from "debug";
@@ -11,15 +12,15 @@ import { cac } from "cac";
11
12
  //#region src/cli.ts
12
13
  const cli = cac("tsdown");
13
14
  cli.help().version(version);
14
- cli.command("[...files]", "Bundle files", { ignoreOptionDefaultValue: true }).option("-c, --config <filename>", "Use a custom config file").option("--no-config", "Disable config file").option("--format <format>", "Bundle format: esm, cjs, iife", { default: "esm" }).option("--clean", "Clean output directory").option("--external <module>", "Mark dependencies as external").option("--minify", "Minify output").option("--debug [scope]", "Show debug logs").option("--target <target>", "Bundle target, e.g \"es2015\", \"esnext\"").option("--silent", "Suppress non-error logs").option("-d, --out-dir <dir>", "Output directory", { default: "dist" }).option("--treeshake", "Tree-shake bundle", { default: true }).option("--sourcemap", "Generate source map", { default: false }).option("--shims", "Enable cjs and esm shims ", { default: false }).option("--platform <platform>", "Target platform", { default: "node" }).option("--dts", "Generate dts files").option("--publint", "Enable publint", { default: false }).option("--unused", "Enable unused dependencies check", { default: false }).option("-w, --watch [path]", "Watch mode").option("--from-vite [vitest]", "Reuse config from Vite or Vitest").option("--report", "Size report", { default: true }).option("--env.* <value>", "Define compile-time env variables").action(async (input, flags) => {
15
- setSilent(!!flags.silent);
15
+ cli.command("[...files]", "Bundle files", { ignoreOptionDefaultValue: true }).option("-c, --config <filename>", "Use a custom config file").option("--no-config", "Disable config file").option("--format <format>", "Bundle format: esm, cjs, iife", { default: "esm" }).option("--clean", "Clean output directory").option("--external <module>", "Mark dependencies as external").option("--minify", "Minify output").option("--debug [scope]", "Show debug logs").option("--target <target>", "Bundle target, e.g \"es2015\", \"esnext\"").option("--silent", "Suppress non-error logs").option("-d, --out-dir <dir>", "Output directory", { default: "dist" }).option("--treeshake", "Tree-shake bundle", { default: true }).option("--sourcemap", "Generate source map", { default: false }).option("--shims", "Enable cjs and esm shims ", { default: false }).option("--platform <platform>", "Target platform", { default: "node" }).option("--dts", "Generate dts files").option("--publint", "Enable publint", { default: false }).option("--unused", "Enable unused dependencies check", { default: false }).option("-w, --watch [path]", "Watch mode").option("--from-vite [vitest]", "Reuse config from Vite or Vitest").option("--report", "Size report", { default: true }).option("--env.* <value>", "Define compile-time env variables").option("--on-success <command>", "Command to run on success").option("--copy <dir>", "Copy files to output dir").option("--public-dir <dir>", "Alias for --copy, deprecated").option("--tsconfig <tsconfig>", "Set tsconfig path").action(async (input, flags) => {
16
+ logger.setSilent(!!flags.silent);
16
17
  logger.info(`tsdown ${dim`v${version}`} powered by rolldown ${dim`v${VERSION}`}`);
17
18
  const { build: build$1 } = await import("./index.js");
18
19
  if (input.length > 0) flags.entry = input;
19
20
  await build$1(flags);
20
21
  });
21
22
  cli.command("migrate", "Migrate from tsup to tsdown").option("-c, --cwd <dir>", "Working directory").option("-d, --dry-run", "Dry run").action(async (args) => {
22
- const { migrate } = await import("./migrate-CowIU0R_.js");
23
+ const { migrate } = await import("./migrate-xZ5d7bv9.js");
23
24
  await migrate(args);
24
25
  });
25
26
  async function runCLI() {
@@ -36,7 +37,7 @@ async function runCLI() {
36
37
  try {
37
38
  await cli.runMatchedCommand();
38
39
  } catch (error) {
39
- logger.fatal(error);
40
+ logger.error(error);
40
41
  process.exit(1);
41
42
  }
42
43
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tsdown",
3
- "version": "0.10.1",
3
+ "version": "0.11.0-beta.1",
4
4
  "description": "The Elegant Bundler for Libraries",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -43,12 +43,16 @@
43
43
  },
44
44
  "peerDependencies": {
45
45
  "publint": "^0.3.0",
46
+ "unplugin-lightningcss": "^0.3.3",
46
47
  "unplugin-unused": "^0.4.0"
47
48
  },
48
49
  "peerDependenciesMeta": {
49
50
  "publint": {
50
51
  "optional": true
51
52
  },
53
+ "unplugin-lightningcss": {
54
+ "optional": true
55
+ },
52
56
  "unplugin-unused": {
53
57
  "optional": true
54
58
  }
@@ -57,48 +61,49 @@
57
61
  "ansis": "^3.17.0",
58
62
  "cac": "^6.7.14",
59
63
  "chokidar": "^4.0.3",
60
- "consola": "^3.4.2",
61
64
  "debug": "^4.4.0",
62
65
  "diff": "^7.0.0",
63
66
  "empathic": "^1.0.0",
64
67
  "hookable": "^5.5.3",
65
- "lightningcss": "^1.29.3",
66
68
  "rolldown": "1.0.0-beta.8-commit.852c603",
67
- "rolldown-plugin-dts": "^0.9.5",
69
+ "rolldown-plugin-dts": "^0.9.7",
70
+ "semver": "^7.7.1",
68
71
  "tinyexec": "^1.0.1",
69
72
  "tinyglobby": "^0.2.13",
70
- "unconfig": "^7.3.2",
71
- "unplugin-lightningcss": "^0.3.3"
73
+ "unconfig": "^7.3.2"
72
74
  },
73
75
  "devDependencies": {
74
- "@sxzz/eslint-config": "^6.1.2",
76
+ "@sxzz/eslint-config": "^6.2.0",
75
77
  "@sxzz/prettier-config": "^2.2.1",
76
78
  "@sxzz/test-utils": "^0.5.5",
77
79
  "@types/debug": "^4.1.12",
78
80
  "@types/diff": "^7.0.2",
79
- "@types/node": "^22.15.2",
81
+ "@types/node": "^22.15.3",
82
+ "@types/semver": "^7.7.0",
80
83
  "@unocss/eslint-plugin": "^66.1.0-beta.12",
81
84
  "bumpp": "^10.1.0",
82
85
  "eslint": "^9.25.1",
86
+ "lightningcss": "^1.29.3",
83
87
  "pkg-types": "^2.1.0",
84
88
  "prettier": "^3.5.3",
85
89
  "publint": "^0.3.12",
86
90
  "tsup": "^8.4.0",
87
- "tsx": "^4.19.3",
91
+ "tsx": "^4.19.4",
88
92
  "typedoc": "^0.28.3",
89
93
  "typedoc-plugin-markdown": "^4.6.3",
90
94
  "typescript": "~5.8.3",
91
95
  "unocss": "^66.1.0-beta.12",
96
+ "unplugin-lightningcss": "^0.3.3",
92
97
  "unplugin-unused": "^0.4.4",
93
98
  "vite": "^6.3.3",
94
99
  "vitepress": "^1.6.3",
95
100
  "vitepress-plugin-group-icons": "^1.5.2",
96
- "vitepress-plugin-llms": "^1.1.0",
101
+ "vitepress-plugin-llms": "^1.1.1",
97
102
  "vitest": "^3.1.2",
98
103
  "vue": "^3.5.13"
99
104
  },
100
105
  "engines": {
101
- "node": ">=18.0.0"
106
+ "node": ">=20.18.0"
102
107
  },
103
108
  "prettier": "@sxzz/prettier-config",
104
109
  "scripts": {
@@ -1,5 +0,0 @@
1
- //#region package.json
2
- var version = "0.10.1";
3
-
4
- //#endregion
5
- export { version };