tsdown 0.2.3 → 0.2.4

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.
@@ -4,10 +4,10 @@ import { isBuiltin } from "node:module";
4
4
  function ExternalPlugin(pkg, platform) {
5
5
  const deps = pkg && getProductionDeps(pkg);
6
6
  return {
7
- name: 'tsdown:external',
7
+ name: "tsdown:external",
8
8
  resolveId(id) {
9
9
  let shouldExternal = deps?.has(id);
10
- shouldExternal ||= platform === 'node' && isBuiltin(id);
10
+ shouldExternal ||= platform === "node" && isBuiltin(id);
11
11
  if (shouldExternal) {
12
12
  return {
13
13
  id,
@@ -1 +1 @@
1
- export declare function cleanOutDir(cwd: string, patterns: (string)[]): Promise<void>;
1
+ export declare function cleanOutDir(cwd: string, patterns: string[]): Promise<void>;
@@ -1,2 +1,2 @@
1
1
  import type { Options } from '../options';
2
- export declare function resolveEntry(entry: Options['entry']): Promise<(((string)[]) | (Record<string, string>))>;
2
+ export declare function resolveEntry(entry: Options['entry']): Promise<string[] | Record<string, string>>;
@@ -1,6 +1,6 @@
1
- import type { PackageJson } from 'pkg-types';
2
1
  import type { ResolvedOptions } from '../options';
2
+ import type { PackageJson } from 'pkg-types';
3
3
  import type { InputOptions, Plugin } from 'rolldown';
4
4
  export type External = InputOptions['external'];
5
- export declare function ExternalPlugin(pkg: ((PackageJson) | (undefined)), platform: ResolvedOptions['platform']): Plugin;
5
+ export declare function ExternalPlugin(pkg: PackageJson | undefined, platform: ResolvedOptions['platform']): Plugin;
6
6
  export declare function getProductionDeps(pkg: PackageJson): Set<string>;
@@ -1,2 +1,2 @@
1
1
  import type { Format } from '../options';
2
- export declare function resolveOutputExtension(pkg: any, format: Format): (('mjs') | ('cjs') | ('js'));
2
+ export declare function resolveOutputExtension(pkg: any, format: Format): 'mjs' | 'cjs' | 'js';
@@ -0,0 +1,2 @@
1
+ import type { ResolvedOptions } from '../options';
2
+ export declare function watchBuild(options: ResolvedOptions, rebuild: () => void): Promise<void>;
package/dist/index.js CHANGED
@@ -1,17 +1,111 @@
1
- import { logger } from "./logger-39fy7Hdx.js";
2
- import { ExternalPlugin } from "./external-BI3U5n3V.js";
3
- import { default as process, default as process$1 } from "node:process";
1
+ import { logger } from "./logger-e0Fr5WMR.js";
2
+ import { ExternalPlugin } from "./external-uGOHYulu.js";
3
+ import { default as process, default as process$1, default as process$2 } from "node:process";
4
4
  import { rolldown } from "rolldown";
5
5
  import { IsolatedDecl } from "unplugin-isolated-decl";
6
6
  import { access, readdir, rm, stat } from "node:fs/promises";
7
- import { default as path, default as path$1, default as path$2 } from "node:path";
8
- import { loadConfig } from "unconfig";
9
- import { globby, globby as globby$1 } from "globby";
7
+ import { default as path, default as path$1, default as path$2, default as path$3 } from "node:path";
8
+ import { default as glob, default as glob$1 } from "fast-glob";
10
9
  import { readPackageJSON } from "pkg-types";
10
+ import { loadConfig } from "unconfig";
11
11
 
12
12
  //#region src/utils/fs.ts
13
- function fsExists(path$3) {
14
- return access(path$3).then(() => true, () => false);
13
+ function fsExists(path$4) {
14
+ return access(path$4).then(() => true, () => false);
15
+ }
16
+
17
+ //#endregion
18
+ //#region src/features/clean.ts
19
+ async function cleanOutDir(cwd, patterns) {
20
+ const files = [];
21
+ if (await fsExists(cwd)) files.push(...(await readdir(cwd)).map((file) => path$3.resolve(cwd, file)));
22
+ if (patterns.length) {
23
+ files.push(...await glob$1(patterns, {
24
+ cwd,
25
+ absolute: true
26
+ }));
27
+ }
28
+ logger.info("Cleaning output folder");
29
+ for (const file of files) {
30
+ await rm(file, {
31
+ force: true,
32
+ recursive: true
33
+ });
34
+ }
35
+ }
36
+
37
+ //#endregion
38
+ //#region src/utils/package.ts
39
+ async function readPackageJson(dir) {
40
+ const packageJsonPath = path$2.join(dir, "package.json");
41
+ const exists = await fsExists(packageJsonPath);
42
+ if (!exists) return;
43
+ return readPackageJSON(packageJsonPath);
44
+ }
45
+ function getPackageType(pkg) {
46
+ if (pkg?.type) {
47
+ if (!["module", "commonjs"].includes(pkg.type)) {
48
+ throw new Error(`Invalid package.json type: ${pkg.type}`);
49
+ }
50
+ return pkg.type;
51
+ }
52
+ return "commonjs";
53
+ }
54
+
55
+ //#endregion
56
+ //#region src/features/output.ts
57
+ function resolveOutputExtension(pkg, format) {
58
+ const type = getPackageType(pkg);
59
+ const isEsmFormat = ["es", "esm", "module"].includes(format);
60
+ if (type === "module") {
61
+ if (isEsmFormat) return "js";
62
+ else return "cjs";
63
+ } else {
64
+ if (isEsmFormat) return "mjs";
65
+ return "js";
66
+ }
67
+ }
68
+
69
+ //#endregion
70
+ //#region src/utils/general.ts
71
+ function toArray(val, defaultValue) {
72
+ if (Array.isArray(val)) {
73
+ return val;
74
+ } else if (val == null) {
75
+ if (defaultValue) return [defaultValue];
76
+ return [];
77
+ } else {
78
+ return [val];
79
+ }
80
+ }
81
+ function debounce(fn, wait) {
82
+ let timeout;
83
+ return function(...args) {
84
+ if (timeout) clearTimeout(timeout);
85
+ timeout = setTimeout(() => {
86
+ timeout = undefined;
87
+ fn.apply(this, args);
88
+ }, wait);
89
+ };
90
+ }
91
+
92
+ //#endregion
93
+ //#region src/features/watch.ts
94
+ async function watchBuild(options, rebuild) {
95
+ const { watch } = await import("chokidar");
96
+ const debouncedRebuild = debounce(rebuild, 100);
97
+ const files = typeof options.watch === "boolean" ? process$2.cwd() : options.watch;
98
+ const ignored = ["**/{.git,node_modules}/**", path$1.resolve(options.outDir)];
99
+ logger.info(`Watching for changes in ${toArray(files).join(", ")}`);
100
+ const watcher = watch(files, {
101
+ ignoreInitial: true,
102
+ ignorePermissionErrors: true,
103
+ ignored
104
+ });
105
+ watcher.on("all", (type, file) => {
106
+ logger.info(`Change detected: ${type} ${file}`);
107
+ debouncedRebuild();
108
+ });
15
109
  }
16
110
 
17
111
  //#endregion
@@ -20,14 +114,14 @@ async function resolveEntry(entry) {
20
114
  if (!entry || Object.keys(entry).length === 0) {
21
115
  throw new Error(`No input files, try "tsdown <your-file>" instead`);
22
116
  }
23
- if (typeof entry === 'string') {
117
+ if (typeof entry === "string") {
24
118
  entry = [entry];
25
119
  }
26
120
  if (Array.isArray(entry)) {
27
- const resolvedEntry = await globby$1(entry);
121
+ const resolvedEntry = await glob(entry);
28
122
  if (resolvedEntry.length > 0) {
29
123
  entry = resolvedEntry;
30
- logger.info(`entry: ${entry.join(', ')}`);
124
+ logger.info(`entry: ${entry.join(", ")}`);
31
125
  } else {
32
126
  throw new Error(`Cannot find entry: ${entry}`);
33
127
  }
@@ -38,24 +132,11 @@ async function resolveEntry(entry) {
38
132
  throw new Error(`Cannot find entry: ${filename}`);
39
133
  }
40
134
  });
41
- logger.info(`entry: ${files.join(', ')}`);
135
+ logger.info(`entry: ${files.join(", ")}`);
42
136
  }
43
137
  return entry;
44
138
  }
45
139
 
46
- //#endregion
47
- //#region src/utils/general.ts
48
- function toArray(val, defaultValue) {
49
- if (Array.isArray(val)) {
50
- return val;
51
- } else if (val == null) {
52
- if (defaultValue) return [defaultValue];
53
- return [];
54
- } else {
55
- return [val];
56
- }
57
- }
58
-
59
140
  //#endregion
60
141
  //#region src/options.ts
61
142
  async function normalizeOptions(options) {
@@ -63,9 +144,9 @@ async function normalizeOptions(options) {
63
144
  ...await loadConfigFile(options),
64
145
  ...options
65
146
  };
66
- let { entry, format = ['es'], plugins = [], external = [], clean = false, treeshake = true, platform = 'node', outDir = 'dist', dts = false, alias = {} } = options;
147
+ let { entry, format = ["es"], plugins = [], external = [], clean = false, treeshake = true, platform = "node", outDir = "dist", dts = false, alias = {}, watch = false } = options;
67
148
  entry = await resolveEntry(entry);
68
- format = toArray(format, 'es');
149
+ format = toArray(format, "es");
69
150
  if (clean === true) clean = [];
70
151
  return {
71
152
  entry,
@@ -77,7 +158,8 @@ async function normalizeOptions(options) {
77
158
  alias,
78
159
  treeshake,
79
160
  platform,
80
- dts
161
+ dts,
162
+ watch
81
163
  };
82
164
  }
83
165
  async function loadConfigFile(options) {
@@ -86,12 +168,12 @@ async function loadConfigFile(options) {
86
168
  let cwd = process$1.cwd();
87
169
  let overrideConfig = false;
88
170
  let stats;
89
- if (typeof filePath === 'string' && (stats = await stat(filePath).catch(() => null))) {
90
- const resolved = path$2.resolve(filePath);
171
+ if (typeof filePath === "string" && (stats = await stat(filePath).catch(() => null))) {
172
+ const resolved = path.resolve(filePath);
91
173
  if (stats.isFile()) {
92
174
  overrideConfig = true;
93
175
  filePath = resolved;
94
- cwd = path$2.dirname(filePath);
176
+ cwd = path.dirname(filePath);
95
177
  } else {
96
178
  cwd = resolved;
97
179
  }
@@ -101,10 +183,10 @@ async function loadConfigFile(options) {
101
183
  files: filePath,
102
184
  extensions: []
103
185
  }] : [{
104
- files: 'tsdown.config',
105
- extensions: ['ts', 'mts', 'cts', 'js', 'mjs', 'cjs', 'json', '']
186
+ files: "tsdown.config",
187
+ extensions: ["ts", "mts", "cts", "js", "mjs", "cjs", "json", ""]
106
188
  }, {
107
- files: 'package.json',
189
+ files: "package.json",
108
190
  extensions: [],
109
191
  rewrite: (config$1) => config$1?.tsdown
110
192
  },],
@@ -112,89 +194,47 @@ async function loadConfigFile(options) {
112
194
  defaults: {}
113
195
  });
114
196
  if (sources.length > 0) {
115
- logger.info(`Using tsdown config: ${sources.join(', ')}`);
197
+ logger.info(`Using tsdown config: ${sources.join(", ")}`);
116
198
  }
117
199
  return config;
118
200
  }
119
201
 
120
- //#endregion
121
- //#region src/features/clean.ts
122
- async function cleanOutDir(cwd, patterns) {
123
- const files = [];
124
- if (await fsExists(cwd)) files.push(...(await readdir(cwd)).map((file) => path$1.resolve(cwd, file)));
125
- if (patterns.length) {
126
- files.push(...await globby(patterns, {
127
- cwd,
128
- absolute: true
129
- }));
130
- }
131
- logger.info('Cleaning output folder');
132
- for (const file of files) {
133
- await rm(file, {
134
- force: true,
135
- recursive: true
136
- });
137
- }
138
- }
139
-
140
- //#endregion
141
- //#region src/utils/package.ts
142
- async function readPackageJson(dir) {
143
- const packageJsonPath = path.join(dir, 'package.json');
144
- const exists = await fsExists(packageJsonPath);
145
- if (!exists) return;
146
- return readPackageJSON(packageJsonPath);
147
- }
148
- function getPackageType(pkg) {
149
- if (pkg.type) {
150
- if (!['module', 'commonjs'].includes(pkg.type)) {
151
- throw new Error(`Invalid package.json type: ${pkg.type}`);
152
- }
153
- return pkg.type;
154
- }
155
- return 'commonjs';
156
- }
157
-
158
- //#endregion
159
- //#region src/features/output.ts
160
- function resolveOutputExtension(pkg, format) {
161
- const type = getPackageType(pkg);
162
- const isEsmFormat = ['es', 'esm', 'module'].includes(format);
163
- if (type === 'module') {
164
- if (isEsmFormat) return 'js';
165
- else return 'cjs';
166
- } else {
167
- if (isEsmFormat) return 'mjs';
168
- return 'js';
169
- }
170
- }
171
-
172
202
  //#endregion
173
203
  //#region src/index.ts
174
204
  async function build(userOptions = {}) {
175
- const { entry, external, plugins, outDir, format, clean, platform, alias, treeshake, dts } = await normalizeOptions(userOptions);
205
+ const resolved = await normalizeOptions(userOptions);
206
+ const { entry, external, plugins, outDir, format, clean, platform, alias, treeshake, dts, watch } = resolved;
176
207
  if (clean) await cleanOutDir(outDir, clean);
177
208
  const pkg = await readPackageJson(process.cwd());
209
+ let startTime = performance.now();
178
210
  const inputOptions = {
179
211
  input: entry,
180
212
  external,
181
- resolve: {alias},
213
+ resolve: { alias },
182
214
  treeshake,
183
215
  plugins: [ExternalPlugin(pkg, platform), dts && IsolatedDecl.rolldown(dts === true ? {} : dts), ...plugins,].filter((plugin) => !!plugin)
184
216
  };
185
217
  const build$1 = await rolldown(inputOptions);
186
- await Promise.all(format.map((format$1) => {
187
- const extension = resolveOutputExtension(pkg, format$1);
188
- return build$1.write({
189
- format: format$1,
190
- dir: outDir,
191
- entryFileNames: `[name].${extension}`,
192
- chunkFileNames: `[name]-[hash].${extension}`
193
- });
194
- }));
195
- await build$1.destroy();
196
- logger.info('Build complete');
197
- process.exit(0);
218
+ await writeBundle(true);
219
+ if (watch) {
220
+ await watchBuild(resolved, writeBundle);
221
+ } else {
222
+ await build$1.destroy();
223
+ process.exit(0);
224
+ }
225
+ async function writeBundle(first) {
226
+ if (!first) startTime = performance.now();
227
+ await Promise.all(format.map((format$1) => {
228
+ const extension = resolveOutputExtension(pkg, format$1);
229
+ return build$1.write({
230
+ format: format$1,
231
+ dir: outDir,
232
+ entryFileNames: `[name].${extension}`,
233
+ chunkFileNames: `[name]-[hash].${extension}`
234
+ });
235
+ }));
236
+ logger.success(`${first ? "Build" : "Rebuild"} complete in ${Math.round(performance.now() - startTime)}ms`);
237
+ }
198
238
  }
199
239
  function defineConfig(options) {
200
240
  return options;
@@ -1,7 +1,7 @@
1
1
  import { consola } from "consola";
2
2
 
3
3
  //#region src/utils/logger.ts
4
- const logger = consola.withTag('tsdown');
4
+ const logger = consola.withTag("tsdown");
5
5
 
6
6
  //#endregion
7
7
  export { logger };
package/dist/options.d.ts CHANGED
@@ -1,25 +1,26 @@
1
1
  import type { External } from './features/external';
2
2
  import type { InputOptions } from 'rolldown';
3
3
  import type { Options as IsolatedDeclOptions } from 'unplugin-isolated-decl';
4
- export type Format = (('es') | ('esm') | ('module') | ('cjs') | ('commonjs'));
4
+ export type Format = 'es' | 'esm' | 'module' | 'cjs' | 'commonjs';
5
5
  export interface Options {
6
6
  entry?: InputOptions['input'];
7
- format?: ((Format) | ((Format)[]));
7
+ format?: Format | Format[];
8
8
  plugins?: InputOptions['plugins'];
9
9
  external?: External;
10
10
  outDir?: string;
11
- clean?: ((boolean) | ((string)[]));
12
- config?: ((boolean) | (string));
11
+ clean?: boolean | string[];
12
+ config?: boolean | string;
13
13
  alias?: Record<string, string>;
14
14
  treeshake?: boolean;
15
- platform?: (('node') | ('neutral'));
16
- dts?: ((boolean) | (IsolatedDeclOptions));
15
+ platform?: 'node' | 'neutral';
16
+ dts?: boolean | IsolatedDeclOptions;
17
+ watch?: boolean | string | string[];
17
18
  }
18
19
  export type OptionsWithoutConfig = Omit<Options, 'config'>;
19
- type Overwrite<T, U> = (({ [P in Exclude<keyof T, keyof U>] : T[P]}) & (U));
20
+ type Overwrite<T, U> = { [P in Exclude<keyof T, keyof U>] : T[P]} & U;
20
21
  export type ResolvedOptions = Omit<Overwrite<Required<Options>, {
21
- format: (Format)[];
22
- clean: (((string)[]) | (false));
22
+ format: Format[];
23
+ clean: string[] | false;
23
24
  }>, 'config'>;
24
25
  export declare function normalizeOptions(options: Options): Promise<ResolvedOptions>;
25
26
  export {};
package/dist/plugins.js CHANGED
@@ -1,3 +1,3 @@
1
- import { ExternalPlugin } from "./external-BI3U5n3V.js";
1
+ import { ExternalPlugin } from "./external-uGOHYulu.js";
2
2
 
3
3
  export { ExternalPlugin };
package/dist/run.js CHANGED
@@ -1,25 +1,23 @@
1
- import { logger } from "./logger-39fy7Hdx.js";
1
+ import { logger } from "./logger-e0Fr5WMR.js";
2
2
  import { default as process } from "node:process";
3
3
  import { cac } from "cac";
4
4
 
5
5
  //#region package.json
6
- const version = '0.2.3';
7
- const files = ['dist'];
8
- const typesVersions = {'*': {'*': ['./dist/*', './*']}};
6
+ const version = "0.2.4";
9
7
 
10
8
  //#endregion
11
9
  //#region src/cli.ts
12
10
  async function runCLI() {
13
- const cli = cac('tsdown');
14
- cli.command('[...files]', 'Bundle files', {ignoreOptionDefaultValue: true}).option('-c, --config <filename>', 'Use a custom config file').option('--format <format>', 'Bundle format: esm, cjs, iife', {default: 'esm'}).option('--clean', 'Clean output directory').option('-d, --out-dir <dir>', 'Output directory', {default: 'dist'}).option('--treeshake', 'Tree-shake bundle', {default: true}).option('--platform <platform>', 'Target platform', {default: 'node'}).action(async (input, flags) => {
11
+ const cli = cac("tsdown");
12
+ 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("-d, --out-dir <dir>", "Output directory", { default: "dist" }).option("--treeshake", "Tree-shake bundle", { default: true }).option("--platform <platform>", "Target platform", { default: "node" }).option("--watch", "Watch mode").action(async (input, flags) => {
15
13
  logger.info(`tsdown v${version}`);
16
- const { build } = await import('./index.js');
14
+ const { build } = await import("./index.js");
17
15
  if (input.length > 0) flags.entry = input;
18
16
  await build(flags);
19
17
  });
20
18
  cli.help();
21
19
  cli.version(version);
22
- cli.parse(process.argv, {run: false});
20
+ cli.parse(process.argv, { run: false });
23
21
  try {
24
22
  await cli.runMatchedCommand();
25
23
  } catch (error) {
@@ -1 +1,2 @@
1
- export declare function toArray<T>(val: ((T) | ((T)[]) | (null) | (undefined)), defaultValue?: T): (T)[];
1
+ export declare function toArray<T>(val: T | T[] | null | undefined, defaultValue?: T): T[];
2
+ export declare function debounce<T extends (...args: any[]) => any>(fn: T, wait: number): T;
@@ -1,3 +1,3 @@
1
1
  import { type PackageJson } from 'pkg-types';
2
- export declare function readPackageJson(dir: string): Promise<((PackageJson) | (undefined))>;
3
- export declare function getPackageType(pkg: any): (('module') | ('commonjs'));
2
+ export declare function readPackageJson(dir: string): Promise<PackageJson | undefined>;
3
+ export declare function getPackageType(pkg: PackageJson | undefined): 'module' | 'commonjs';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tsdown",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
4
4
  "description": "An even faster bundler powered by Rolldown.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -40,24 +40,27 @@
40
40
  },
41
41
  "dependencies": {
42
42
  "cac": "^6.7.14",
43
+ "chokidar": "^3.6.0",
43
44
  "consola": "^3.2.3",
44
- "globby": "^14.0.1",
45
- "pkg-types": "^1.1.1",
45
+ "fast-glob": "^3.3.2",
46
+ "pkg-types": "^1.1.3",
46
47
  "rolldown": "nightly",
47
- "unconfig": "^0.4.4",
48
- "unplugin-isolated-decl": "^0.3.0"
48
+ "unconfig": "^0.5.5",
49
+ "unplugin-isolated-decl": "^0.4.1"
49
50
  },
50
51
  "devDependencies": {
51
- "@sxzz/eslint-config": "^3.13.0",
52
+ "@sxzz/eslint-config": "^3.16.3",
52
53
  "@sxzz/prettier-config": "^2.0.2",
53
- "@types/node": "^20.14.8",
54
- "bumpp": "^9.4.1",
55
- "eslint": "^9.5.0",
56
- "prettier": "^3.3.2",
57
- "tsup": "^8.1.0",
58
- "tsx": "^4.15.7",
59
- "typescript": "~5.5.2",
60
- "vitest": "^1.6.0"
54
+ "@types/node": "^20.14.14",
55
+ "bumpp": "^9.4.2",
56
+ "eslint": "^9.8.0",
57
+ "execa": "^9.3.0",
58
+ "fdir": "^6.2.0",
59
+ "prettier": "^3.3.3",
60
+ "tsup": "^8.2.4",
61
+ "tsx": "^4.16.5",
62
+ "typescript": "~5.5.4",
63
+ "vitest": "^2.0.5"
61
64
  },
62
65
  "engines": {
63
66
  "node": ">=18.0.0"