tsdown 0.16.8 → 0.17.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import { f as UserConfig, m as UserConfigFn, p as UserConfigExport } from "./index-k1oOp_n4.mjs";
1
+ import { f as UserConfig, m as UserConfigFn, p as UserConfigExport } from "./index-C9klZ7SZ.mjs";
2
2
 
3
3
  //#region src/config.d.ts
4
4
 
package/dist/config.d.mts CHANGED
@@ -1,3 +1,3 @@
1
- import { f as UserConfig, m as UserConfigFn, p as UserConfigExport } from "./index-k1oOp_n4.mjs";
2
- import { t as defineConfig } from "./config-qCTuQ4uL.mjs";
1
+ import { f as UserConfig, m as UserConfigFn, p as UserConfigExport } from "./index-C9klZ7SZ.mjs";
2
+ import { t as defineConfig } from "./config-LvwttpKK.mjs";
3
3
  export { UserConfig, UserConfigExport, UserConfigFn, defineConfig };
@@ -426,7 +426,7 @@ interface UserConfig {
426
426
  logLevel?: LogLevel;
427
427
  /**
428
428
  * If true, fails the build on warnings.
429
- * @default false
429
+ * @default 'ci-only'
430
430
  */
431
431
  failOnWarn?: boolean | CIOption;
432
432
  /**
@@ -442,6 +442,9 @@ interface UserConfig {
442
442
  * @default false
443
443
  */
444
444
  watch?: boolean | Arrayable<string>;
445
+ /**
446
+ * Files or patterns to not watch while in watch mode.
447
+ */
445
448
  ignoreWatch?: Arrayable<string | RegExp>;
446
449
  /**
447
450
  * You can specify command to be executed after a successful build, specially useful for Watch mode
package/dist/index.d.mts CHANGED
@@ -1,14 +1,14 @@
1
- import { A as TsdownHooks, C as ChunkAddonObject, D as PackageType, E as OutExtensionObject, F as CopyOptions, I as CopyOptionsFn, L as AttwOptions, M as TsdownChunks, N as DebugOptions, O as BuildContext, P as CopyEntry, S as ChunkAddonFunction, T as OutExtensionFactory, _ as ReportOptions, a as NoExternalFn, b as globalLogger, c as ResolvedConfig, d as UnusedOptions, f as UserConfig, g as Workspace, h as WithEnabled, i as InlineConfig, j as ExportsOptions, k as RolldownContext, l as Sourcemap, m as UserConfigFn, n as DtsOptions, o as NormalizedFormat, p as UserConfigExport, r as Format, s as PublintOptions, t as CIOption, u as TreeshakingOptions, w as OutExtensionContext, x as ChunkAddon, y as Logger } from "./index-k1oOp_n4.mjs";
2
- import { t as defineConfig } from "./config-qCTuQ4uL.mjs";
1
+ import { A as TsdownHooks, C as ChunkAddonObject, D as PackageType, E as OutExtensionObject, F as CopyOptions, I as CopyOptionsFn, L as AttwOptions, M as TsdownChunks, N as DebugOptions, O as BuildContext, P as CopyEntry, S as ChunkAddonFunction, T as OutExtensionFactory, _ as ReportOptions, a as NoExternalFn, b as globalLogger, c as ResolvedConfig, d as UnusedOptions, f as UserConfig, g as Workspace, h as WithEnabled, i as InlineConfig, j as ExportsOptions, k as RolldownContext, l as Sourcemap, m as UserConfigFn, n as DtsOptions, o as NormalizedFormat, p as UserConfigExport, r as Format, s as PublintOptions, t as CIOption, u as TreeshakingOptions, w as OutExtensionContext, x as ChunkAddon, y as Logger } from "./index-C9klZ7SZ.mjs";
2
+ import { t as defineConfig } from "./config-LvwttpKK.mjs";
3
3
 
4
4
  //#region src/index.d.ts
5
-
5
+ interface TsdownBundle extends AsyncDisposable {
6
+ chunks: TsdownChunks;
7
+ }
6
8
  /**
7
9
  * Build with tsdown.
8
10
  */
9
- declare function build(userOptions?: InlineConfig): Promise<void>;
10
- /** @internal */
11
- declare const shimFile: string;
11
+ declare function build(userOptions?: InlineConfig): Promise<TsdownBundle[]>;
12
12
  /**
13
13
  * Build a single configuration, without watch and shortcuts features.
14
14
  *
@@ -17,6 +17,8 @@ declare const shimFile: string;
17
17
  * @private
18
18
  * @param config Resolved options
19
19
  */
20
- declare function buildSingle(config: ResolvedConfig, clean: () => Promise<void>): Promise<(() => Promise<void>) | undefined>;
20
+ declare function buildSingle(config: ResolvedConfig, configFiles: string[], clean: () => Promise<void>, restart: () => void): Promise<TsdownBundle>;
21
+ /** @internal */
22
+ declare const shimFile: string;
21
23
  //#endregion
22
- export { AttwOptions, BuildContext, CIOption, ChunkAddon, ChunkAddonFunction, ChunkAddonObject, CopyEntry, CopyOptions, CopyOptionsFn, DebugOptions, DtsOptions, ExportsOptions, Format, InlineConfig, type Logger, NoExternalFn, NormalizedFormat, OutExtensionContext, OutExtensionFactory, OutExtensionObject, PackageType, PublintOptions, ReportOptions, ResolvedConfig, RolldownContext, Sourcemap, TreeshakingOptions, TsdownChunks, TsdownHooks, UnusedOptions, UserConfig, UserConfigExport, UserConfigFn, WithEnabled, Workspace, build, buildSingle, defineConfig, globalLogger, shimFile };
24
+ export { AttwOptions, BuildContext, CIOption, ChunkAddon, ChunkAddonFunction, ChunkAddonObject, CopyEntry, CopyOptions, CopyOptionsFn, DebugOptions, DtsOptions, ExportsOptions, Format, InlineConfig, type Logger, NoExternalFn, NormalizedFormat, OutExtensionContext, OutExtensionFactory, OutExtensionObject, PackageType, PublintOptions, ReportOptions, ResolvedConfig, RolldownContext, Sourcemap, TreeshakingOptions, TsdownBundle, TsdownChunks, TsdownHooks, UnusedOptions, UserConfig, UserConfigExport, UserConfigFn, WithEnabled, Workspace, build, buildSingle, defineConfig, globalLogger, shimFile };
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { t as defineConfig } from "./config-DLSWqKoz.mjs";
2
- import { n as buildSingle, r as shimFile, t as build } from "./src-EBZO44R8.mjs";
3
- import { a as globalLogger } from "./package-BDAjF-Kz.mjs";
2
+ import { n as buildSingle, r as shimFile, t as build } from "./src-Cky32-M_.mjs";
3
+ import { a as globalLogger } from "./package-CMsW8X66.mjs";
4
4
 
5
5
  export { build, buildSingle, defineConfig, globalLogger, shimFile };
@@ -15,16 +15,6 @@ function resolveRegex(str) {
15
15
  if (typeof str === "string" && str.length > 2 && str[0] === "/" && str.at(-1) === "/") return new RegExp(str.slice(1, -1));
16
16
  return str;
17
17
  }
18
- function debounce(fn, wait) {
19
- let timeout;
20
- return function(...args) {
21
- if (timeout) clearTimeout(timeout);
22
- timeout = setTimeout(() => {
23
- timeout = void 0;
24
- fn.apply(this, args);
25
- }, wait);
26
- };
27
- }
28
18
  function slash(string) {
29
19
  return string.replaceAll("\\", "/");
30
20
  }
@@ -160,7 +150,7 @@ function hue2rgb(p, q, t) {
160
150
 
161
151
  //#endregion
162
152
  //#region package.json
163
- var version = "0.16.8";
153
+ var version = "0.17.0-beta.2";
164
154
 
165
155
  //#endregion
166
- export { globalLogger as a, debounce as c, noop as d, pkgExists as f, toArray as g, slash as h, generateColor as i, importWithError as l, resolveRegex as m, LogLevels as n, prettyFormat as o, resolveComma as p, createLogger as r, prettyName as s, version as t, matchPattern as u };
156
+ export { globalLogger as a, importWithError as c, pkgExists as d, resolveComma as f, toArray as h, generateColor as i, matchPattern as l, slash as m, LogLevels as n, prettyFormat as o, resolveRegex as p, createLogger as r, prettyName as s, version as t, noop as u };
@@ -1,4 +1,4 @@
1
- import { c as ResolvedConfig, v as ReportPlugin, y as Logger } from "./index-k1oOp_n4.mjs";
1
+ import { c as ResolvedConfig, v as ReportPlugin, y as Logger } from "./index-C9klZ7SZ.mjs";
2
2
  import { Plugin } from "rolldown";
3
3
 
4
4
  //#region src/features/external.d.ts
package/dist/plugins.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import "./config-DLSWqKoz.mjs";
2
- import { a as ReportPlugin, i as ShebangPlugin, o as NodeProtocolPlugin, s as ExternalPlugin } from "./src-EBZO44R8.mjs";
3
- import "./package-BDAjF-Kz.mjs";
2
+ import { a as ReportPlugin, i as ShebangPlugin, o as NodeProtocolPlugin, s as ExternalPlugin } from "./src-Cky32-M_.mjs";
3
+ import "./package-CMsW8X66.mjs";
4
4
 
5
5
  export { ExternalPlugin, NodeProtocolPlugin, ReportPlugin, ShebangPlugin };
package/dist/run.mjs CHANGED
@@ -1,10 +1,11 @@
1
1
  #!/usr/bin/env node
2
- import { a as globalLogger, g as toArray, p as resolveComma, t as version } from "./package-BDAjF-Kz.mjs";
2
+ import { a as globalLogger, f as resolveComma, h as toArray, t as version } from "./package-CMsW8X66.mjs";
3
3
  import module from "node:module";
4
- import process from "node:process";
5
4
  import { dim } from "ansis";
6
5
  import { VERSION } from "rolldown";
6
+ import process from "node:process";
7
7
  import { createDebug, enable, namespaces } from "obug";
8
+ import { x } from "tinyexec";
8
9
  import { cac } from "cac";
9
10
 
10
11
  //#region src/features/debug.ts
@@ -35,9 +36,23 @@ cli.command("[...files]", "Bundle files", {
35
36
  if (input.length > 0) flags.entry = input;
36
37
  await build$1(flags);
37
38
  });
38
- cli.command("migrate", "Migrate from tsup to tsdown").option("-c, --cwd <dir>", "Working directory").option("-d, --dry-run", "Dry run").action(async (args) => {
39
- const { migrate } = await import("./migrate-nFQ0dxbr.mjs");
40
- await migrate(args);
39
+ cli.command("create", "[deprecated] Create a tsdown project. Use \"npx create-tsdown\" instead.", { allowUnknownOptions: true }).action(async () => {
40
+ globalLogger.warn(`"tsdown create" is deprecated. Please use "npx create-tsdown" instead.`);
41
+ const { exitCode } = await x("npx", [
42
+ "-y",
43
+ "create-tsdown@latest",
44
+ ...process.argv.slice(3)
45
+ ], { nodeOptions: { stdio: "inherit" } });
46
+ process.exitCode = exitCode;
47
+ });
48
+ cli.command("migrate", "[deprecated] Migrate from tsup to tsdown. Use \"npx tsdown-migrate\" instead.", { allowUnknownOptions: true }).action(async () => {
49
+ globalLogger.warn(`"tsdown migrate" is deprecated. Please use "npx tsdown-migrate" instead.`);
50
+ const { exitCode } = await x("npx", [
51
+ "-y",
52
+ "tsdown-migrate@latest",
53
+ ...process.argv.slice(3)
54
+ ], { nodeOptions: { stdio: "inherit" } });
55
+ process.exitCode = exitCode;
41
56
  });
42
57
  async function runCLI() {
43
58
  cli.parse(process.argv, { run: false });
@@ -1,15 +1,13 @@
1
1
  import { createRequire as __cjs_createRequire } from "node:module";
2
2
  const __cjs_require = __cjs_createRequire(import.meta.url);
3
- import { a as globalLogger, c as debounce, d as noop, f as pkgExists, g as toArray, h as slash, i as generateColor, l as importWithError, m as resolveRegex, n as LogLevels, o as prettyFormat, p as resolveComma, r as createLogger, s as prettyName, t as version, u as matchPattern } from "./package-BDAjF-Kz.mjs";
3
+ import { a as globalLogger, c as importWithError, d as pkgExists, f as resolveComma, h as toArray, i as generateColor, l as matchPattern, m as slash, n as LogLevels, o as prettyFormat, p as resolveRegex, r as createLogger, s as prettyName, t as version, u as noop } from "./package-CMsW8X66.mjs";
4
4
  import { builtinModules, isBuiltin } from "node:module";
5
5
  import path, { dirname, join, normalize, sep } from "node:path";
6
- import process, { env } from "node:process";
7
6
  import { fileURLToPath, pathToFileURL } from "node:url";
8
7
  import { blue, bold, dim, green, underline } from "ansis";
9
- import { VERSION, build } from "rolldown";
10
- import { exec } from "tinyexec";
11
- const treeKill = __cjs_require("tree-kill");
8
+ import { VERSION, build, watch } from "rolldown";
12
9
  import { access, chmod, cp, mkdtemp, readFile, rm, stat, writeFile } from "node:fs/promises";
10
+ import process, { env } from "node:process";
13
11
  import { createDebug } from "obug";
14
12
  import { createConfigCoreLoader } from "unconfig-core";
15
13
  import { glob, isDynamicPattern } from "tinyglobby";
@@ -18,15 +16,16 @@ const minVersion = __cjs_require("semver/ranges/min-version.js");
18
16
  import { up } from "empathic/find";
19
17
  import { up as up$1 } from "empathic/package";
20
18
  import { tmpdir } from "node:os";
19
+ import { exec } from "tinyexec";
21
20
  const coerce = __cjs_require("semver/functions/coerce.js");
22
21
  const satisfies = __cjs_require("semver/functions/satisfies.js");
23
22
  import { createHooks } from "hookable";
23
+ const treeKill = __cjs_require("tree-kill");
24
24
  import util, { promisify } from "node:util";
25
25
  import { importGlobPlugin } from "rolldown/experimental";
26
26
  import { Buffer } from "node:buffer";
27
27
  import { brotliCompress, gzip } from "node:zlib";
28
28
  import readline from "node:readline";
29
- import { globalContext, invalidateContextFile } from "rolldown-plugin-dts/tsc-context";
30
29
 
31
30
  //#region node_modules/.pnpm/is-in-ci@2.0.0/node_modules/is-in-ci/index.js
32
31
  const check = (key) => key in env && env[key] !== "0" && env[key] !== "false";
@@ -107,9 +106,9 @@ async function loadViteConfig(prefix, cwd, configLoader) {
107
106
  return resolved;
108
107
  }
109
108
  const configPrefix = "tsdown.config";
110
- let isWatch = false;
111
- function setWatch() {
112
- isWatch = true;
109
+ let noCacheLoad = false;
110
+ function setNoCacheLoad() {
111
+ noCacheLoad = true;
113
112
  }
114
113
  async function loadConfigFile(inlineConfig, workspace) {
115
114
  let cwd = inlineConfig.cwd || process.cwd();
@@ -154,7 +153,7 @@ async function loadConfigFile(inlineConfig, workspace) {
154
153
  }],
155
154
  cwd,
156
155
  stopAt: workspace && path.dirname(workspace)
157
- }).load(isWatch);
156
+ }).load(noCacheLoad);
158
157
  let exported = [];
159
158
  let file;
160
159
  if (result) {
@@ -172,7 +171,7 @@ async function loadConfigFile(inlineConfig, workspace) {
172
171
  };
173
172
  }
174
173
  function resolveConfigLoader(configLoader = "auto") {
175
- if (isWatch) return "unrun";
174
+ if (noCacheLoad) return "unrun";
176
175
  else if (configLoader === "auto") return !!(process.features.typescript || process.versions.bun || process.versions.deno) ? "native" : "unrun";
177
176
  else return configLoader === "native" ? "native" : "unrun";
178
177
  }
@@ -234,6 +233,13 @@ function resolveClean(clean, outDir, cwd) {
234
233
  if (clean.some((item) => path.resolve(item) === cwd)) throw new Error("Cannot clean the current working directory. Please specify a different path to clean option.");
235
234
  return clean;
236
235
  }
236
+ async function cleanupChunks(outDir, chunks) {
237
+ await Promise.all(chunks.map(async (chunk) => {
238
+ const filePath = path.resolve(outDir, chunk.fileName);
239
+ debug$7("Removing chunk file", filePath);
240
+ await fsRemove(filePath);
241
+ }));
242
+ }
237
243
 
238
244
  //#endregion
239
245
  //#region src/features/entry.ts
@@ -268,6 +274,23 @@ async function toObjectEntry(entry, cwd) {
268
274
  }));
