tsdown 0.16.8 → 0.17.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.
@@ -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-BrlHanBo.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-BrlHanBo.mjs";
2
+ import { t as defineConfig } from "./config-CSoQwDij.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-BrlHanBo.mjs";
2
+ import { t as defineConfig } from "./config-CSoQwDij.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-hEE2DSx9.mjs";
3
+ import { a as globalLogger } from "./package-r6WmI0kC.mjs";
4
4
 
5
5
  export { build, buildSingle, defineConfig, globalLogger, shimFile };
@@ -1,7 +1,7 @@
1
- import { a as globalLogger, t as version } from "./package-BDAjF-Kz.mjs";
2
- import process from "node:process";
1
+ import { a as globalLogger, t as version } from "./package-r6WmI0kC.mjs";
3
2
  import { bold, green, underline } from "ansis";
4
3
  import { readFile, unlink, writeFile } from "node:fs/promises";
4
+ import process from "node:process";
5
5
  import { existsSync } from "node:fs";
6
6
  import { createInterface } from "node:readline/promises";
7
7
 
@@ -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.1";
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-BrlHanBo.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-hEE2DSx9.mjs";
3
+ import "./package-r6WmI0kC.mjs";
4
4
 
5
5
  export { ExternalPlugin, NodeProtocolPlugin, ReportPlugin, ShebangPlugin };
package/dist/run.mjs CHANGED
@@ -1,9 +1,9 @@
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-r6WmI0kC.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
8
  import { cac } from "cac";
9
9
 
@@ -36,7 +36,7 @@ cli.command("[...files]", "Bundle files", {
36
36
  await build$1(flags);
37
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");
39
+ const { migrate } = await import("./migrate-CcVRf9lh.mjs");
40
40
  await migrate(args);
41
41
  });
42
42
  async function runCLI() {
@@ -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-r6WmI0kC.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
@@ -566,7 +572,7 @@ async function resolveWorkspace(config, inlineConfig) {
566
572
  };
567
573
  }
568
574
  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;
575
+ 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
576
  const logger = createLogger(logLevel, {
571
577
  customLogger,
572
578
  failOnWarn: resolveFeatureOption(failOnWarn, true)
@@ -615,46 +621,49 @@ async function resolveUserConfig(userConfig, inlineConfig) {
615
621
  }
616
622
  if (inlineOnly != null) inlineOnly = toArray(inlineOnly);
617
623
  debug$9 = resolveFeatureOption(debug$9, {});
618
- if (debug$9) debug$9.devtools ??= !!pkgExists("@vitejs/devtools/cli");
624
+ if (debug$9) if (watch$1) {
625
+ if (debug$9.devtools) logger.warn("Devtools is not supported in watch mode, disabling it.");
626
+ debug$9.devtools = false;
627
+ } else debug$9.devtools ??= !!pkgExists("@vitejs/devtools/cli");
619
628
  return {
620
629
  ...userConfig,
630
+ alias,
631
+ attw: attw$1,
632
+ cjsDefault,
633
+ clean,
634
+ copy: publicDir || copy$1,
635
+ cwd,
636
+ debug: debug$9,
637
+ dts,
621
638
  entry,
622
- plugins,
639
+ env: env$1,
640
+ exports,
641
+ external,
642
+ fixedExtension,
623
643
  format: normalizeFormat(format),
624
- target,
625
- outDir,
626
- clean,
644
+ globImport,
645
+ hash,
646
+ ignoreWatch,
647
+ inlineOnly,
627
648
  logger,
628
- treeshake,
649
+ name,
650
+ nodeProtocol,
651
+ noExternal,
652
+ outDir,
653
+ pkg,
629
654
  platform,
630
- sourcemap,
631
- dts,
655
+ plugins,
656
+ publint: publint$1,
632
657
  report,
633
- unused,
634
- watch,
635
- ignoreWatch,
636
658
  shims,
637
659
  skipNodeModulesBundle,
638
- publint: publint$1,
639
- attw: attw$1,
640
- alias,
660
+ sourcemap,
661
+ target,
662
+ treeshake,
641
663
  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
664
  unbundle,
652
- nodeProtocol,
653
- cjsDefault,
654
- globImport,
655
- inlineOnly,
656
- fixedExtension,
657
- debug: debug$9
665
+ unused,
666
+ watch: watch$1
658
667
  };
659
668
  }
660
669
  async function mergeUserOptions(defaults, user, args) {
@@ -811,6 +820,23 @@ async function createHooks$1(options) {
811
820
  }
812
821
  };
813
822
  }
