bunchee 4.3.4 → 4.4.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
@@ -64,7 +64,7 @@ Then use use the [exports field in package.json](https://nodejs.org/api/packages
64
64
  "files": ["dist"],
65
65
  "exports": {
66
66
  "import": "./dist/es/index.mjs",
67
- "require": "./dist/cjs/index.cjs"
67
+ "require": "./dist/cjs/index.js"
68
68
  },
69
69
  "scripts": {
70
70
  "build": "bunchee"
@@ -88,8 +88,8 @@ If you're build a TypeScript library, separate the types from the main entry fil
88
88
  "default": "./dist/es/index.mjs"
89
89
  },
90
90
  "require": {
91
- "types": "./dist/cjs/index.d.cts",
92
- "default": "./dist/cjs/index.cjs"
91
+ "types": "./dist/cjs/index.d.ts",
92
+ "default": "./dist/cjs/index.js"
93
93
  }
94
94
  },
95
95
  "scripts": {
@@ -107,13 +107,13 @@ If you're using TypeScript with Node 10 and Node 16 module resolution, you can u
107
107
  ```json
108
108
  {
109
109
  "files": ["dist"],
110
- "main": "./dist/cjs/index.cjs",
110
+ "main": "./dist/cjs/index.js",
111
111
  "module": "./dist/es/index.mjs",
112
112
  "types": "./dist/cjs/index.d.ts",
113
113
  "exports": {
114
114
  "import": {
115
- "types": "./dist/es/index.d.mts",
116
- "default": "./dist/es/index.mjs"
115
+ "types": "./dist/es/index.d.ts",
116
+ "default": "./dist/es/index.js"
117
117
  },
118
118
  "require": {
119
119
  "types": "./dist/cjs/index.d.cts",
@@ -268,6 +268,7 @@ If you're using `"use client"` or `"use server"` in a file that used as a depend
268
268
  - Types (`--dts`): Generate TypeScript declaration files along with assets.
269
269
  - Minify (`-m`): Compress output.
270
270
  - Watch (`-w`): Watch for source file changes.
271
+ - No Clean(`--no-clean`): Do not clean the dist folder before building. (default: `false`)
271
272
 
272
273
  ```sh
273
274
  cd <project-root-dir>
@@ -323,6 +324,21 @@ You can use `index.<export-type>.<ext>` to override the input source file for sp
323
324
 
324
325
  This will match the export name `"react-server"` and `"edge-light"` then use the corresponding input source file to build the bundle.
325
326
 
327
+ #### Auto Development and Production Mode
328
+
329
+ `process.env.NODE_ENV` is injected by default if present that you don't need to manually inject yourself. If you need to separate the development build and production build, `bunchee` provides different export conditions for development and production mode with `development` and `production` export conditions.
330
+
331
+ ```json
332
+ {
333
+ "exports": {
334
+ "development": "./dist/index.development.js",
335
+ "production": "./dist/index.production.js"
336
+ }
337
+ }
338
+ ```
339
+
340
+ Then you can use `bunchee` to build the development bundle and production bundle automatically.
341
+
326
342
  ### Wildcard Exports
327
343
 
328
344
  Bunchee implements the Node.js feature of using the asterisk `*` as a wildcard to match the exportable entry files.
@@ -439,6 +455,7 @@ await bundle(path.resolve('./src/index.ts'), {
439
455
  target: 'es2015', // ES syntax target
440
456
  runtime: 'nodejs', // 'browser' | 'nodejs'
441
457
  cwd: process.cwd(), // string
458
+ clean: true, // boolean
442
459
  })
443
460
  ```
444
461
 
package/dist/bin/cli.js CHANGED
@@ -3,6 +3,7 @@ var path = require('path');
3
3
  var arg = require('arg');
4
4
  var fs = require('fs');
5
5
  var fsp = require('fs/promises');
6
+ require('rimraf');
6
7
  var require$$0 = require('tty');
7
8
  var bunchee = require('bunchee');
8
9
 
@@ -25,6 +26,7 @@ const availableExtensions = new Set([
25
26
  'mts'
26
27
  ]);
27
28
  const SRC = 'src';
29
+ const DIST = 'dist';
28
30
  const dtsExtensionsMap = {
29
31
  js: 'd.ts',
30
32
  cjs: 'd.cts',
@@ -36,6 +38,12 @@ const tsExtensions = new Set([
36
38
  'cts',
37
39
  'mts'
38
40
  ]);
41
+ const DEFAULT_TS_CONFIG = {
42
+ compilerOptions: {
43
+ module: 'ESNext',
44
+ moduleResolution: 'bundler'
45
+ }
46
+ };
39
47
 
40
48
  function getDefaultExportFromCjs (x) {
41
49
  return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
@@ -86,8 +94,9 @@ let createColors = (enabled = isColorSupported)=>({
86
94
  });
87
95
  picocolors.exports = createColors();
88
96
  picocolors.exports.createColors = createColors;
97
+
89
98
  var picocolorsExports = picocolors.exports;
90
- var pc = /*@__PURE__*/ getDefaultExportFromCjs(picocolorsExports);
99
+ var pc = /*@__PURE__*/getDefaultExportFromCjs(picocolorsExports);
91
100
 
92
101
  const defaultColorFn = (text)=>text;
93
102
  function color(prefixColor) {
@@ -140,22 +149,379 @@ function fileExists(filePath) {
140
149
  return fs__default.default.existsSync(filePath);
141
150
  }
142
151
  const hasAvailableExtension = (filename)=>availableExtensions.has(path__default.default.extname(filename).slice(1));
152
+ const hasCjsExtension = (filename)=>path__default.default.extname(filename) === '.cjs';
143
153
  // TODO: add unit test
144
154
  const baseNameWithoutExtension = (filename)=>path__default.default.basename(filename, path__default.default.extname(filename));
155
+ const isTestFile = (filename)=>/\.(test|spec)$/.test(baseNameWithoutExtension(filename));
156
+
157
+ function getTypings(pkg) {
158
+ return pkg.types || pkg.typings;
159
+ }
160
+ // Reached the end of the export path
161
+ function isExportLike(field) {
162
+ if (typeof field === 'string') return true;
163
+ return Object.entries(field).every(// Every value is string and key is not start with '.'
164
+ ([key, value])=>typeof value === 'string' && !key.startsWith('.'));
165
+ }
166
+ function constructFullExportCondition(exportCondition, packageType) {
167
+ let fullExportCond;
168
+ if (typeof exportCondition === 'string') {
169
+ const exportType = getExportTypeFromFile(exportCondition, packageType);
170
+ fullExportCond = {
171
+ [exportType]: exportCondition
172
+ };
173
+ } else {
174
+ const exportTypes = Object.keys(exportCondition);
175
+ fullExportCond = {};
176
+ exportTypes.forEach((exportType)=>{
177
+ const condition = exportCondition[exportType];
178
+ // Filter out nullable value
179
+ if (condition) {
180
+ fullExportCond[exportType] = condition;
181
+ }
182
+ });
183
+ }
184
+ return fullExportCond;
185
+ }
186
+ function joinRelativePath(...segments) {
187
+ let result = path.join(...segments);
188
+ // If the first segment starts with '.', ensure the result does too.
189
+ if (segments[0] === '.' && !result.startsWith('.')) {
190
+ result = './' + result;
191
+ }
192
+ return result;
193
+ }
194
+ const getFirstExportPath = (fullExportCondition)=>{
195
+ // Handle all export cond { <require|import|default>: ... }
196
+ if (typeof fullExportCondition === 'object') {
197
+ for (const key of Object.keys(fullExportCondition)){
198
+ if (key.startsWith('.') || key === 'types') {
199
+ continue;
200
+ }
201
+ return fullExportCondition[key];
202
+ }
203
+ }
204
+ return fullExportCondition;
205
+ };
206
+ function findExport(exportPath, exportCondition, paths, packageType, currentPath) {
207
+ // Skip `types` field, it cannot be the entry point
208
+ if (exportPath === 'types') return;
209
+ if (isExportLike(exportCondition)) {
210
+ const fullExportCondition = constructFullExportCondition(exportCondition, packageType);
211
+ if (exportPath.startsWith('.')) {
212
+ paths[exportPath] = {
213
+ ...paths[exportPath],
214
+ ...fullExportCondition
215
+ };
216
+ } else {
217
+ const exportJsBundlePath = getFirstExportPath(fullExportCondition);
218
+ // exportPath is exportType, import, require, ...
219
+ // merge to currentPath
220
+ paths[currentPath] = {
221
+ ...paths[currentPath],
222
+ [exportPath]: exportJsBundlePath
223
+ };
224
+ }
225
+ return;
226
+ }
227
+ Object.keys(exportCondition).forEach((subpath)=>{
228
+ if (subpath.startsWith('.')) {
229
+ // subpath is actual export path, ./a, ./b, ...
230
+ const nestedExportPath = joinRelativePath(currentPath, subpath);
231
+ const nestedExportCondition = exportCondition[subpath];
232
+ findExport(nestedExportPath, nestedExportCondition, paths, packageType, nestedExportPath);
233
+ } else {
234
+ // subpath is exportType, import, require, ...
235
+ const exportType = subpath;
236
+ const defaultPath = typeof exportCondition[subpath] === 'object' ? exportCondition[subpath].default : exportCondition[subpath];
237
+ const nestedExportCondition = {
238
+ [exportType]: defaultPath
239
+ };
240
+ findExport(exportPath, nestedExportCondition, paths, packageType, currentPath);
241
+ }
242
+ });
243
+ }
244
+ /**
245
+ *
246
+ * Convert package.exports field to paths mapping
247
+ * Example
248
+ *
249
+ * Input:
250
+ * {
251
+ * "./sub": {
252
+ * "import": {
253
+ * "types": "./sub.js",
254
+ * "default": "./sub.cjs",
255
+ * }
256
+ * }
257
+ * }
258
+ *
259
+ * Output:
260
+ * {
261
+ * "./sub": {
262
+ * "import": "./sub.js",
263
+ * "require": "./sub.cjs",
264
+ * "types": "./sub.d.ts",
265
+ * }
266
+ * }
267
+ *
268
+ */ function parseExport(exportsCondition, packageType) {
269
+ const paths = {};
270
+ const initialPath = '.';
271
+ if (typeof exportsCondition === 'string') {
272
+ paths[initialPath] = constructFullExportCondition(exportsCondition, packageType);
273
+ } else if (typeof exportsCondition === 'object') {
274
+ if (isExportLike(exportsCondition)) {
275
+ paths[initialPath] = constructFullExportCondition(exportsCondition, packageType);
276
+ } else {
277
+ Object.keys(exportsCondition).forEach((key)=>{
278
+ const exportCondition = exportsCondition[key];
279
+ findExport(key, exportCondition, paths, packageType, initialPath);
280
+ });
281
+ }
282
+ }
283
+ return paths;
284
+ }
285
+ /**
286
+ * Get package exports paths
287
+ *
288
+ * Example:
289
+ *
290
+ * ```json
291
+ * {
292
+ * "exports": {
293
+ * ".": {
294
+ * "require": "./dist/index.cjs",
295
+ * "module": "./dist/index.esm.js",
296
+ * "default": "./dist/index.esm.js"
297
+ * },
298
+ * "./foo": {
299
+ * "require": "./dist/foo.cjs",
300
+ * "module": "./dist/foo.esm.js",
301
+ * "default": "./dist/foo.esm.js"
302
+ * }
303
+ * }
304
+ *
305
+ * ```
306
+ *
307
+ * will be parsed to:
308
+ *
309
+ * ```js
310
+ * {
311
+ * '.': {
312
+ * main: './dist/index.cjs',
313
+ * module: './dist/index.esm.js',
314
+ * export: './dist/index.esm.js'
315
+ * },
316
+ * './foo': {
317
+ * main: './dist/foo.cjs',
318
+ * module: './dist/foo.esm.js',
319
+ * export: './dist/foo.esm.js'
320
+ * }
321
+ *
322
+ *
323
+ * pkg.main and pkg.module will be added to ['.'] if exists
324
+ */ function getExportPaths(pkg, resolvedWildcardExports) {
325
+ var _pathsMap_;
326
+ let pathsMap = {};
327
+ const packageType = getPackageType(pkg);
328
+ const isEsmPackage = isESModulePackage(packageType);
329
+ const exportsConditions = resolvedWildcardExports != null ? resolvedWildcardExports : pkg.exports;
330
+ if (exportsConditions) {
331
+ const paths = parseExport(exportsConditions, packageType);
332
+ pathsMap = {
333
+ ...pathsMap,
334
+ ...paths
335
+ };
336
+ }
337
+ // main export '.' from main/module/typings
338
+ let mainExportCondition;
339
+ if (pkg.main) {
340
+ const mainExportType = isEsmPackage ? hasCjsExtension(pkg.main) ? 'require' : 'import' : 'require';
341
+ mainExportCondition = {
342
+ [mainExportType]: pkg.main
343
+ };
344
+ }
345
+ const defaultMainExport = constructFullExportCondition({
346
+ ...mainExportCondition,
347
+ module: pkg.module,
348
+ types: getTypings(pkg)
349
+ }, packageType);
350
+ if (!isEsmPackage && ((_pathsMap_ = pathsMap['.']) == null ? void 0 : _pathsMap_['require'])) {
351
+ // pathsMap's exports.require are prioritized.
352
+ defaultMainExport['require'] = pathsMap['.']['require'];
353
+ }
354
+ // Merge the main export into '.' paths
355
+ const mainExport = {
356
+ ...pathsMap['.'],
357
+ ...defaultMainExport
358
+ };
359
+ // main export is not empty
360
+ if (Object.keys(mainExport).length > 0) {
361
+ pathsMap['.'] = {
362
+ ...pathsMap['.'],
363
+ ...mainExport
364
+ };
365
+ }
366
+ return pathsMap;
367
+ }
368
+ function getPackageType(pkg) {
369
+ return pkg.type || 'commonjs';
370
+ }
371
+ function isESModulePackage(packageType) {
372
+ return packageType === 'module';
373
+ }
374
+ function getExportTypeFromFile(filename, pkgType) {
375
+ const isESModule = isESModulePackage(pkgType);
376
+ const isCjsExt = filename.endsWith('.cjs');
377
+ const isEsmExt = filename.endsWith('.mjs');
378
+ const exportType = isEsmExt ? 'import' : isCjsExt ? 'require' : isESModule ? 'import' : 'require';
379
+ return exportType;
380
+ }
381
+
382
+ function lint$1(pkg) {
383
+ const { name, main, exports } = pkg;
384
+ const isESM = isESModulePackage(pkg.type);
385
+ const exportPaths = getExportPaths(pkg);
386
+ if (!name) {
387
+ logger.warn('Missing package name');
388
+ }
389
+ const state = {
390
+ badMainExtension: false,
391
+ badMainExport: false,
392
+ invalidExportsFieldType: false,
393
+ badCjsRequireExport: {
394
+ value: false,
395
+ paths: []
396
+ },
397
+ badCjsImportExport: {
398
+ value: false,
399
+ paths: []
400
+ },
401
+ badEsmRequireExport: {
402
+ value: false,
403
+ paths: []
404
+ },
405
+ badEsmImportExport: {
406
+ value: false,
407
+ paths: []
408
+ }
409
+ };
410
+ // Validate ESM package
411
+ if (isESM) {
412
+ if (exports) {
413
+ if (typeof exports === 'string') {
414
+ if (hasCjsExtension(exports)) {
415
+ state.badMainExport = true;
416
+ }
417
+ }
418
+ if (typeof exports !== 'object') {
419
+ state.invalidExportsFieldType = true;
420
+ } else {
421
+ Object.keys(exportPaths).forEach((key)=>{
422
+ const exportConditions = exportPaths[key];
423
+ if (typeof exportConditions === 'object') {
424
+ var // @ts-ignore TODO: fix the type
425
+ _exportConditions_require, // @ts-ignore TODO: fix the type
426
+ _exportConditions_import;
427
+ var _exportConditions_require_default;
428
+ const requirePath = (_exportConditions_require_default = (_exportConditions_require = exportConditions.require) == null ? void 0 : _exportConditions_require.default) != null ? _exportConditions_require_default : exportConditions.require;
429
+ var _exportConditions_import_default;
430
+ const importPath = (_exportConditions_import_default = (_exportConditions_import = exportConditions.import) == null ? void 0 : _exportConditions_import.default) != null ? _exportConditions_import_default : exportConditions.import;
431
+ const requireExt = requirePath && path__default.default.extname(requirePath);
432
+ const importExt = importPath && path__default.default.extname(importPath);
433
+ if (requireExt === '.mjs' || requireExt === '.js') {
434
+ state.badEsmRequireExport.value = true;
435
+ state.badEsmRequireExport.paths.push(requirePath);
436
+ }
437
+ if (importExt === '.cjs') {
438
+ state.badEsmImportExport.value = true;
439
+ state.badEsmImportExport.paths.push(importPath);
440
+ }
441
+ }
442
+ });
443
+ }
444
+ }
445
+ } else {
446
+ if (main && path__default.default.extname(main) === '.mjs') {
447
+ state.badMainExtension = true;
448
+ }
449
+ // Validate CJS package
450
+ if (exports) {
451
+ if (typeof exports === 'string') {
452
+ if (!hasCjsExtension(exports)) {
453
+ state.badMainExport = true;
454
+ }
455
+ }
456
+ if (typeof exports !== 'object') {
457
+ state.invalidExportsFieldType = true;
458
+ } else {
459
+ Object.keys(exportPaths).forEach((key)=>{
460
+ const exportConditions = exportPaths[key];
461
+ if (typeof exportConditions === 'object') {
462
+ var // @ts-ignore TODO: fix the type
463
+ _exportConditions_require, // @ts-ignore TODO: fix the type
464
+ _exportConditions_import;
465
+ var _exportConditions_require_default;
466
+ const requirePath = (_exportConditions_require_default = (_exportConditions_require = exportConditions.require) == null ? void 0 : _exportConditions_require.default) != null ? _exportConditions_require_default : exportConditions.require;
467
+ var _exportConditions_import_default;
468
+ const importPath = (_exportConditions_import_default = (_exportConditions_import = exportConditions.import) == null ? void 0 : _exportConditions_import.default) != null ? _exportConditions_import_default : exportConditions.import;
469
+ const requireExt = requirePath && path__default.default.extname(requirePath);
470
+ const importExt = importPath && path__default.default.extname(importPath);
471
+ if (requireExt === '.mjs') {
472
+ state.badCjsRequireExport.value = true;
473
+ state.badCjsRequireExport.paths.push(requirePath);
474
+ }
475
+ if (importExt === '.js' || importExt === '.cjs') {
476
+ state.badCjsImportExport.value = true;
477
+ state.badCjsImportExport.paths.push(importPath);
478
+ }
479
+ }
480
+ });
481
+ }
482
+ }
483
+ }
484
+ if (state.badMainExtension) {
485
+ logger.warn('Cannot export `main` field with .mjs extension in CJS package, only .js extension is allowed');
486
+ }
487
+ if (state.badMainExport) {
488
+ logger.warn('Cannot export `exports` field with .cjs extension in ESM package, only .mjs and .js extensions are allowed');
489
+ }
490
+ if (state.invalidExportsFieldType) {
491
+ logger.warn('Invalid exports field type, only object or string is allowed');
492
+ }
493
+ if (state.badCjsRequireExport.value) {
494
+ logger.warn('Cannot export `require` field with .mjs extension in CJS package, only .cjs and .js extensions are allowed');
495
+ state.badCjsRequireExport.paths.forEach((p)=>{
496
+ logger.warn(` ${p}`);
497
+ });
498
+ }
499
+ if (state.badCjsImportExport.value) {
500
+ logger.warn('Cannot export `import` field with .js or .cjs extension in CJS package, only .mjs extensions are allowed');
501
+ state.badCjsImportExport.paths.forEach((p)=>{
502
+ logger.warn(` ${p}`);
503
+ });
504
+ }
505
+ if (state.badEsmRequireExport.value) {
506
+ logger.warn('Cannot export `require` field with .js or .mjs extension in ESM package, only .cjs extensions are allowed');
507
+ state.badEsmRequireExport.paths.forEach((p)=>{
508
+ logger.warn(` ${p}`);
509
+ });
510
+ }
511
+ if (state.badEsmImportExport.value) {
512
+ logger.warn('Cannot export `import` field with .cjs extension in ESM package, only .js and .mjs extensions are allowed');
513
+ state.badEsmImportExport.paths.forEach((p)=>{
514
+ logger.warn(` ${p}`);
515
+ });
516
+ }
517
+ }
145
518
 
146
- var version = "4.3.4";
519
+ var version = "4.4.1";
147
520
 
148
521
  function relativify(path) {
149
522
  return path.startsWith('.') ? path : `./${path}`;
150
523
  }
151
524
 
152
- const DIST = 'dist';
153
- const DEFAULT_TS_CONFIG = {
154
- compilerOptions: {
155
- module: 'ESNext',
156
- moduleResolution: 'bundler'
157
- }
158
- };
159
525
  // Output with posix style in package.json
160
526
  function getDistPath(...subPaths) {
161
527
  return `./${DIST}/${subPaths.join('/')}`;
@@ -213,7 +579,7 @@ async function collectSourceEntries(sourceFolderPath) {
213
579
  // Search folder/<index>.<ext> convention entries
214
580
  for (const extension of availableExtensions){
215
581
  const indexFile = path__default.default.join(dirent.name, `index.${extension}`);
216
- if (fs__default.default.existsSync(indexFile)) {
582
+ if (fs__default.default.existsSync(indexFile) && !isTestFile(indexFile)) {
217
583
  exportsEntries.set(dirent.name, indexFile);
218
584
  break;
219
585
  }
@@ -227,7 +593,7 @@ async function collectSourceEntries(sourceFolderPath) {
227
593
  if (isBinFile) {
228
594
  bins.set('.', dirent.name);
229
595
  } else {
230
- if (hasAvailableExtension(dirent.name)) {
596
+ if (hasAvailableExtension(dirent.name) && !isTestFile(dirent.name)) {
231
597
  exportsEntries.set(baseName, dirent.name);
232
598
  }
233
599
  }
@@ -351,7 +717,9 @@ async function prepare(cwd) {
351
717
  } else {
352
718
  // Update existing exports
353
719
  Object.keys(pkgExports).forEach((exportName)=>{
354
- pkgJson.exports[exportName] = pkgExports[exportName];
720
+ if (pkgJson.exports[exportName]) {
721
+ pkgJson.exports[exportName] = pkgExports[exportName];
722
+ }
355
723
  });
356
724
  }
357
725
  }
@@ -373,6 +741,7 @@ Options:
373
741
  --prepare auto configure package.json exports for building
374
742
  --external <mod> specify an external dependency, separate by comma
375
743
  --no-external do not bundle external dependencies
744
+ --no-clean do not clean dist folder before building, default: false
376
745
  --target <target> js features target: swc target es versions. default: es2015
377
746
  --runtime <runtime> build runtime (nodejs, browser). default: browser
378
747
  --env <env> inlined process env variables, separate by comma. default: NODE_ENV
@@ -383,21 +752,12 @@ Options:
383
752
  function help() {
384
753
  logger.log(helpMessage);
385
754
  }
386
- async function lintPackage(cwd) {
755
+ async function lint(cwd) {
387
756
  // Not package.json detected, skip package linting
388
757
  if (!await hasPackageJson(cwd)) {
389
758
  return;
390
759
  }
391
- const { publint } = await import('publint');
392
- const { formatMessage } = await import('publint/utils');
393
- const { messages } = await publint({
394
- pkgDir: cwd,
395
- level: 'error'
396
- });
397
- const pkg = await getPackageMeta(cwd);
398
- for (const message of messages){
399
- console.log(formatMessage(message, pkg));
400
- }
760
+ await lint$1(await getPackageMeta(cwd));
401
761
  }
402
762
  function parseCliArgs(argv) {
403
763
  let args;
@@ -416,6 +776,7 @@ function parseCliArgs(argv) {
416
776
  '--env': String,
417
777
  '--external': String,
418
778
  '--no-external': Boolean,
779
+ '--no-clean': Boolean,
419
780
  '--prepare': Boolean,
420
781
  '-h': '--help',
421
782
  '-v': '--version',
@@ -442,6 +803,7 @@ function parseCliArgs(argv) {
442
803
  runtime: args['--runtime'],
443
804
  target: args['--target'],
444
805
  external: !!args['--no-external'] ? null : args['--external'],
806
+ clean: !args['--no-clean'],
445
807
  env: args['--env'],
446
808
  prepare: !!args['--prepare']
447
809
  };
@@ -449,7 +811,7 @@ function parseCliArgs(argv) {
449
811
  }
450
812
  async function run(args) {
451
813
  var _args_external;
452
- const { source, format, watch, minify, sourcemap, target, runtime, dts, env } = args;
814
+ const { source, format, watch, minify, sourcemap, target, runtime, dts, env, clean } = args;
453
815
  const cwd = args.cwd || process.cwd();
454
816
  const file = args.file ? path__default.default.resolve(cwd, args.file) : undefined;
455
817
  const bundleConfig = {
@@ -463,7 +825,8 @@ async function run(args) {
463
825
  watch: !!watch,
464
826
  minify: !!minify,
465
827
  sourcemap: sourcemap === false ? false : true,
466
- env: (env == null ? void 0 : env.split(',')) || []
828
+ env: (env == null ? void 0 : env.split(',')) || [],
829
+ clean
467
830
  };
468
831
  if (args.version) {
469
832
  return logger.log(version);
@@ -474,9 +837,11 @@ async function run(args) {
474
837
  if (args.prepare) {
475
838
  return await prepare(cwd);
476
839
  }
477
- const entry = source ? path__default.default.resolve(cwd, source) : '';
840
+ const cliEntry = source ? path__default.default.resolve(cwd, source) : '';
841
+ // lint package
842
+ await lint(cwd);
478
843
  try {
479
- await bunchee.bundle(entry, bundleConfig);
844
+ await bunchee.bundle(cliEntry, bundleConfig);
480
845
  } catch (err) {
481
846
  if (err.name === 'NOT_EXISTED') {
482
847
  help();
@@ -492,7 +857,6 @@ async function run(args) {
492
857
  // build mode
493
858
  logger.log();
494
859
  paint('✓', 'green', `bunchee ${version} build completed`);
495
- await lintPackage(cwd);
496
860
  }
497
861
  async function main() {
498
862
  let params, error;
package/dist/index.d.ts CHANGED
@@ -17,6 +17,7 @@ type BundleConfig = {
17
17
  dts?: boolean;
18
18
  runtime?: string;
19
19
  pkg?: PackageMetadata;
20
+ clean?: boolean;
20
21
  };
21
22
  type PackageMetadata = {
22
23
  name?: string;
@@ -32,6 +33,6 @@ type PackageMetadata = {
32
33
  typings?: string;
33
34
  };
34
35
 
35
- declare function bundle(entryPath: string, { cwd: _cwd, ...options }?: BundleConfig): Promise<any>;
36
+ declare function bundle(cliEntryPath: string, { cwd: _cwd, ...options }?: BundleConfig): Promise<any>;
36
37
 
37
38
  export { type BundleConfig, bundle };
package/dist/index.js CHANGED
@@ -4,8 +4,9 @@ var rollup = require('rollup');
4
4
  var fsp = require('fs/promises');
5
5
  var fs = require('fs');
6
6
  var path = require('path');
7
- var module$1 = require('module');
8
7
  var require$$0 = require('tty');
8
+ var module$1 = require('module');
9
+ var rimraf = require('rimraf');
9
10
  var pluginWasm = require('@rollup/plugin-wasm');
10
11
  var rollupPluginSwc3 = require('rollup-plugin-swc3');
11
12
  var commonjs = require('@rollup/plugin-commonjs');
@@ -14,6 +15,7 @@ var pluginNodeResolve = require('@rollup/plugin-node-resolve');
14
15
  var replace = require('@rollup/plugin-replace');
15
16
  var esmShim = require('@rollup/plugin-esm-shim');
16
17
  var preserveDirectives = require('rollup-preserve-directives');
18
+ var CleanCSS = require('clean-css');
17
19
  var pluginutils = require('@rollup/pluginutils');
18
20
  var prettyBytes = require('pretty-bytes');
19
21
 
@@ -28,47 +30,9 @@ var json__default = /*#__PURE__*/_interopDefault(json);
28
30
  var replace__default = /*#__PURE__*/_interopDefault(replace);
29
31
  var esmShim__default = /*#__PURE__*/_interopDefault(esmShim);
30
32
  var preserveDirectives__default = /*#__PURE__*/_interopDefault(preserveDirectives);
33
+ var CleanCSS__default = /*#__PURE__*/_interopDefault(CleanCSS);
31
34
  var prettyBytes__default = /*#__PURE__*/_interopDefault(prettyBytes);
32
35
 
33
- const availableExtensions = new Set([
34
- 'js',
35
- 'cjs',
36
- 'mjs',
37
- 'jsx',
38
- 'ts',
39
- 'tsx',
40
- 'cts',
41
- 'mts'
42
- ]);
43
- const nodeResolveExtensions = [
44
- '.mjs',
45
- '.cjs',
46
- '.js',
47
- '.json',
48
- '.node',
49
- '.jsx'
50
- ];
51
- const availableExportConventions = new Set([
52
- 'react-server',
53
- 'react-native',
54
- 'edge-light'
55
- ]);
56
- const availableESExtensionsRegex = /\.(m|c)?[jt]sx?$/;
57
- const SRC = 'src';
58
- const dtsExtensionsMap = {
59
- js: 'd.ts',
60
- cjs: 'd.cts',
61
- mjs: 'd.mts'
62
- };
63
- const disabledWarnings = new Set([
64
- 'MIXED_EXPORTS',
65
- 'PREFER_NAMED_EXPORTS',
66
- 'UNRESOLVED_IMPORT',
67
- 'THIS_IS_UNDEFINED',
68
- 'INVALID_ANNOTATION',
69
- 'UNUSED_EXTERNAL_IMPORT'
70
- ]);
71
-
72
36
  function getDefaultExportFromCjs (x) {
73
37
  return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
74
38
  }
@@ -118,8 +82,62 @@ let createColors = (enabled = isColorSupported)=>({
118
82
  });
119
83
  picocolors.exports = createColors();
120
84
  picocolors.exports.createColors = createColors;
85
+
121
86
  var picocolorsExports = picocolors.exports;
122
- var pc = /*@__PURE__*/ getDefaultExportFromCjs(picocolorsExports);
87
+ var pc = /*@__PURE__*/getDefaultExportFromCjs(picocolorsExports);
88
+
89
+ const availableExtensions = new Set([
90
+ 'js',
91
+ 'cjs',
92
+ 'mjs',
93
+ 'jsx',
94
+ 'ts',
95
+ 'tsx',
96
+ 'cts',
97
+ 'mts'
98
+ ]);
99
+ const nodeResolveExtensions = [
100
+ '.mjs',
101
+ '.cjs',
102
+ '.js',
103
+ '.json',
104
+ '.node',
105
+ '.jsx'
106
+ ];
107
+ const suffixedExportConventions = new Set([
108
+ 'react-server',
109
+ 'react-native',
110
+ 'edge-light',
111
+ 'development',
112
+ 'production'
113
+ ]);
114
+ const availableESExtensionsRegex = /\.(m|c)?[jt]sx?$/;
115
+ const SRC = 'src';
116
+ const dtsExtensionsMap = {
117
+ js: 'd.ts',
118
+ cjs: 'd.cts',
119
+ mjs: 'd.mts'
120
+ };
121
+ const disabledWarnings = new Set([
122
+ 'MIXED_EXPORTS',
123
+ 'PREFER_NAMED_EXPORTS',
124
+ 'UNRESOLVED_IMPORT',
125
+ 'THIS_IS_UNDEFINED',
126
+ 'INVALID_ANNOTATION',
127
+ 'UNUSED_EXTERNAL_IMPORT'
128
+ ]);
129
+ const tsExtensions = new Set([
130
+ 'ts',
131
+ 'tsx',
132
+ 'cts',
133
+ 'mts'
134
+ ]);
135
+ const DEFAULT_TS_CONFIG = {
136
+ compilerOptions: {
137
+ module: 'ESNext',
138
+ moduleResolution: 'bundler'
139
+ }
140
+ };
123
141
 
124
142
  const defaultColorFn = (text)=>text;
125
143
  function color(prefixColor) {
@@ -154,15 +172,24 @@ async function getPackageMeta(cwd) {
154
172
  } catch (_) {}
155
173
  return targetPackageJson;
156
174
  }
175
+ function isTypescriptFile(filename) {
176
+ const ext = path__default.default.extname(filename).slice(1);
177
+ return tsExtensions.has(ext);
178
+ }
157
179
  function fileExists(filePath) {
158
180
  return fs__default.default.existsSync(filePath);
159
181
  }
160
- // . -> pkg name
161
- // ./lite -> <pkg name>/lite
162
- function getExportPath(pkg, cwd, exportName) {
163
- const name = pkg.name || path__default.default.basename(cwd);
164
- if (exportName === '.' || !exportName) return name;
165
- return path__default.default.join(name, exportName);
182
+ async function removeDir(dirPath) {
183
+ try {
184
+ const dirStat = await fsp__default.default.stat(dirPath);
185
+ if (dirStat.isDirectory()) {
186
+ await rimraf.rimraf(dirPath);
187
+ }
188
+ } catch (err) {
189
+ if (err.code !== 'ENOENT') {
190
+ throw err;
191
+ }
192
+ }
166
193
  }
167
194
  const isNotNull = (n)=>Boolean(n);
168
195
  function resolveSourceFile(cwd, filename) {
@@ -191,7 +218,7 @@ async function getSourcePathFromExportPath(cwd, exportPath, exportType) {
191
218
  if (exportPath === '.') exportPath = './index';
192
219
  // Find convention-based source file for specific export types
193
220
  // $binary represents `pkg.bin`
194
- if (availableExportConventions.has(exportType) && exportType !== '$binary') {
221
+ if (suffixedExportConventions.has(exportType) && exportType !== '$binary') {
195
222
  const filename = await findSourceEntryFile(cwd, exportPath, exportType, ext);
196
223
  if (filename) return filename;
197
224
  }
@@ -249,14 +276,6 @@ async function convertCompilerOptions(cwd, json) {
249
276
  return ts.convertCompilerOptionsFromJson(json, './');
250
277
  }
251
278
 
252
- function minifyCSS(content) {
253
- return content.replace(/\/\*[\s\S]*?\*\/|([^:]|^)\/\/.*$|(?:^|\s)(\s+)|\s*([\{\};,:])\s*|\s+(!)\s+/g, (match, p1, p2, p3, p4)=>{
254
- if (p1) return p1 === ' ' ? '' : p1;
255
- if (p2) return ' ';
256
- if (p3) return p3;
257
- if (p4) return '!';
258
- });
259
- }
260
279
  const helpers = {
261
280
  cssImport: {
262
281
  // have to assign r.type = 'text/css' to make it work in Safari
@@ -284,6 +303,10 @@ export default sheet`;
284
303
  }
285
304
  }
286
305
  };
306
+ const cleanCssInstance = new CleanCSS__default.default({});
307
+ function minify(code) {
308
+ return cleanCssInstance.minify(code).styles;
309
+ }
287
310
  function inlineCss(options) {
288
311
  const cssIds = new Set();
289
312
  var _options_exclude;
@@ -296,7 +319,7 @@ function inlineCss(options) {
296
319
  transform (code, id) {
297
320
  if (!filter(id)) return;
298
321
  if (options.skip) return '';
299
- const cssCode = minifyCSS(code);
322
+ const cssCode = minify(code);
300
323
  cssIds.add(id);
301
324
  return {
302
325
  code: helpers.cssImport.create(cssCode),
@@ -305,7 +328,7 @@ function inlineCss(options) {
305
328
  }
306
329
  };
307
330
  },
308
- renderChunk (code, options) {
331
+ renderChunk (code) {
309
332
  const dependenciesIds = this.getModuleIds();
310
333
  let foundCss = false;
311
334
  for (const depId of dependenciesIds){
@@ -428,6 +451,18 @@ function joinRelativePath(...segments) {
428
451
  }
429
452
  return result;
430
453
  }
454
+ const getFirstExportPath = (fullExportCondition)=>{
455
+ // Handle all export cond { <require|import|default>: ... }
456
+ if (typeof fullExportCondition === 'object') {
457
+ for (const key of Object.keys(fullExportCondition)){
458
+ if (key.startsWith('.') || key === 'types') {
459
+ continue;
460
+ }
461
+ return fullExportCondition[key];
462
+ }
463
+ }
464
+ return fullExportCondition;
465
+ };
431
466
  function findExport(exportPath, exportCondition, paths, packageType, currentPath) {
432
467
  // Skip `types` field, it cannot be the entry point
433
468
  if (exportPath === 'types') return;
@@ -439,11 +474,12 @@ function findExport(exportPath, exportCondition, paths, packageType, currentPath
439
474
  ...fullExportCondition
440
475
  };
441
476
  } else {
477
+ const exportJsBundlePath = getFirstExportPath(fullExportCondition);
442
478
  // exportPath is exportType, import, require, ...
443
479
  // merge to currentPath
444
480
  paths[currentPath] = {
445
481
  ...paths[currentPath],
446
- [exportPath]: fullExportCondition.default
482
+ [exportPath]: exportJsBundlePath
447
483
  };
448
484
  }
449
485
  return;
@@ -545,10 +581,10 @@ function findExport(exportPath, exportCondition, paths, packageType, currentPath
545
581
  *
546
582
  *
547
583
  * pkg.main and pkg.module will be added to ['.'] if exists
548
- */ function getExportPaths(pkg, pkgType, resolvedWildcardExports) {
584
+ */ function getExportPaths(pkg, resolvedWildcardExports) {
549
585
  var _pathsMap_;
550
586
  let pathsMap = {};
551
- const packageType = pkgType != null ? pkgType : getPackageType(pkg);
587
+ const packageType = getPackageType(pkg);
552
588
  const isEsmPackage = isESModulePackage(packageType);
553
589
  const exportsConditions = resolvedWildcardExports != null ? resolvedWildcardExports : pkg.exports;
554
590
  if (exportsConditions) {
@@ -558,12 +594,16 @@ function findExport(exportPath, exportCondition, paths, packageType, currentPath
558
594
  ...paths
559
595
  };
560
596
  }
561
- if (isEsmPackage && pkg.main && hasCjsExtension(pkg.main)) {
562
- exit('Cannot export main field with .cjs extension in ESM package, only .mjs and .js extensions are allowed');
563
- }
564
597
  // main export '.' from main/module/typings
598
+ let mainExportCondition;
599
+ if (pkg.main) {
600
+ const mainExportType = isEsmPackage ? hasCjsExtension(pkg.main) ? 'require' : 'import' : 'require';
601
+ mainExportCondition = {
602
+ [mainExportType]: pkg.main
603
+ };
604
+ }
565
605
  const defaultMainExport = constructFullExportCondition({
566
- [isEsmPackage ? 'import' : 'require']: pkg.main,
606
+ ...mainExportCondition,
567
607
  module: pkg.module,
568
608
  types: getTypings(pkg)
569
609
  }, packageType);
@@ -668,7 +708,8 @@ const swcMinifyOptions = {
668
708
  toplevel: true
669
709
  }
670
710
  };
671
- function getBuildEnv(envs) {
711
+ // return { 'process.env.<key>': '<value>' }
712
+ function getBuildEnv(envs, exportConditions) {
672
713
  if (!envs.includes('NODE_ENV')) {
673
714
  envs.push('NODE_ENV');
674
715
  }
@@ -679,10 +720,17 @@ function getBuildEnv(envs) {
679
720
  }
680
721
  return acc;
681
722
  }, {});
723
+ // For development and production convention, we override the NODE_ENV value
724
+ const exportConditionNames = new Set(Object.keys(exportConditions));
725
+ if (exportConditionNames.has('development')) {
726
+ envVars['process.env.NODE_ENV'] = JSON.stringify('development');
727
+ } else if (exportConditionNames.has('production')) {
728
+ envVars['process.env.NODE_ENV'] = JSON.stringify('production');
729
+ }
682
730
  return envVars;
683
731
  }
684
732
  /**
685
- * return {
733
+ * return {
686
734
  * <absolute source path>: <pkg>/<export>
687
735
  * }
688
736
  */ function getReversedAlias(entries) {
@@ -712,6 +760,7 @@ async function buildInputConfig(entry, options, buildContext, exportCondition, d
712
760
  externals.push(entryFilePath);
713
761
  }
714
762
  }
763
+ const envValues = getBuildEnv(options.env || [], exportCondition.export);
715
764
  const { useTypeScript } = buildContext;
716
765
  const { runtime, target: jscTarget, minify: shouldMinify } = options;
717
766
  const hasSpecifiedTsTarget = Boolean(tsCompilerOptions.target && tsConfigPath);
@@ -758,6 +807,13 @@ async function buildInputConfig(entry, options, buildContext, exportCondition, d
758
807
  })
759
808
  ];
760
809
  if (useTypeScript) {
810
+ const enableIncrementalWithoutBuildInfo = tsCompilerOptions.incremental && !tsCompilerOptions.tsBuildInfoFile;
811
+ const incrementalOptions = enableIncrementalWithoutBuildInfo ? {
812
+ incremental: false
813
+ } : undefined;
814
+ const compositeOptions = tsCompilerOptions.composite && enableIncrementalWithoutBuildInfo ? {
815
+ composite: false
816
+ } : undefined;
761
817
  const { options: overrideResolvedTsOptions } = await convertCompilerOptions(cwd, {
762
818
  declaration: true,
763
819
  noEmit: false,
@@ -772,9 +828,9 @@ async function buildInputConfig(entry, options, buildContext, exportCondition, d
772
828
  } : undefined,
773
829
  // error TS5074: Option '--incremental' can only be specified using tsconfig, emitting to single
774
830
  // file or when option '--tsBuildInfoFile' is specified.
775
- ...tsCompilerOptions.incremental && !tsCompilerOptions.tsBuildInfoFile ? {
776
- incremental: false
777
- } : undefined
831
+ ...incrementalOptions,
832
+ // error TS6379: Composite projects may not disable incremental compilation.
833
+ ...compositeOptions
778
834
  });
779
835
  const dtsPlugin = require('rollup-plugin-dts').default({
780
836
  tsconfig: tsConfigPath,
@@ -794,24 +850,25 @@ async function buildInputConfig(entry, options, buildContext, exportCondition, d
794
850
  preserveDirectives__default.default(),
795
851
  prependDirectives(),
796
852
  replace__default.default({
797
- values: getBuildEnv(options.env || []),
853
+ values: envValues,
798
854
  preventAssignment: true
799
855
  }),
800
856
  pluginNodeResolve.nodeResolve({
801
857
  preferBuiltins: runtime === 'node',
802
858
  extensions: nodeResolveExtensions
803
859
  }),
804
- commonjs__default.default({
805
- exclude: options.external || null
806
- }),
807
- json__default.default(),
808
860
  pluginWasm.wasm(),
809
861
  rollupPluginSwc3.swc({
810
862
  include: availableESExtensionsRegex,
811
863
  exclude: 'node_modules',
812
- tsconfig: tsConfigPath,
864
+ // Use `false` to disable retrieving tsconfig.json
865
+ tsconfig: tsConfigPath != null ? tsConfigPath : false,
813
866
  ...swcOptions
814
- })
867
+ }),
868
+ commonjs__default.default({
869
+ exclude: options.external || null
870
+ }),
871
+ json__default.default()
815
872
  ]).filter(isNotNull);
816
873
  return {
817
874
  input: entry,
@@ -959,48 +1016,48 @@ async function buildEntryConfig(bundleConfig, pluginContext, dts) {
959
1016
  }
960
1017
  return await Promise.all(configs);
961
1018
  }
1019
+ async function collectEntry(// export type, e.g. react-server, edge-light those special cases required suffix
1020
+ exportType, options) {
1021
+ const { cwd, pkg, entries, entryPath, exportCondRef, entryExport } = options;
1022
+ let exportCondForType = {
1023
+ ...exportCondRef
1024
+ };
1025
+ // Special cases of export type, only pass down the exportPaths for the type
1026
+ if (suffixedExportConventions.has(exportType)) {
1027
+ exportCondForType = {
1028
+ [exportType]: exportCondRef[exportType]
1029
+ };
1030
+ // Basic export type, pass down the exportPaths with erasing the special ones
1031
+ } else {
1032
+ for (const exportType of suffixedExportConventions){
1033
+ delete exportCondForType[exportType];
1034
+ }
1035
+ }
1036
+ let source = entryPath;
1037
+ if (source) {
1038
+ source = resolveSourceFile(cwd, source);
1039
+ } else {
1040
+ source = await getSourcePathFromExportPath(cwd, entryExport, exportType);
1041
+ }
1042
+ if (!source) {
1043
+ return;
1044
+ }
1045
+ const exportCondition = {
1046
+ source,
1047
+ name: entryExport,
1048
+ export: exportCondForType
1049
+ };
1050
+ const nameWithExportPath = pkg.name ? path__default.default.join(pkg.name, exportCondition.name) : exportCondition.name;
1051
+ const needsDelimiter = !nameWithExportPath.endsWith('.') && exportType;
1052
+ const entryImportPath = nameWithExportPath + (needsDelimiter ? '.' : '') + exportType;
1053
+ entries[entryImportPath] = exportCondition;
1054
+ }
962
1055
  /*
963
1056
  * build configs for each entry from package exports
964
1057
  *
965
1058
  * return { <pkg>/<export>: { input: InputOptions, output: OutputOptions[] }
966
1059
  */ async function collectEntries(pkg, entryPath, exportPaths, cwd) {
967
1060
  const entries = {};
968
- async function collectEntry(// export type, e.g. react-server, edge-light those special cases required suffix
969
- exportType, exportCondRef, // export name, e.g. ./<export-path> in exports field of package.json
970
- entryExport) {
971
- let exportCondForType = {
972
- ...exportCondRef
973
- };
974
- // Special cases of export type, only pass down the exportPaths for the type
975
- if (availableExportConventions.has(exportType)) {
976
- exportCondForType = {
977
- [exportType]: exportCondRef[exportType]
978
- };
979
- // Basic export type, pass down the exportPaths with erasing the special ones
980
- } else {
981
- for (const exportType of availableExportConventions){
982
- delete exportCondForType[exportType];
983
- }
984
- }
985
- let source = entryPath;
986
- if (source) {
987
- source = resolveSourceFile(cwd, source);
988
- } else {
989
- source = await getSourcePathFromExportPath(cwd, entryExport, exportType);
990
- }
991
- if (!source) {
992
- return undefined;
993
- }
994
- const exportCondition = {
995
- source,
996
- name: entryExport,
997
- export: exportCondForType
998
- };
999
- const nameWithExportPath = pkg.name ? path__default.default.join(pkg.name, exportCondition.name) : exportCondition.name;
1000
- const needsDelimiter = !nameWithExportPath.endsWith('.') && exportType;
1001
- const entryImportPath = nameWithExportPath + (needsDelimiter ? '.' : '') + exportType;
1002
- entries[entryImportPath] = exportCondition;
1003
- }
1004
1061
  const binaryExports = pkg.bin;
1005
1062
  if (binaryExports) {
1006
1063
  // binDistPaths: [ [ 'bin1', './dist/bin1.js'], [ 'bin2', './dist/bin2.js'] ]
@@ -1036,11 +1093,19 @@ async function buildEntryConfig(bundleConfig, pluginContext, dts) {
1036
1093
  }
1037
1094
  const collectEntriesPromises = Object.keys(exportPaths).map(async (entryExport)=>{
1038
1095
  const exportCond = exportPaths[entryExport];
1096
+ const collectEntryOptions = {
1097
+ cwd,
1098
+ pkg,
1099
+ entries,
1100
+ entryPath,
1101
+ exportCondRef: exportCond,
1102
+ entryExport
1103
+ };
1039
1104
  if (entryExport.startsWith('.')) {
1040
- await collectEntry('', exportCond, entryExport);
1041
- for (const exportType of availableExportConventions){
1042
- if (exportCond[exportType]) {
1043
- await collectEntry(exportType, exportCond, entryExport);
1105
+ await collectEntry('', collectEntryOptions);
1106
+ for (const exportCondType of suffixedExportConventions){
1107
+ if (exportCond[exportCondType]) {
1108
+ await collectEntry(exportCondType, collectEntryOptions);
1044
1109
  }
1045
1110
  }
1046
1111
  }
@@ -1204,6 +1269,10 @@ function getExportNameWithoutExportCondition(exportName) {
1204
1269
  }
1205
1270
  function logOutputState(sizeCollector) {
1206
1271
  const stats = sizeCollector.getSizeStats();
1272
+ if (stats.size === 0) {
1273
+ logger.warn('No build info can be logged');
1274
+ return;
1275
+ }
1207
1276
  const allFileNameLengths = Array.from(stats.values()).flat(1).map(([filename])=>filename.length);
1208
1277
  const maxFilenameLength = Math.max(...allFileNameLengths);
1209
1278
  const statsArray = [
@@ -1232,11 +1301,12 @@ function logOutputState(sizeCollector) {
1232
1301
  }).forEach((item, index)=>{
1233
1302
  const [filename, , size] = item;
1234
1303
  const normalizedExportName = normalizeExportName(exportName);
1235
- const prefix = index === 0 ? normalizedExportName + ' '.repeat(maxLengthOfExportName - normalizedExportName.length) : ' '.repeat(maxLengthOfExportName);
1236
- const sizePadding = ' '.repeat(maxFilenameLength - filename.length);
1237
- const prettiedSize = prettyBytes__default.default(size);
1304
+ const prefix = index === 0 ? normalizedExportName : ' '.repeat(normalizedExportName.length);
1305
+ const filenamePadding = ' '.repeat(Math.max(maxLengthOfExportName, 'Exports'.length) - normalizedExportName.length);
1238
1306
  const isType = isTypeFile(filename);
1239
- console.log(` ${prefix} ${pc[isType ? 'dim' : 'bold'](filename)}${sizePadding} ${prettiedSize}`);
1307
+ const sizePadding = ' '.repeat(Math.max(maxFilenameLength, 'File'.length) - filename.length);
1308
+ const prettiedSize = prettyBytes__default.default(size);
1309
+ console.log(prefix, filenamePadding, `${pc[isType ? 'dim' : 'bold'](filename)}`, sizePadding, prettiedSize);
1240
1310
  });
1241
1311
  });
1242
1312
  }
@@ -1305,7 +1375,7 @@ function hasMultiEntryExport(exportPaths) {
1305
1375
  const exportKeys = Object.keys(exportPaths).filter((key)=>key !== './package.json');
1306
1376
  return exportKeys.length > 0 && exportKeys.every((name)=>name.startsWith('.'));
1307
1377
  }
1308
- async function bundle(entryPath, { cwd: _cwd, ...options } = {}) {
1378
+ async function bundle(cliEntryPath, { cwd: _cwd, ...options } = {}) {
1309
1379
  const cwd = path.resolve(process.cwd(), _cwd || '');
1310
1380
  assignDefault(options, 'format', 'es');
1311
1381
  assignDefault(options, 'minify', false);
@@ -1313,12 +1383,13 @@ async function bundle(entryPath, { cwd: _cwd, ...options } = {}) {
1313
1383
  const pkg = await getPackageMeta(cwd);
1314
1384
  const resolvedWildcardExports = await resolveWildcardExports(pkg.exports, cwd);
1315
1385
  const packageType = getPackageType(pkg);
1316
- const exportPaths = getExportPaths(pkg, packageType, resolvedWildcardExports);
1386
+ const exportPaths = getExportPaths(pkg, resolvedWildcardExports);
1317
1387
  const isMultiEntries = hasMultiEntryExport(exportPaths) // exportPathsLength > 1
1318
1388
  ;
1319
1389
  const hasBin = Boolean(pkg.bin);
1320
- const tsConfig = await resolveTsConfig(cwd);
1321
- const hasTsConfig = Boolean(tsConfig == null ? void 0 : tsConfig.tsConfigPath);
1390
+ const isFromCli = Boolean(cliEntryPath);
1391
+ let tsConfig = await resolveTsConfig(cwd);
1392
+ let hasTsConfig = Boolean(tsConfig == null ? void 0 : tsConfig.tsConfigPath);
1322
1393
  const defaultTsOptions = {
1323
1394
  tsConfigPath: tsConfig == null ? void 0 : tsConfig.tsConfigPath,
1324
1395
  tsCompilerOptions: (tsConfig == null ? void 0 : tsConfig.tsCompilerOptions) || {}
@@ -1327,9 +1398,10 @@ async function bundle(entryPath, { cwd: _cwd, ...options } = {}) {
1327
1398
  if (!isMultiEntries) {
1328
1399
  // Use specified string file path if possible, then fallback to the default behavior entry picking logic
1329
1400
  // e.g. "exports": "./dist/index.js" -> use "./index.<ext>" as entry
1330
- entryPath = entryPath || await getSourcePathFromExportPath(cwd, '.', 'default') || '';
1401
+ cliEntryPath = cliEntryPath || await getSourcePathFromExportPath(cwd, '.', 'default') || '';
1331
1402
  }
1332
- if (entryPath) {
1403
+ // Handle CLI input
1404
+ if (cliEntryPath) {
1333
1405
  let mainEntryPath;
1334
1406
  let typesEntryPath;
1335
1407
  // with -o option
@@ -1346,21 +1418,22 @@ async function bundle(entryPath, { cwd: _cwd, ...options } = {}) {
1346
1418
  }, packageType);
1347
1419
  }
1348
1420
  }
1349
- const bundleOrWatch = (rollupConfig)=>{
1350
- const { input, exportName } = rollupConfig;
1351
- const exportPath = getExportPath(pkg, cwd, exportName);
1352
- // Log original entry file relative path
1353
- typeof input.input === 'string' ? path.relative(cwd, input.input) : exportPath;
1421
+ const bundleOrWatch = async (rollupConfig)=>{
1422
+ if (options.clean) {
1423
+ if (!isFromCli) {
1424
+ await removeOutputDir(rollupConfig.output);
1425
+ }
1426
+ }
1354
1427
  if (options.watch) {
1355
1428
  return Promise.resolve(runWatch(rollupConfig));
1356
1429
  }
1357
1430
  return runBundle(rollupConfig);
1358
1431
  };
1359
- const hasSpecifiedEntryFile = entryPath ? fs__default.default.existsSync(entryPath) && (await fsp__default.default.stat(entryPath)).isFile() : false;
1432
+ const hasSpecifiedEntryFile = cliEntryPath ? fs__default.default.existsSync(cliEntryPath) && (await fsp__default.default.stat(cliEntryPath)).isFile() : false;
1360
1433
  const hasNoEntry = !hasSpecifiedEntryFile && !isMultiEntries && !hasBin;
1361
1434
  if (hasNoEntry) {
1362
- if (entryPath) {
1363
- const err = new Error(`Entry file "${entryPath}" does not exist`);
1435
+ if (cliEntryPath) {
1436
+ const err = new Error(`Entry file "${cliEntryPath}" does not exist`);
1364
1437
  err.name = 'NOT_EXISTED';
1365
1438
  return Promise.reject(err);
1366
1439
  } else if (cwd) {
@@ -1372,7 +1445,15 @@ async function bundle(entryPath, { cwd: _cwd, ...options } = {}) {
1372
1445
  }
1373
1446
  }
1374
1447
  }
1375
- const entries = await collectEntries(pkg, entryPath, exportPaths, cwd);
1448
+ const entries = await collectEntries(pkg, cliEntryPath, exportPaths, cwd);
1449
+ const hasTypeScriptFiles = Object.values(entries).some((entry)=>isTypescriptFile(entry.source));
1450
+ if (hasTypeScriptFiles && !hasTsConfig) {
1451
+ const tsConfigPath = path.resolve(cwd, 'tsconfig.json');
1452
+ defaultTsOptions.tsConfigPath = tsConfigPath;
1453
+ await fsp__default.default.writeFile(tsConfigPath, JSON.stringify(DEFAULT_TS_CONFIG, null, 2), 'utf-8');
1454
+ logger.log(`Detected using TypeScript but tsconfig.json is missing, created a ${pc.blue('tsconfig.json')} for you.`);
1455
+ hasTsConfig = true;
1456
+ }
1376
1457
  const sizeCollector = createOutputState({
1377
1458
  entries
1378
1459
  });
@@ -1402,7 +1483,7 @@ async function bundle(entryPath, { cwd: _cwd, ...options } = {}) {
1402
1483
  }
1403
1484
  return result;
1404
1485
  }
1405
- function runWatch({ input, output }, metadata) {
1486
+ function runWatch({ input, output }) {
1406
1487
  const watchOptions = [
1407
1488
  {
1408
1489
  ...input,
@@ -1436,6 +1517,12 @@ function runWatch({ input, output }, metadata) {
1436
1517
  });
1437
1518
  return watcher;
1438
1519
  }
1520
+ async function removeOutputDir(output) {
1521
+ const dirs = new Set(output.map(({ dir })=>dir));
1522
+ for (const dir of dirs){
1523
+ if (dir) await removeDir(dir);
1524
+ }
1525
+ }
1439
1526
  function runBundle({ input, output }) {
1440
1527
  return rollup.rollup(input).then((bundle)=>{
1441
1528
  const writeJobs = output.map((options)=>bundle.write(options));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bunchee",
3
- "version": "4.3.4",
3
+ "version": "4.4.1",
4
4
  "description": "zero config bundler for js/ts/jsx libraries",
5
5
  "bin": "./dist/bin/cli.js",
6
6
  "main": "./dist/index.js",
@@ -57,8 +57,9 @@
57
57
  "@swc/core": "^1.3.102",
58
58
  "@swc/helpers": "^0.5.3",
59
59
  "arg": "^5.0.2",
60
+ "clean-css": "^5.3.3",
60
61
  "pretty-bytes": "^5.6.0",
61
- "publint": "~0.2.7",
62
+ "rimraf": "^5.0.5",
62
63
  "rollup": "^4.9.4",
63
64
  "rollup-plugin-dts": "^6.1.0",
64
65
  "rollup-plugin-swc3": "^0.11.0",
@@ -80,6 +81,7 @@
80
81
  "@huozhi/testing-package": "1.0.0",
81
82
  "@swc/jest": "^0.2.29",
82
83
  "@swc/types": "^0.1.5",
84
+ "@types/clean-css": "^4.2.11",
83
85
  "@types/jest": "29.0.0",
84
86
  "@types/node": "^20.4.1",
85
87
  "bunchee": "link:./",
@@ -106,7 +108,11 @@
106
108
  "^.+\\.(t|j)sx?$": [
107
109
  "@swc/jest"
108
110
  ]
109
- }
111
+ },
112
+ "testPathIgnorePatterns": [
113
+ "/node_modules/",
114
+ "<rootDir>/test/integration/.*/*src"
115
+ ]
110
116
  },
111
117
  "packageManager": "pnpm@8.8.0"
112
118
  }