269
275
  }
270
276
 
277
+ //#endregion
278
+ //#region src/utils/format.ts
279
+ function formatBytes(bytes) {
280
+ if (bytes === Infinity) return void 0;
281
+ return `${(bytes / 1e3).toFixed(2)} kB`;
282
+ }
283
+ function detectIndentation(jsonText) {
284
+ const lines = jsonText.split(/\r?\n/);
285
+ for (const line of lines) {
286
+ const match = line.match(/^(\s+)\S/);
287
+ if (!match) continue;
288
+ if (match[1].includes(" ")) return " ";
289
+ return match[1].length;
290
+ }
291
+ return 2;
292
+ }
293
+
271
294
  //#endregion
272
295
  //#region src/features/exports.ts
273
296
  async function writeExports(options, chunks) {
@@ -285,20 +308,10 @@ async function writeExports(options, chunks) {
285
308
  updatedPkg.publishConfig.exports = publishExports;
286
309
  }
287
310
  const original = await readFile(pkg.packageJsonPath, "utf8");
288
- let contents = JSON.stringify(updatedPkg, null, detectIndent(original));
311
+ let contents = JSON.stringify(updatedPkg, null, detectIndentation(original));
289
312
  if (original.endsWith("\n")) contents += "\n";
290
313
  if (contents !== original) await writeFile(pkg.packageJsonPath, contents, "utf8");
291
314
  }
