tsdown 0.3.0 → 0.3.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
  # tsdown [![npm](https://img.shields.io/npm/v/tsdown.svg)](https://npmjs.com/package/tsdown) [![Unit Test](https://github.com/sxzz/tsdown/actions/workflows/unit-test.yml/badge.svg)](https://github.com/sxzz/tsdown/actions/workflows/unit-test.yml) [![JSR](https://jsr.io/badges/@sxzz/tsdown)](https://jsr.io/@sxzz/tsdown)
2
2
 
3
- An even faster bundler powered by Rolldown.
3
+ An even faster bundler powered by [Rolldown](https://github.com/rolldown/rolldown).
4
4
 
5
5
  > [!NOTE]
6
6
  > 🚧 **Work in Progress**
@@ -0,0 +1,28 @@
1
+ import { debug } from "./logger-Pk57TMWT.js";
2
+ import path from "node:path";
3
+
4
+ //#region src/features/external.ts
5
+ function ExternalPlugin(pkg, skipNodeModulesBundle) {
6
+ const deps = Array.from(getProductionDeps(pkg));
7
+ return {
8
+ name: "tsdown:external",
9
+ resolveId(id, importer, { isEntry }) {
10
+ if (isEntry) return;
11
+ let shouldExternal = skipNodeModulesBundle && !path.isAbsolute(id) && id[0] !== ".";
12
+ shouldExternal ||= deps.some((dep) => id === dep || id.startsWith(`${dep}/`));
13
+ if (shouldExternal) {
14
+ debug("[external]", "External dependency:", id);
15
+ return {
16
+ id,
17
+ external: true
18
+ };
19
+ }
20
+ }
21
+ };
22
+ }
23
+ function getProductionDeps(pkg) {
24
+ return new Set([...Object.keys(pkg.dependencies || {}), ...Object.keys(pkg.peerDependencies || {})]);
25
+ }
26
+
27
+ //#endregion
28
+ export { ExternalPlugin };
@@ -1,2 +1,2 @@
1
- import type { Options } from '../options';
2
- export declare function resolveEntry(entry: Options['entry']): Promise<string[] | Record<string, string>>;
1
+ import type { Options } from "../options.js";
2
+ export declare function resolveEntry(entry: Options["entry"]): Promise<string[] | Record<string, string>>;
@@ -1,6 +1,5 @@
1
- import type { ResolvedOptions } from '../options';
2
- import type { PackageJson } from 'pkg-types';
3
- import type { InputOptions, Plugin } from 'rolldown';
4
- export type External = InputOptions['external'];
5
- export declare function ExternalPlugin(pkg: PackageJson | undefined, platform: ResolvedOptions['platform']): Plugin;
1
+ import type { PackageJson } from "pkg-types";
2
+ import type { InputOptions, Plugin } from "rolldown";
3
+ export type External = InputOptions["external"];
4
+ export declare function ExternalPlugin(pkg: PackageJson, skipNodeModulesBundle?: boolean): Plugin;
6
5
  export declare function getProductionDeps(pkg: PackageJson): Set<string>;
@@ -1,2 +1,2 @@
1
- import type { Format } from '../options';
2
- export declare function resolveOutputExtension(pkg: any, format: Format): 'mjs' | 'cjs' | 'js';
1
+ import type { ModuleFormat } from "rolldown";
2
+ export declare function resolveOutputExtension(pkg: any, format: ModuleFormat): "mjs" | "cjs" | "js";
@@ -1,7 +1,7 @@
1
- import type { FSWatcher } from 'chokidar';
1
+ import type { FSWatcher } from "chokidar";
2
2
  export interface Shortcut {
3
- key: string;
4
- description: string;
5
- action: () => void | Promise<void>;
3
+ key: string;
4
+ description: string;
5
+ action: () => void | Promise<void>;
6
6
  }
7
7
  export declare function shortcuts(watcher: FSWatcher, rebuild: () => void): void;
@@ -1,3 +1,3 @@
1
- import type { ResolvedOptions } from '../options';
2
- import type { FSWatcher } from 'chokidar';
1
+ import type { ResolvedOptions } from "../options.js";
2
+ import type { FSWatcher } from "chokidar";
3
3
  export declare function watchBuild(options: ResolvedOptions, rebuild: () => void): Promise<FSWatcher>;
package/dist/index.d.ts CHANGED
@@ -1,12 +1,18 @@
1
- import { type Options, type OptionsWithoutConfig } from './options';
2
- import { logger } from './utils/logger';
1
+ import { type Config, type Options, type ResolvedOptions } from "./options.js";
2
+ import { logger } from "./utils/logger.js";
3
3
  /**
4
- * Build with tsdown.
5
- */
6
- export declare function build(userOptions?: Omit<Options, 'silent'>): Promise<void>;
4
+ * Build with tsdown.
5
+ */
6
+ export declare function build(userOptions?: Omit<Options, "silent">): Promise<void>;
7
7
  /**
8
- * Defines the configuration for tsdown.
9
- */
10
- export declare function defineConfig(options: OptionsWithoutConfig): OptionsWithoutConfig;
8
+ * Build a single configuration.
9
+ *
10
+ * @param resolved Resolved options
11
+ */
12
+ export declare function buildSingle(resolved: ResolvedOptions): Promise<void>;
13
+ /**
14
+ * Defines the configuration for tsdown.
15
+ */
16
+ export declare function defineConfig(options: Config): Config;
11
17
  export { logger };
12
- export type { Options, OptionsWithoutConfig };
18
+ export type { Config, Options };
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { logger } from "./logger-e0Fr5WMR.js";
2
- import { ExternalPlugin } from "./external-DZ7KC16d.js";
1
+ import { debug, logger } from "./logger-Pk57TMWT.js";
2
+ import { ExternalPlugin } from "./external-9r3oq3tH.js";
3
3
  import process, { default as process$1, default as process$2, default as process$3 } from "node:process";
4
4
  import { rolldown } from "rolldown";
5
5
  import { IsolatedDecl } from "unplugin-isolated-decl";
@@ -27,10 +27,13 @@ async function cleanOutDir(cwd, patterns) {
27
27
  absolute: true
28
28
  }));