823
+ function executeOnSuccess(config) {
824
+ if (!config.onSuccess) return;
825
+ const ab = new AbortController();
826
+ if (typeof config.onSuccess === "string") {
827
+ const p = exec(config.onSuccess, [], { nodeOptions: {
828
+ shell: true,
829
+ stdio: "inherit"
830
+ } });
831
+ p.then(({ exitCode }) => {
832
+ if (exitCode) process.exitCode = exitCode;
833
+ });
834
+ ab.signal.addEventListener("abort", () => {
835
+ if (typeof p.pid === "number") treeKill(p.pid);
836
+ });
837
+ } else config.onSuccess(config, ab.signal);
838
+ return ab;
839
+ }
814
840
 
815
841
  //#endregion
816
842
  //#region src/features/publint.ts
@@ -1158,11 +1184,36 @@ function getShimsInject(format, platform) {
1158
1184
  };
1159
1185
  }
1160
1186
 
1187
+ //#endregion
1188
+ //#region src/features/watch.ts
1189
+ const endsWithConfig = /[\\/](?:tsdown\.config.*|tsconfig\.json)$/;
1190
+ function WatchPlugin(configFiles, { config, chunks }) {
1191
+ return {
1192
+ name: "tsdown:watch",
1193
+ options: config.ignoreWatch.length ? (inputOptions) => {
1194
+ inputOptions.watch ||= {};
1195
+ inputOptions.watch.exclude = toArray(inputOptions.watch.exclude);
1196
+ inputOptions.watch.exclude.push(...config.ignoreWatch);
1197
+ } : void 0,
1198
+ buildStart() {
1199
+ config.tsconfig && this.addWatchFile(config.tsconfig);
1200
+ for (const file of configFiles) this.addWatchFile(file);
1201
+ if (typeof config.watch !== "boolean") for (const file of resolveComma(toArray(config.watch))) this.addWatchFile(file);
1202
+ },
1203
+ generateBundle: {
1204
+ order: "post",
1205
+ handler(outputOptions, bundle) {
1206
+ chunks.push(...Object.values(bundle));
1207
+ }
1208
+ }
1209
+ };
1210
+ }
1211
+
1161
1212
  //#endregion
1162
1213
  //#region src/features/rolldown.ts
1163
1214
  const debug = createDebug("tsdown:rolldown");