292
- function detectIndent(jsonText) {
293
- const lines = jsonText.split(/\r?\n/);
294
- for (const line of lines) {
295
- const match = line.match(/^(\s+)\S/);
296
- if (!match) continue;
297
- if (match[1].includes(" ")) return " ";
298
- return match[1].length;
299
- }
300
- return 2;
301
- }
302
315
  async function generateExports(pkg, outDir, chunks, { devExports, all, customExports }) {
303
316
  const pkgJsonPath = pkg.packageJsonPath;
304
317
  const pkgRoot$1 = path.dirname(pkgJsonPath);
@@ -566,7 +579,7 @@ async function resolveWorkspace(config, inlineConfig) {
566
579
  };
567
580
  }
568
581
  async function resolveUserConfig(userConfig, inlineConfig) {
569
- let { entry, format = ["es"], plugins = [], clean = true, silent = false, logLevel = silent ? "silent" : "info", failOnWarn = false, customLogger, treeshake = true, platform = "node", outDir = "dist", sourcemap = false, dts, unused = false, watch = false, ignoreWatch, shims = false, skipNodeModulesBundle = false, publint: publint$1 = false, attw: attw$1 = false, fromVite, alias, tsconfig, report = true, target, env: env$1 = {}, copy: copy$1, publicDir, hash = true, cwd = process.cwd(), name, workspace, external, noExternal, exports = false, bundle, unbundle = typeof bundle === "boolean" ? !bundle : false, removeNodeProtocol, nodeProtocol, cjsDefault = true, globImport = true, inlineOnly, fixedExtension = platform === "node", debug: debug$9 = false } = userConfig;
582
+ let { entry, format = ["es"], plugins = [], clean = true, silent = false, logLevel = silent ? "silent" : "info", failOnWarn = "ci-only", customLogger, treeshake = true, platform = "node", outDir = "dist", sourcemap = false, dts, unused = false, watch: watch$1 = false, ignoreWatch, shims = false, skipNodeModulesBundle = false, publint: publint$1 = false, attw: attw$1 = false, fromVite, alias, tsconfig, report = true, target, env: env$1 = {}, copy: copy$1, publicDir, hash = true, cwd = process.cwd(), name, workspace, external, noExternal, exports = false, bundle, unbundle = typeof bundle === "boolean" ? !bundle : false, removeNodeProtocol, nodeProtocol, cjsDefault = true, globImport = true, inlineOnly, fixedExtension = platform === "node", debug: debug$9 = false } = userConfig;
570
583
  const logger = createLogger(logLevel, {
571
584
  customLogger,
572
585
  failOnWarn: resolveFeatureOption(failOnWarn, true)
@@ -615,46 +628,49 @@ async function resolveUserConfig(userConfig, inlineConfig) {
615
628
  }
616
629
  if (inlineOnly != null) inlineOnly = toArray(inlineOnly);
617
630
  debug$9 = resolveFeatureOption(debug$9, {});
618
- if (debug$9) debug$9.devtools ??= !!pkgExists("@vitejs/devtools/cli");
631
+ if (debug$9) if (watch$1) {
632
+ if (debug$9.devtools) logger.warn("Devtools is not supported in watch mode, disabling it.");
633
+ debug$9.devtools = false;
634
+ } else debug$9.devtools ??= !!pkgExists("@vitejs/devtools/cli");
619
635
  return {
620
636
  ...userConfig,
637
+ alias,
638
+ attw: attw$1,
639
+ cjsDefault,
640
+ clean,
641
+ copy: publicDir || copy$1,
642
+ cwd,
643
+ debug: debug$9,
644
+ dts,
621
645
  entry,
622
- plugins,
646
+ env: env$1,
647
+ exports,
648
+ external,
649
+ fixedExtension,
623
650
  format: normalizeFormat(format),
624
- target,
625
- outDir,
626
- clean,
651
+ globImport,
652
+ hash,
653
+ ignoreWatch,
654
+ inlineOnly,
627
655
  logger,
628
- treeshake,
656
+ name,
657
+ nodeProtocol,
658
+ noExternal,
659
+ outDir,
660
+ pkg,
629
661
  platform,
630
- sourcemap,
631
- dts,
662
+ plugins,
663
+ publint: publint$1,
632
664
  report,
633
- unused,
634
- watch,
635
- ignoreWatch,
636
665
  shims,
637
666
  skipNodeModulesBundle,
638
- publint: publint$1,
639
- attw: attw$1,
640
- alias,
667
+ sourcemap,
668
+ target,
669
+ treeshake,
641
670
  tsconfig,
642
- cwd,
643
- env: env$1,
644
- pkg,
645
- copy: publicDir || copy$1,
646
- hash,
647
- name,
648
- external,
649
- noExternal,
650
- exports,
651
671
  unbundle,
652
- nodeProtocol,
653
- cjsDefault,
654
- globImport,
655
- inlineOnly,
656
- fixedExtension,
657
- debug: debug$9
672
+ unused,
673
+ watch: watch$1
658
674
  };
659
675
  }
660
676
  async function mergeUserOptions(defaults, user, args) {
@@ -695,11 +711,7 @@ async function attw(options) {
695
711
  options.logger.warn("attw is enabled but package.json is not found");
696
712
  return;
697
713
  }
698
- let { profile = "strict", level = "warn", ...attwOptions } = options.attw;
699
- if (profile === "esmOnly") {
700
- options.logger.warn("attw option \"esmOnly\" is deprecated, use \"esm-only\" instead");
701
- profile = "esm-only";
702
- }
714
+ const { profile = "strict", level = "warn", ...attwOptions } = options.attw;
703
715
  const t = performance.now();
704
716
  debug$4("Running attw check");
705
717
  const tempDir = await mkdtemp(path.join(tmpdir(), "tsdown-attw-"));
@@ -811,6 +823,23 @@ async function createHooks$1(options) {
811
823
  }
812
824
  };
813
825
  }
826
+ function executeOnSuccess(config) {
827
+ if (!config.onSuccess) return;
828
+ const ab = new AbortController();
829
+ if (typeof config.onSuccess === "string") {
830
+ const p = exec(config.onSuccess, [], { nodeOptions: {
831
+ shell: true,
832
+ stdio: "inherit"
833
+ } });
834
+ p.then(({ exitCode }) => {
835
+ if (exitCode) process.exitCode = exitCode;
836
+ });
837
+ ab.signal.addEventListener("abort", () => {
838
+ if (typeof p.pid === "number") treeKill(p.pid);
839
+ });
840
+ } else config.onSuccess(config, ab.signal);
841
+ return ab;
842
+ }
814
843
 
815
844
  //#endregion
816
845
  //#region src/features/publint.ts
@@ -1040,13 +1069,6 @@ function resolveChunkAddon(chunkAddon, format, dts) {
1040
1069
  };
1041
1070
  }