29
29
  logger.info("Cleaning output folder");
30
- for (const file of files) await rm(file, {
31
- force: true,
32
- recursive: true
33
- });
30
+ for (const file of files) {
31
+ debug("[clean]", "Removing", file);
32
+ await rm(file, {
33
+ force: true,
34
+ recursive: true
35
+ });
36
+ }
34
37
  }
35
38
 
36
39
  //#endregion
@@ -39,6 +42,7 @@ async function readPackageJson(dir) {
39
42
  const packageJsonPath = path$1.join(dir, "package.json");
40
43
  const exists = await fsExists(packageJsonPath);
41
44
  if (!exists) return;
45
+ debug("Reading package.json:", packageJsonPath);
42
46
  return readPackageJSON(packageJsonPath);
43
47
  }
44
48
  function getPackageType(pkg) {
@@ -54,12 +58,12 @@ function getPackageType(pkg) {
54
58
  function resolveOutputExtension(pkg, format) {
55
59
  const moduleType = getPackageType(pkg);
56
60
  switch (format) {
57
- case "iife": return "js";
58
61
  case "es":
59
62
  case "esm":
60
63
  case "module": return moduleType === "module" ? "js" : "mjs";
61
64
  case "cjs":
62
65
  case "commonjs": return moduleType === "module" ? "cjs" : "js";
66
+ default: return "js";
63
67
  }
64
68
  }
65
69
 
@@ -179,39 +183,39 @@ async function resolveEntry(entry) {
179
183
 
180
184
  //#endregion
181
185
  //#region src/options.ts
182
- async function normalizeOptions(options) {
183
- options = {
184
- ...await loadConfigFile(options),
185
- ...options
186
- };
187
- let { entry, format = ["es"], plugins = [], external, clean = false, silent = false, treeshake = true, platform = "node", outDir = "dist", sourcemap = false, dts = false, unused = false, minify, alias, watch = false, inputOptions, outputOptions, onSuccess } = options;
188
- entry = await resolveEntry(entry);
189
- format = toArray(format, "es");
190
- if (clean === true) clean = [];
191
- return {
192
- entry,
193
- plugins,
194
- external,
195
- format,
196
- outDir: path.resolve(outDir),
197
- clean,
198
- silent,
199
- alias,
200
- treeshake,
201
- platform,
202
- sourcemap,
203
- dts,
204
- unused,
205
- minify,
206
- watch,
207
- inputOptions,
208
- outputOptions,
209
- onSuccess
210
- };
186
+ async function resolveOptions(options) {
187
+ const [config, configFile] = await loadConfigFile(options);
188
+ if (config.length === 0) config.push({});
189
+ return [await Promise.all(config.map(async (subConfig) => {
190
+ const subOptions = {
191
+ ...subConfig,
192
+ ...options
193
+ };
194
+ let { entry, format = ["es"], plugins = [], clean = false, silent = false, treeshake = true, platform = "node", outDir = "dist", sourcemap = false, dts = false, unused = false, watch = false, skipNodeModulesBundle = false } = subOptions;
195
+ entry = await resolveEntry(entry);
196
+ format = toArray(format, "es");
197
+ if (clean === true) clean = [];
198
+ return {
199
+ ...subOptions,
200
+ entry,
201
+ plugins,
202
+ format,
203
+ outDir: path.resolve(outDir),
204
+ clean,
205
+ silent,
206
+ treeshake,
207
+ platform,
208
+ sourcemap,
209
+ dts,
210
+ unused,
211
+ watch,
212
+ skipNodeModulesBundle
213
+ };
214
+ })), configFile];
211
215
  }
212
216
  async function loadConfigFile(options) {
213
217
  let { config: filePath } = options;
214
- if (filePath === false) return {};
218
+ if (filePath === false) return [[]];
215
219
  let cwd = process$1.cwd();
216
220
  let overrideConfig = false;
217
221
  let stats;
@@ -248,13 +252,19 @@ async function loadConfigFile(options) {
248
252
  defaults: {}
249
253
  });
250
254
  if (sources.length > 0) logger.info(`Using tsdown config: ${pc.underline(sources.join(", "))}`);
251
- return config;
255
+ const file = sources[0];
256
+ return [toArray(config), file];
252
257
  }
253
258
 
254
259
  //#endregion
255
260
  //#region src/index.ts
256
261
  async function build(userOptions = {}) {
257
- const resolved = await normalizeOptions(userOptions);
262
+ debug("Loading config");
263
+ const [resolved, configFile] = await resolveOptions(userOptions);
264
+ if (configFile) debug("Loaded config:", configFile);
265
+ await Promise.all(resolved.map(buildSingle));
266
+ }
267
+ async function buildSingle(resolved) {
258
268
  const { entry, external, plugins, outDir, format, clean, platform, alias, treeshake, sourcemap, dts, minify, watch, unused, onSuccess } = resolved;
259
269
  if (clean) await cleanOutDir(outDir, clean);
260
270
  const pkg = await readPackageJson(process.cwd());
@@ -266,9 +276,9 @@ async function build(userOptions = {}) {
266
276
  treeshake,
267
277
  platform,
268
278
  plugins: [
269
- ExternalPlugin(pkg, platform),
270
- dts && IsolatedDecl.rolldown(dts === true ? {} : dts),
279
+ pkg && ExternalPlugin(pkg, resolved.skipNodeModulesBundle),
271
280
  unused && Unused.rolldown(unused === true ? {} : unused),
281
+ dts && IsolatedDecl.rolldown(dts === true ? {} : dts),
272
282
  ...plugins
273
283
  ].filter((plugin) => !!plugin),
274
284
  ...resolved.inputOptions
@@ -278,6 +288,7 @@ async function build(userOptions = {}) {
278
288
  const extension = resolveOutputExtension(pkg, format$1);
279
289
  const outputOptions$1 = {
280
290
  format: format$1,
291
+ name: resolved.globalName,
281
292
  sourcemap,
282
293
  dir: outDir,
283
294
  minify,
@@ -307,4 +318,4 @@ function defineConfig(options) {
307
318
  }
308
319
 
309
320
  //#endregion
310
- export { build, defineConfig, logger };
321
+ export { build, buildSingle, defineConfig, logger };
@@ -1,7 +1,9 @@
1
1
  import { consola } from "consola";
2
+ import Debug from "debug";
2
3
 
3
4
  //#region src/utils/logger.ts
4
5
  const logger = consola.withTag("tsdown");
6
+ const debug = Debug("tsdown");
5
7
 
6
8
  //#endregion
7
- export { logger };
9
+ export { debug, logger };
package/dist/options.d.ts CHANGED
@@ -1,49 +1,54 @@
1
- import type { External } from './features/external';
2
- import type { MarkPartial, MaybePromise, Overwrite } from './utils/types';
3
- import type { InputOptions, OutputOptions } from 'rolldown';
4
- import type { Options as IsolatedDeclOptions } from 'unplugin-isolated-decl';
5
- import type { Options as UnusedOptions } from 'unplugin-unused';
6
- export type Format = 'es' | 'cjs' | 'esm' | 'module' | 'commonjs' | 'iife';
7
- export type Sourcemap = boolean | 'inline' | 'hidden';
1
+ import type { External } from "./features/external.js";
2
+ import type { Arrayable, MarkPartial, MaybePromise, Overwrite } from "./utils/types.js";
3
+ import type { InputOptions, ModuleFormat, OutputOptions } from "rolldown";
4
+ import type { Options as IsolatedDeclOptions } from "unplugin-isolated-decl";
5
+ import type { Options as UnusedOptions } from "unplugin-unused";
6
+ export type Sourcemap = boolean | "inline" | "hidden";
8
7
  /**
9
- * Options for tsdown.
10
- */
8
+ * Options for tsdown.
9
+ */
11
10
  export interface Options {
12
- entry?: InputOptions['input'];
13
- format?: Format | Format[];
14
- plugins?: InputOptions['plugins'];
15
- external?: External;
16
- outDir?: string;
17
- clean?: boolean | string[];
18
- silent?: boolean;
19
- config?: boolean | string;
20
- sourcemap?: Sourcemap;
21
- alias?: Record<string, string>;
22
- /** @default true */
23
- treeshake?: boolean;
24
- /** @default false */
25
- minify?: boolean;
26
- /** @default 'node' */
27
- platform?: 'node' | 'neutral' | 'browser';
28
- /**
29
- * Enable dts generation with `isolatedDeclarations` (experimental)
30
- */
31
- dts?: boolean | IsolatedDeclOptions;
32
- /**
33
- * Enable unused dependencies check with `unplugin-unused` (experimental)
34
- */
35
- unused?: boolean | UnusedOptions;
36
- watch?: boolean | string | string[];
37
- inputOptions?: InputOptions;
38
- outputOptions?: OutputOptions | ((options: OutputOptions, format: Format) => MaybePromise<OutputOptions | void | null>);
39
- onSuccess?: () => void | Promise<void>;
11
+ entry?: InputOptions["input"];
12
+ format?: ModuleFormat | ModuleFormat[];
13
+ globalName?: string;
14
+ plugins?: InputOptions["plugins"];
15
+ external?: External;
16
+ outDir?: string;
17
+ clean?: boolean | string[];
18
+ silent?: boolean;
19
+ config?: boolean | string;
20
+ sourcemap?: Sourcemap;
21
+ alias?: Record<string, string>;
22
+ /** @default true */
23
+ treeshake?: boolean;
24
+ /** @default false */
25
+ minify?: boolean;
26
+ /** @default 'node' */
27
+ platform?: "node" | "neutral" | "browser";
28
+ /**
29
+ * Enable dts generation with `isolatedDeclarations` (experimental)
30
+ */
31
+ dts?: boolean | IsolatedDeclOptions;
32
+ /**
33
+ * Enable unused dependencies check with `unplugin-unused` (experimental)
34
+ */
35
+ unused?: boolean | UnusedOptions;
36
+ watch?: boolean | string | string[];
37
+ inputOptions?: InputOptions;
38
+ outputOptions?: OutputOptions | ((options: OutputOptions, format: ModuleFormat) => MaybePromise<OutputOptions | void | null>);
39
+ onSuccess?: () => void | Promise<void>;
40
+ /**
41
+ * Skip bundling node_modules.
42
+ */
43
+ skipNodeModulesBundle?: boolean;
40
44
  }
41
45
  /**
42
- * Options without specifying config file path.
43
- */
44
- export type OptionsWithoutConfig = Omit<Options, 'config'>;
45
- export type ResolvedOptions = Omit<Overwrite<MarkPartial<Options, 'inputOptions' | 'outputOptions' | 'minify' | 'alias' | 'external' | 'onSuccess'>, {
46
- format: Format[];
47
- clean: string[] | false;
48
- }>, 'config'>;
49
- export declare function normalizeOptions(options: Options): Promise<ResolvedOptions>;
46
+ * Options without specifying config file path.
47
+ */
48
+ export type Config = Arrayable<Omit<Options, "config">>;
49
+ export type ResolvedConfig = Extract<Config, any[]>;
50
+ export type ResolvedOptions = Omit<Overwrite<MarkPartial<Options, "globalName" | "inputOptions" | "outputOptions" | "minify" | "alias" | "external" | "onSuccess">, {
51
+ format: ModuleFormat[];
52
+ clean: string[] | false;
53
+ }>, "config">;
54
+ export declare function resolveOptions(options: Options): Promise<[configs: ResolvedOptions[], configFile?: string]>;
package/dist/plugins.d.ts CHANGED
@@ -1 +1 @@
1
- export { ExternalPlugin } from './features/external';
1
+ export { ExternalPlugin } from "./features/external.js";
package/dist/plugins.js CHANGED
@@ -1,3 +1,4 @@
1
- import { ExternalPlugin } from "./external-DZ7KC16d.js";
1
+ import "./logger-Pk57TMWT.js";
2
+ import { ExternalPlugin } from "./external-9r3oq3tH.js";
2
3
 
3
4
  export { ExternalPlugin };
package/dist/run.js CHANGED
@@ -1,18 +1,18 @@
1
- import { logger } from "./logger-e0Fr5WMR.js";
1
+ import { logger } from "./logger-Pk57TMWT.js";
2
2
  import process from "node:process";
3
3
  import { VERSION as rolldownVersion } from "rolldown";
4
4
  import pc from "picocolors";
5
5
  import { cac } from "cac";
6
6
 
7
7
  //#region package.json
8
- const version = "0.3.0";
8
+ const version = "0.3.1";
9
9
 
10
10
  //#endregion
11
11
  //#region src/cli.ts
12
12
  async function runCLI() {
13
13
  const cli = cac("tsdown");
14
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("--minify", "Minify output").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("--platform <platform>", "Target platform", { default: "node" }).option("-w, --watch", "Watch mode").action(async (input, flags) => {
15
- logger.level = flags.silent ? 0 : 3;
15
+ if (!("CONSOLA_LEVEL" in process.env)) logger.level = flags.silent ? 0 : 3;
16
16
  logger.info(`tsdown ${pc.dim(`v${version}`)} powered by rolldown ${pc.dim(`v${rolldownVersion}`)}`);
17
17
  const { build } = await import("./index.js");
18
18
  if (input.length > 0) flags.entry = input;
@@ -1,5 +1,7 @@
1
- import { type ConsolaInstance } from 'consola';
1
+ import { type ConsolaInstance } from "consola";
2
+ import Debug from "debug";
2
3
  /**
3
- * Logger instance
4
- */
4
+ * Logger instance
5
+ */
5
6
  export declare const logger: ConsolaInstance;
7
+ export declare const debug: Debug.Debugger;
@@ -1,3 +1,3 @@
1
- import { type PackageJson } from 'pkg-types';
1
+ import { type PackageJson } from "pkg-types";
2
2
  export declare function readPackageJson(dir: string): Promise<PackageJson | undefined>;
3
- export declare function getPackageType(pkg: PackageJson | undefined): 'module' | 'commonjs';
3
+ export declare function getPackageType(pkg: PackageJson | undefined): "module" | "commonjs";
@@ -1,3 +1,10 @@
1
- export type Overwrite<T, U> = Omit<T, keyof U> & U;
1
+ export type Overwrite<
2
+ T,
3
+ U
4
+ > = Omit<T, keyof U> & U;
2
5
  export type MaybePromise<T> = T | Promise<T>;
3
- export type MarkPartial<T, K extends keyof T> = Omit<Required<T>, K> & Partial<Pick<T, K>>;
6
+ export type MarkPartial<
7
+ T,
8
+ K extends keyof T
9
+ > = Omit<Required<T>, K> & Partial<Pick<T, K>>;
10
+ export type Arrayable<T> = T | T[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tsdown",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "An even faster bundler powered by Rolldown.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -42,27 +42,30 @@
42
42
  "cac": "^6.7.14",
43
43
  "chokidar": "^4.0.1",
44
44
  "consola": "^3.2.3",
45
+ "debug": "^4.3.7",
45
46
  "picocolors": "^1.1.1",
46
47
  "pkg-types": "^1.2.1",
47
48
  "rolldown": "nightly",
48
49
  "tinyglobby": "^0.2.10",
49
50
  "unconfig": "^0.6.0",
50
- "unplugin-isolated-decl": "^0.6.8",
51
+ "unplugin-isolated-decl": "^0.7.2",
51
52
  "unplugin-unused": "^0.2.3"
52
53
  },
53
54
  "devDependencies": {
54
- "@sxzz/eslint-config": "^4.4.0",
55
+ "@sxzz/eslint-config": "^4.4.1",
55
56
  "@sxzz/prettier-config": "^2.0.2",
56
- "@types/node": "^22.8.2",
57
- "bumpp": "^9.8.0",
58
- "eslint": "^9.13.0",
57
+ "@types/debug": "^4.1.12",
58
+ "@types/node": "^22.9.1",
59
+ "bumpp": "^9.8.1",
60
+ "eslint": "^9.15.0",
59
61
  "execa": "^9.5.1",
60
62
  "fdir": "^6.4.2",
63
+ "oxc-transform": "^0.36.0",
61
64
  "prettier": "^3.3.3",
62
65
  "tsup": "^8.3.5",
63
66
  "tsx": "^4.19.2",
64
67
  "typescript": "~5.6.3",
65
- "vitest": "^2.1.4"
68
+ "vitest": "^2.1.5"
66
69
  },
67
70
  "engines": {
68
71
  "node": ">=18.0.0"
@@ -1,23 +0,0 @@
1
- import { isBuiltin } from "node:module";
2
-
3
- //#region src/features/external.ts
4
- function ExternalPlugin(pkg, platform) {
5
- const deps = pkg && Array.from(getProductionDeps(pkg));
6
- return {
7
- name: "tsdown:external",
8
- resolveId(id) {
9
- let shouldExternal = deps && deps.some((dep) => id === dep || id.startsWith(`${dep}/`));
10
- shouldExternal ||= platform === "node" && isBuiltin(id);
11
- if (shouldExternal) return {
12
- id,
13
- external: true
14
- };
15
- }
16
- };
17
- }
18
- function getProductionDeps(pkg) {
19
- return new Set([...Object.keys(pkg.dependencies || {}), ...Object.keys(pkg.peerDependencies || {})]);
20
- }
21
-
22
- //#endregion
23
- export { ExternalPlugin };