1164
- async function getBuildOptions(config, format, isMultiFormat, cjsDts = false) {
1165
- const inputOptions = await resolveInputOptions(config, format, cjsDts, isMultiFormat);
1215
+ async function getBuildOptions(config, format, configFiles, watchContext, cjsDts = false, isMultiFormat) {
1216
+ const inputOptions = await resolveInputOptions(config, format, configFiles, watchContext, cjsDts, isMultiFormat);
1166
1217
  const outputOptions = await resolveOutputOptions(inputOptions, config, format, cjsDts);
1167
1218
  const rolldownConfig = {
1168
1219
  ...inputOptions,
@@ -1171,8 +1222,8 @@ async function getBuildOptions(config, format, isMultiFormat, cjsDts = false) {
1171
1222
  debug("rolldown config with format \"%s\" %O", cjsDts ? "cjs dts" : format, rolldownConfig);
1172
1223
  return rolldownConfig;
1173
1224
  }
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;
1225
+ async function resolveInputOptions(config, format, configFiles, watchContext, cjsDts, isMultiFormat) {
1226
+ 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
1227
  const plugins = [];
1177
1228
  if (nodeProtocol) plugins.push(NodeProtocolPlugin(nodeProtocol));
1178
1229
  if (config.pkg || config.skipNodeModulesBundle) plugins.push(ExternalPlugin(config));
@@ -1204,6 +1255,7 @@ async function resolveInputOptions(config, format, cjsDts, isMultiFormat) {
1204
1255
  if (globImport) plugins.push(importGlobPlugin());
1205
1256
  }
1206
1257
  if (report && LogLevels[logger.level] >= 3) plugins.push(ReportPlugin(report, logger, cwd, cjsDts, name, isMultiFormat));
1258
+ if (watch$1) plugins.push(WatchPlugin(configFiles, watchContext));
1207
1259
  if (!cjsDts) plugins.push(userPlugins);
1208
1260
  const define = {
1209
1261
  ...config.define,
@@ -1340,52 +1392,9 @@ function shortcuts(restart) {
1340
1392
  return () => rl.close();
1341
1393
  }
1342
1394
 
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
1395
  //#endregion
1388
1396
  //#region src/index.ts
1397
+ const asyncDispose = Symbol.asyncDispose || Symbol.for("Symbol.asyncDispose");
1389
1398
  /**
1390
1399
  * Build with tsdown.
1391
1400
  */
@@ -1397,20 +1406,22 @@ async function build$1(userOptions = {}) {
1397
1406
  if (cleanPromise) return cleanPromise;
1398
1407
  return cleanPromise = cleanOutDir(configs);
1399
1408
  };
1400
- globalLogger.info("Build start");
1401
- const rebuilds = await Promise.all(configs.map((options) => buildSingle(options, clean)));
1402
1409
  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());
1410
+ let restarting = false;
1411
+ async function restart() {
1412
+ if (restarting) return;
1413
+ restarting = true;
1414
+ await Promise.all(disposeCbs.map((cb) => cb()));
1415
+ setNoCacheLoad();
1416
+ build$1(userOptions);
1409
1417
  }
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;
1418
+ globalLogger.info("Build start");
1419
+ const bundles = await Promise.all(configs.map((options) => buildSingle(options, configFiles, clean, restart)));
1420
+ const firstDevtoolsConfig = configs.find((config) => config.debug && config.debug.devtools);
1421
+ if (configs.some((config) => config.watch)) {
1422
+ disposeCbs.push(shortcuts(restart));
1423
+ for (const bundle of bundles) disposeCbs.push(bundle[asyncDispose]);
1424
+ return;
1414
1425
  }
1415
1426
  if (firstDevtoolsConfig) {
1416
1427
  const { start } = await importWithError("@vitejs/devtools/cli-commands");
@@ -1421,16 +1432,8 @@ async function build$1(userOptions = {}) {
1421
1432
  ...typeof devtoolsOptions === "object" ? devtoolsOptions : {}
1422
1433
  });
1423
1434
  }
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
- }
1435
+ return bundles;
1429
1436
  }
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
1437
  /**
1435
1438
  * Build a single configuration, without watch and shortcuts features.
1436
1439
  *
@@ -1439,66 +1442,110 @@ const shimFile = path.resolve(pkgRoot, "esm-shims.js");
1439
1442
  * @private
1440
1443
  * @param config Resolved options
1441
1444
  */
1442
- async function buildSingle(config, clean) {
1443
- const { format: formats, dts, watch, onSuccess, logger } = config;
1444
- let ab;
1445
+ async function buildSingle(config, configFiles, clean, restart) {
1446
+ const { format: formats, dts, watch: watch$1, logger } = config;
1445
1447
  const { hooks, context } = await createHooks$1(config);
1446
1448
  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;
1449
+ const startTime = performance.now();
1450
+ await hooks.callHook("build:prepare", context);
1451
+ await clean();
1452
+ const debugRolldownConfigDir = await getDebugRolldownDir();
1453
+ const chunks = {};
1454
+ let watcher;
1455
+ const watchCtx = { config };
1456
+ let ab;
1457
+ const isMultiFormat = formats.length > 1;
1458
+ const configsByFormat = (await Promise.all(formats.map((format) => buildOptionsByFormat(format)))).flat();
1459
+ if (watch$1) {
1460
+ watcher = watch(configsByFormat.map((item) => item[1]));
1461
+ handleWatcher(watcher);
1462
+ } else {
1463
+ const outputs = await build(configsByFormat.map((item) => item[1]));
1464
+ for (const [i, output] of outputs.entries()) {
1465
+ const format = configsByFormat[i][0];
1466
+ chunks[format] ||= [];
1467
+ chunks[format].push(...output.output);
1468
+ }
1469
+ }
1470
+ if (!watch$1) {
1471
+ logger.success(prettyName(config.name), `Build complete in ${green(`${Math.round(performance.now() - startTime)}ms`)}`);
1472
+ await postBuild();
1473
+ }
1474
+ return {
1475
+ chunks,
1476
+ async [asyncDispose]() {
1477
+ ab?.abort();
1478
+ await watcher?.close();
1479
+ }
1480
+ };
1481
+ function handleWatcher(watcher$1) {
1482
+ const changedFile = [];
1483
+ let hasError = false;
1484
+ watcher$1.on("change", (id, event) => {
1485
+ if (event.event === "update") changedFile.push(id);
1486
+ if (configFiles.includes(id) || endsWithConfig.test(id)) {
1487
+ globalLogger.info(`Reload config: ${id}, restarting...`);
1488
+ restart();
1480
1489
  }
1481
- }));
1482
- if (hasErrors) return;
1490
+ });
1491
+ watcher$1.on("event", async (event) => {
1492
+ switch (event.code) {
1493
+ case "START":
1494
+ for (const format of formats) {
1495
+ await cleanupChunks(config.outDir, chunks[format]);
1496
+ chunks[format].length = 0;
1497
+ }
1498
+ hasError = false;
1499
+ break;
1500
+ case "END":
1501
+ if (!hasError) await postBuild();
1502
+ break;
1503
+ case "BUNDLE_START":
1504
+ if (changedFile.length > 0) {
1505
+ console.info("");
1506
+ logger.info(`Found ${bold(changedFile.join(", "))} changed, rebuilding...`);
1507
+ }
1508
+ changedFile.length = 0;
1509
+ break;
1510
+ case "BUNDLE_END":
1511
+ await event.result.close();
1512
+ logger.success(`Rebuilt in ${event.duration}ms.`);
1513
+ break;
1514
+ case "ERROR":
1515
+ await event.result.close();
1516
+ logger.error(event.error);
1517
+ hasError = true;
1518
+ break;
1519
+ }
1520
+ });
1521
+ }
1522
+ async function buildOptionsByFormat(format) {
1523
+ const watchContext = {
1524
+ ...watchCtx,
1525
+ chunks: chunks[format] = []
1526
+ };
1527
+ const buildOptions = await getBuildOptions(config, format, configFiles, watchContext, false, isMultiFormat);
1528
+ await hooks.callHook("build:before", {
1529
+ ...context,
1530
+ buildOptions
1531
+ });
1532
+ if (debugRolldownConfigDir) await debugBuildOptions(debugRolldownConfigDir, config.name, format, buildOptions);
1533
+ const configs = [[format, buildOptions]];
1534
+ if (format === "cjs" && dts) configs.push([format, await getBuildOptions(config, format, configFiles, watchContext, true, isMultiFormat)]);
1535
+ return configs;
1536
+ }
1537
+ async function postBuild() {
1483
1538
  await Promise.all([writeExports(config, chunks), copy(config)]);
1484
1539
  await Promise.all([publint(config), attw(config)]);
1485
1540
  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);