1042
1071
 
1043
- //#endregion
1044
- //#region src/utils/format.ts
1045
- function formatBytes(bytes) {
1046
- if (bytes === Infinity) return void 0;
1047
- return `${(bytes / 1e3).toFixed(2)} kB`;
1048
- }
1049
-
1050
1072
  //#endregion
1051
1073
  //#region src/features/report.ts
1052
1074
  const debug$1 = createDebug("tsdown:report");
@@ -1158,11 +1180,36 @@ function getShimsInject(format, platform) {
1158
1180
  };
1159
1181
  }
1160
1182
 
1183
+ //#endregion
1184
+ //#region src/features/watch.ts
1185
+ const endsWithConfig = /[\\/](?:tsdown\.config.*|tsconfig\.json)$/;
1186
+ function WatchPlugin(configFiles, { config, chunks }) {
1187
+ return {
1188
+ name: "tsdown:watch",
1189
+ options: config.ignoreWatch.length ? (inputOptions) => {
1190
+ inputOptions.watch ||= {};
1191
+ inputOptions.watch.exclude = toArray(inputOptions.watch.exclude);
1192
+ inputOptions.watch.exclude.push(...config.ignoreWatch);
1193
+ } : void 0,
1194
+ buildStart() {
1195
+ config.tsconfig && this.addWatchFile(config.tsconfig);
1196
+ for (const file of configFiles) this.addWatchFile(file);
1197
+ if (typeof config.watch !== "boolean") for (const file of resolveComma(toArray(config.watch))) this.addWatchFile(file);
1198
+ },
1199
+ generateBundle: {
1200
+ order: "post",
1201
+ handler(outputOptions, bundle) {
1202
+ chunks.push(...Object.values(bundle));
1203
+ }
1204
+ }
1205
+ };
1206
+ }
1207
+
1161
1208
  //#endregion
1162
1209
  //#region src/features/rolldown.ts
1163
1210
  const debug = createDebug("tsdown:rolldown");
1164
- async function getBuildOptions(config, format, isMultiFormat, cjsDts = false) {
1165
- const inputOptions = await resolveInputOptions(config, format, cjsDts, isMultiFormat);
1211
+ async function getBuildOptions(config, format, configFiles, watchContext, cjsDts = false, isMultiFormat) {
1212
+ const inputOptions = await resolveInputOptions(config, format, configFiles, watchContext, cjsDts, isMultiFormat);
1166
1213
  const outputOptions = await resolveOutputOptions(inputOptions, config, format, cjsDts);
1167
1214
  const rolldownConfig = {
1168
1215
  ...inputOptions,
@@ -1171,8 +1218,8 @@ async function getBuildOptions(config, format, isMultiFormat, cjsDts = false) {
1171
1218
  debug("rolldown config with format \"%s\" %O", cjsDts ? "cjs dts" : format, rolldownConfig);
1172
1219
  return rolldownConfig;
1173
1220
  }
1174
- async function resolveInputOptions(config, format, cjsDts, isMultiFormat) {
1175
- const { entry, external, plugins: userPlugins, platform, alias, treeshake, dts, unused, target, shims, tsconfig, cwd, report, env: env$1, nodeProtocol, loader, name, logger, cjsDefault, banner, footer, globImport, debug: debug$9 } = config;
1221
+ async function resolveInputOptions(config, format, configFiles, watchContext, cjsDts, isMultiFormat) {
1222
+ const { alias, banner, cjsDefault, cwd, debug: debug$9, dts, entry, env: env$1, external, footer, globImport, loader, logger, name, nodeProtocol, platform, plugins: userPlugins, report, shims, target, treeshake, tsconfig, unused, watch: watch$1 } = config;
1176
1223
  const plugins = [];
1177
1224
  if (nodeProtocol) plugins.push(NodeProtocolPlugin(nodeProtocol));
1178
1225
  if (config.pkg || config.skipNodeModulesBundle) plugins.push(ExternalPlugin(config));
@@ -1204,6 +1251,7 @@ async function resolveInputOptions(config, format, cjsDts, isMultiFormat) {
1204
1251
  if (globImport) plugins.push(importGlobPlugin());
1205
1252
  }
1206
1253
  if (report && LogLevels[logger.level] >= 3) plugins.push(ReportPlugin(report, logger, cwd, cjsDts, name, isMultiFormat));
1254
+ if (watch$1) plugins.push(WatchPlugin(configFiles, watchContext));
1207
1255
  if (!cjsDts) plugins.push(userPlugins);
1208
1256
  const define = {
1209
1257
  ...config.define,
@@ -1340,52 +1388,9 @@ function shortcuts(restart) {
1340
1388
  return () => rl.close();
1341
1389
  }
1342
1390
 
1343
- //#endregion
1344
- //#region src/features/watch.ts
1345
- const endsWithConfig = /[\\/](?:(?:package|tsconfig)\.json|pnpm-(?:workspace|lock)\.yaml|tsdown\.config.*)$/;
1346
- async function watchBuild(options, configFiles, rebuild, restart) {
1347
- if (typeof options.watch === "boolean" && options.outDir === options.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.`);
1348
- const files = toArray(typeof options.watch === "boolean" ? options.cwd : options.watch);
1349
- options.logger.info(`Watching for changes in ${files.join(", ")}`);
1350
- files.push(...configFiles);
1351
- const { watch } = await import("chokidar");
1352
- const debouncedOnChange = debounce(onChange, 100);
1353
- const watcher = watch(files, {
1354
- cwd: options.cwd,
1355
- ignoreInitial: true,
1356
- ignorePermissionErrors: true,
1357
- ignored: [
1358
- /[\\/]\.git[\\/]/,
1359
- RE_NODE_MODULES,
1360
- options.outDir,
1361
- ...options.ignoreWatch
1362
- ]
1363
- });
1364
- let pending = [];
1365
- let pendingPromise;
1366
- watcher.on("all", (type, file) => {
1367
- pending.push(path.resolve(options.cwd, file));
1368
- debouncedOnChange();
1369
- });
1370
- return watcher;
1371
- async function onChange() {
1372
- await pendingPromise;
1373
- if (!pending.length) return;
1374
- for (const file of pending) invalidateContextFile(globalContext, file);
1375
- if (pending.some((file) => configFiles.includes(file) || endsWithConfig.test(file))) {
1376
- options.logger.info(`Restarting due to config change...`);
1377
- pendingPromise = restart();
1378
- } else {
1379
- options.logger.info(`Change detected: ${pending.join(", ")}`);
1380
- pendingPromise = rebuild();
1381
- }
1382
- pending = [];
1383
- await pendingPromise;
1384
- }
1385
- }
1386
-
1387
1391
  //#endregion
1388
1392
  //#region src/index.ts
1393
+ const asyncDispose = Symbol.asyncDispose || Symbol.for("Symbol.asyncDispose");
1389
1394
  /**
1390
1395
  * Build with tsdown.
1391
1396
  */
@@ -1397,20 +1402,22 @@ async function build$1(userOptions = {}) {
1397
1402
  if (cleanPromise) return cleanPromise;
1398
1403
  return cleanPromise = cleanOutDir(configs);
1399
1404
  };
1400
- globalLogger.info("Build start");
1401
- const rebuilds = await Promise.all(configs.map((options) => buildSingle(options, clean)));
1402
1405
  const disposeCbs = [];
1403
- for (const [i, config] of configs.entries()) {
1404
- const rebuild = rebuilds[i];
1405
- if (!rebuild) continue;
1406
- setWatch();
1407
- const watcher = await watchBuild(config, configFiles, rebuild, restart);
1408
- disposeCbs.push(() => watcher.close());
1406
+ let restarting = false;
1407
+ async function restart() {
1408
+ if (restarting) return;
1409
+ restarting = true;
1410
+ await Promise.all(disposeCbs.map((cb) => cb()));
1411
+ setNoCacheLoad();
1412
+ build$1(userOptions);
1409
1413
  }
1410
- let firstDevtoolsConfig = configs.find((config) => config.debug && config.debug.devtools);
1411
- if (disposeCbs.length && firstDevtoolsConfig) {
1412
- globalLogger.warn("Devtools is not supported in watch mode, disabling it.");
1413
- firstDevtoolsConfig = void 0;
1414
+ globalLogger.info("Build start");
1415
+ const bundles = await Promise.all(configs.map((options) => buildSingle(options, configFiles, clean, restart)));
1416
+ const firstDevtoolsConfig = configs.find((config) => config.debug && config.debug.devtools);
1417
+ if (configs.some((config) => config.watch)) {
1418
+ disposeCbs.push(shortcuts(restart));
1419
+ for (const bundle of bundles) disposeCbs.push(bundle[asyncDispose]);
1420
+ return;
1414
1421
  }
1415
1422
  if (firstDevtoolsConfig) {
1416
1423
  const { start } = await importWithError("@vitejs/devtools/cli-commands");
@@ -1421,16 +1428,8 @@ async function build$1(userOptions = {}) {
1421
1428
  ...typeof devtoolsOptions === "object" ? devtoolsOptions : {}
1422
1429
  });
1423
1430
  }
1424
- if (disposeCbs.length) disposeCbs.push(shortcuts(restart));
1425
- async function restart() {
1426
- for (const dispose of disposeCbs) await dispose();
1427
- build$1(userOptions);
1428
- }
1431
+ return bundles;
1429
1432
  }
1430
- const dirname$1 = path.dirname(fileURLToPath(import.meta.url));
1431
- const pkgRoot = path.resolve(dirname$1, "..");
1432
- /** @internal */
1433
- const shimFile = path.resolve(pkgRoot, "esm-shims.js");
1434
1433
  /**
1435
1434
  * Build a single configuration, without watch and shortcuts features.
1436
1435
  *
@@ -1439,66 +1438,110 @@ const shimFile = path.resolve(pkgRoot, "esm-shims.js");
1439
1438
  * @private
1440
1439
  * @param config Resolved options
1441
1440
  */
1442
- async function buildSingle(config, clean) {
1443
- const { format: formats, dts, watch, onSuccess, logger } = config;
1444
- let ab;
1441
+ async function buildSingle(config, configFiles, clean, restart) {
1442
+ const { format: formats, dts, watch: watch$1, logger } = config;
1445
1443
  const { hooks, context } = await createHooks$1(config);
1446
1444
  warnLegacyCJS(config);
1447
- await rebuild(true);
1448
- if (watch) return () => rebuild();
1449
- async function rebuild(first) {
1450
- const startTime = performance.now();
1451
- await hooks.callHook("build:prepare", context);
1452
- ab?.abort();
1453
- if (first) await clean();
1454
- else await cleanOutDir([config]);
1455
- let hasErrors = false;
1456
- const isMultiFormat = formats.length > 1;
1457
- const chunks = {};
1458
- const debugRolldownDir = await getDebugRolldownDir();
1459
- await Promise.all(formats.map(async (format) => {
1460
- try {
1461
- const buildOptions = await getBuildOptions(config, format, isMultiFormat, false);
1462
- await hooks.callHook("build:before", {
1463
- ...context,
1464
- buildOptions
1465
- });
1466
- if (debugRolldownDir) await debugBuildOptions(debugRolldownDir, config.name, format, buildOptions);
1467
- const { output } = await build(buildOptions);
1468
- chunks[format] = output;
1469
- if (format === "cjs" && dts) {
1470
- const { output: output$1 } = await build(await getBuildOptions(config, format, isMultiFormat, true));
1471
- chunks[format].push(...output$1);
1472
- }
1473
- } catch (error) {
1474
- if (watch) {
1475
- logger.error(error);
1476
- hasErrors = true;
1477
- return;
1478
- }
1479
- throw error;
1445
+ const startTime = performance.now();
1446
+ await hooks.callHook("build:prepare", context);
1447
+ await clean();
1448
+ const debugRolldownConfigDir = await getDebugRolldownDir();
1449
+ const chunks = {};
1450
+ let watcher;
1451
+ const watchCtx = { config };
1452
+ let ab;
1453
+ const isMultiFormat = formats.length > 1;
1454
+ const configsByFormat = (await Promise.all(formats.map((format) => buildOptionsByFormat(format)))).flat();
1455
+ if (watch$1) {
1456
+ watcher = watch(configsByFormat.map((item) => item[1]));
1457
+ handleWatcher(watcher);
1458
+ } else {
1459
+ const outputs = await build(configsByFormat.map((item) => item[1]));
1460
+ for (const [i, output] of outputs.entries()) {
1461
+ const format = configsByFormat[i][0];
1462
+ chunks[format] ||= [];
1463
+ chunks[format].push(...output.output);
1464
+ }
1465
+ }
1466
+ if (!watch$1) {
1467
+ logger.success(prettyName(config.name), `Build complete in ${green(`${Math.round(performance.now() - startTime)}ms`)}`);
1468
+ await postBuild();
1469
+ }
1470
+ return {
1471
+ chunks,
1472
+ async [asyncDispose]() {
1473
+ ab?.abort();
1474
+ await watcher?.close();
1475
+ }
1476
+ };
1477
+ function handleWatcher(watcher$1) {
1478
+ const changedFile = [];
1479
+ let hasError = false;
1480
+ watcher$1.on("change", (id, event) => {
1481
+ if (event.event === "update") changedFile.push(id);
1482
+ if (configFiles.includes(id) || endsWithConfig.test(id)) {
1483
+ globalLogger.info(`Reload config: ${id}, restarting...`);
1484
+ restart();
1480
1485
  }
1481
- }));
1482
- if (hasErrors) return;
1486
+ });
1487
+ watcher$1.on("event", async (event) => {
1488
+ switch (event.code) {
1489
+ case "START":
1490
+ for (const format of formats) {
1491
+ await cleanupChunks(config.outDir, chunks[format]);
1492
+ chunks[format].length = 0;
1493
+ }
1494
+ hasError = false;
1495
+ break;
1496
+ case "END":
1497
+ if (!hasError) await postBuild();
1498
+ break;
1499
+ case "BUNDLE_START":
1500
+ if (changedFile.length > 0) {
1501
+ console.info("");
1502
+ logger.info(`Found ${bold(changedFile.join(", "))} changed, rebuilding...`);
1503
+ }
1504
+ changedFile.length = 0;
1505
+ break;
1506
+ case "BUNDLE_END":
1507
+ await event.result.close();
1508
+ logger.success(`Rebuilt in ${event.duration}ms.`);
1509
+ break;
1510
+ case "ERROR":
1511
+ await event.result.close();
1512
+ logger.error(event.error);
1513
+ hasError = true;
1514
+ break;
1515
+ }
1516
+ });
1517
+ }
1518
+ async function buildOptionsByFormat(format) {
1519
+ const watchContext = {
1520
+ ...watchCtx,
1521
+ chunks: chunks[format] = []
1522
+ };
1523
+ const buildOptions = await getBuildOptions(config, format, configFiles, watchContext, false, isMultiFormat);
1524
+ await hooks.callHook("build:before", {
1525
+ ...context,
1526
+ buildOptions
1527
+ });
1528
+ if (debugRolldownConfigDir) await debugBuildOptions(debugRolldownConfigDir, config.name, format, buildOptions);
1529
+ const configs = [[format, buildOptions]];
1530
+ if (format === "cjs" && dts) configs.push([format, await getBuildOptions(config, format, configFiles, watchContext, true, isMultiFormat)]);
1531
+ return configs;
1532
+ }
1533
+ async function postBuild() {
1483
1534
  await Promise.all([writeExports(config, chunks), copy(config)]);
1484
1535
  await Promise.all([publint(config), attw(config)]);
1485
1536
  await hooks.callHook("build:done", context);
1486
- logger.success(prettyName(config.name), `${first ? "Build" : "Rebuild"} complete in ${green(`${Math.round(performance.now() - startTime)}ms`)}`);
1487
- ab = new AbortController();
1488
- if (typeof onSuccess === "string") {
1489
- const p = exec(onSuccess, [], { nodeOptions: {
1490
- shell: true,
1491
- stdio: "inherit"
1492
- } });
1493
- p.then(({ exitCode }) => {
1494
- if (exitCode) process.exitCode = exitCode;
1495
- });
1496
- ab.signal.addEventListener("abort", () => {
1497
- if (typeof p.pid === "number") treeKill(p.pid);
1498
- });
1499
- } else await onSuccess?.(config, ab.signal);
1537
+ ab?.abort();
1538
+ ab = executeOnSuccess(config);
1500
1539
  }
1501
1540
  }
1541
+ const dirname$1 = path.dirname(fileURLToPath(import.meta.url));
1542
+ const pkgRoot = path.resolve(dirname$1, "..");
1543
+ /** @internal */
1544
+ const shimFile = path.resolve(pkgRoot, "esm-shims.js");
1502
1545
 
1503
1546
  //#endregion
1504
1547
  export { ReportPlugin as a, ShebangPlugin as i, buildSingle as n, NodeProtocolPlugin as o, shimFile as r, ExternalPlugin as s, build$1 as t };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tsdown",
3
- "version": "0.16.8",
3
+ "version": "0.17.0-beta.2",
4
4
  "description": "The Elegant Bundler for Libraries",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -75,8 +75,6 @@
75
75
  "dependencies": {
76
76
  "ansis": "^4.2.0",
77
77
  "cac": "^6.7.14",
78
- "chokidar": "^5.0.0",
79
- "diff": "^8.0.2",
80
78
  "empathic": "^2.0.0",
81
79
  "hookable": "^5.5.3",
82
80
  "obug": "^2.1.1",
@@ -87,17 +85,18 @@
87
85
  "tinyglobby": "^0.2.15",
88
86
  "tree-kill": "^1.2.2",
89
87
  "unconfig-core": "^7.4.1",
90
- "unrun": "^0.2.13"
88
+ "unrun": "^0.2.14"
91
89
  },
92
90
  "devDependencies": {
93
91
  "@arethetypeswrong/core": "^0.18.2",
94
- "@sxzz/eslint-config": "^7.3.2",
92
+ "@sxzz/eslint-config": "^7.4.0",
95
93
  "@sxzz/prettier-config": "^2.2.6",
96
94
  "@sxzz/test-utils": "^0.5.13",
97
95
  "@types/node": "^24.10.1",
98
96
  "@types/semver": "^7.7.1",
99
97
  "@unocss/eslint-plugin": "^66.5.9",
100
98
  "@vitejs/devtools": "^0.0.0-alpha.18",
99
+ "@vitest/coverage-v8": "4.0.14",
101
100
  "@vueuse/core": "^14.1.0",
102
101
  "bumpp": "^10.3.2",
103
102
  "eslint": "^9.39.1",
@@ -106,7 +105,7 @@
106
105
  "pkg-types": "^2.3.0",
107
106
  "prettier": "^3.7.1",
108
107
  "publint": "^0.3.15",
109
- "rolldown-plugin-require-cjs": "^0.3.1",
108
+ "rolldown-plugin-require-cjs": "^0.3.2",
110
109
  "typescript": "~5.9.3",
111
110
  "unocss": "^66.5.9",
112
111
  "unplugin-lightningcss": "^0.4.3",
@@ -1,118 +0,0 @@
1
- import { a as globalLogger, t as version } from "./package-BDAjF-Kz.mjs";
2
- import process from "node:process";
3
- import { bold, green, underline } from "ansis";
4
- import { readFile, unlink, writeFile } from "node:fs/promises";
5
- import { existsSync } from "node:fs";
6
- import { createInterface } from "node:readline/promises";
7
-
8
- //#region src/migrate.ts
9
- async function migrate({ cwd, dryRun }) {
10
- if (dryRun) globalLogger.info("Dry run enabled. No changes were made.");
11
- else {
12
- const rl = createInterface({
13
- input: process.stdin,
14
- output: process.stdout
15
- });
16
- globalLogger.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.`);
17
- const input = await rl.question(bold`Continue? (Y/n) `);
18
- rl.close();
19
- if (!(input.toLowerCase() === "y" || input === "")) {
20
- globalLogger.error("Migration cancelled.");
21
- process.exitCode = 1;
22
- return;
23
- }
24
- }
25
- if (cwd) process.chdir(cwd);
26
- let migrated = await migratePackageJson(dryRun);
27
- if (await migrateTsupConfig(dryRun)) migrated = true;
28
- if (migrated) globalLogger.success("Migration completed. Remember to run install command with your package manager.");
29
- else {
30
- globalLogger.error("No migration performed.");
31
- process.exitCode = 1;
32
- }
33
- }
34
- const DEP_FIELDS = {
35
- dependencies: `^${version}`,
36
- devDependencies: `^${version}`,
37
- peerDependencies: "*"
38
- };
39
- async function migratePackageJson(dryRun) {
40
- if (!existsSync("package.json")) {
41
- globalLogger.error("No package.json found");
42
- return false;
43
- }
44
- const pkgRaw = await readFile("package.json", "utf8");
45
- let pkg = JSON.parse(pkgRaw);
46
- let found = false;
47
- for (const [field, semver] of Object.entries(DEP_FIELDS)) if (pkg[field]?.tsup) {
48
- globalLogger.info(`Migrating \`${field}\` to tsdown.`);
49
- found = true;
50
- pkg[field] = renameKey(pkg[field], "tsup", "tsdown", semver);
51
- }
52
- if (pkg.scripts) {
53
- for (const key of Object.keys(pkg.scripts)) if (pkg.scripts[key].includes("tsup")) {
54
- globalLogger.info(`Migrating \`${key}\` script to tsdown`);
55
- found = true;
56
- pkg.scripts[key] = pkg.scripts[key].replaceAll(/tsup(?:-node)?/g, "tsdown");
57
- }
58
- }
59
- if (pkg.tsup) {
60
- globalLogger.info("Migrating `tsup` field in package.json to `tsdown`.");
61
- found = true;
62
- pkg = renameKey(pkg, "tsup", "tsdown");
63
- }
64
- if (!found) {
65
- globalLogger.warn("No tsup-related fields found in package.json");
66
- return false;
67
- }
68
- const pkgStr = `${JSON.stringify(pkg, null, pkgRaw.includes(" ") ? " " : 2)}\n`;
69
- if (dryRun) {
70
- const { createPatch } = await import("diff");
71
- globalLogger.info("[dry-run] package.json:");
72
- console.info(createPatch("package.json", pkgRaw, pkgStr));
73
- } else {
74
- await writeFile("package.json", pkgStr);
75
- globalLogger.success("Migrated `package.json`");
76
- }
77
- return true;
78
- }
79
- const TSUP_FILES = [
80
- "tsup.config.ts",
81
- "tsup.config.cts",
82
- "tsup.config.mts",
83
- "tsup.config.js",
84
- "tsup.config.cjs",
85
- "tsup.config.mjs",
86
- "tsup.config.json"
87
- ];
88
- async function migrateTsupConfig(dryRun) {
89
- let found = false;
90
- for (const file of TSUP_FILES) {
91
- if (!existsSync(file)) continue;
92
- globalLogger.info(`Found \`${file}\``);
93
- found = true;
94
- const tsupConfigRaw = await readFile(file, "utf8");
95
- const tsupConfig = tsupConfigRaw.replaceAll(/\btsup\b/g, "tsdown").replaceAll(/\bTSUP\b/g, "TSDOWN");
96
- const renamed = file.replaceAll("tsup", "tsdown");
97
- if (dryRun) {
98
- const { createTwoFilesPatch } = await import("diff");
99
- globalLogger.info(`[dry-run] ${file} -> ${renamed}:`);
100
- console.info(createTwoFilesPatch(file, renamed, tsupConfigRaw, tsupConfig));
101
- } else {
102
- await writeFile(renamed, tsupConfig, "utf8");
103
- await unlink(file);
104
- globalLogger.success(`Migrated \`${file}\` to \`${renamed}\``);
105
- }
106
- }
107
- if (!found) globalLogger.warn("No tsup config found");
108
- return found;
109
- }
110
- function renameKey(obj, oldKey, newKey, newValue) {
111
- const newObj = {};
112
- for (const key of Object.keys(obj)) if (key === oldKey) newObj[newKey] = newValue || obj[oldKey];
113
- else newObj[key] = obj[key];
114
- return newObj;
115
- }
116
-
117
- //#endregion
118
- export { migrate };