1541
+ ab?.abort();
1542
+ ab = executeOnSuccess(config);
1500
1543
  }
1501
1544
  }
1545
+ const dirname$1 = path.dirname(fileURLToPath(import.meta.url));
1546
+ const pkgRoot = path.resolve(dirname$1, "..");
1547
+ /** @internal */
1548
+ const shimFile = path.resolve(pkgRoot, "esm-shims.js");
1502
1549
 
1503
1550
  //#endregion
1504
1551
  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.1",
4
4
  "description": "The Elegant Bundler for Libraries",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -75,7 +75,6 @@
75
75
  "dependencies": {
76
76
  "ansis": "^4.2.0",
77
77
  "cac": "^6.7.14",
78
- "chokidar": "^5.0.0",
79
78
  "diff": "^8.0.2",
80
79
  "empathic": "^2.0.0",
81
80
  "hookable": "^5.5.3",
@@ -87,11 +86,11 @@
87
86
  "tinyglobby": "^0.2.15",
88
87
  "tree-kill": "^1.2.2",
89
88
  "unconfig-core": "^7.4.1",
90
- "unrun": "^0.2.13"
89
+ "unrun": "^0.2.14"
91
90
  },
92
91
  "devDependencies": {
93
92
  "@arethetypeswrong/core": "^0.18.2",
94
- "@sxzz/eslint-config": "^7.3.2",
93
+ "@sxzz/eslint-config": "^7.4.0",
95
94
  "@sxzz/prettier-config": "^2.2.6",
96
95
  "@sxzz/test-utils": "^0.5.13",
97
96
  "@types/node": "^24.10.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",