bunchee 4.3.3 → 4.4.0

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/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
  }
@@ -121,6 +85,59 @@ picocolors.exports.createColors = createColors;
121
85
  var picocolorsExports = picocolors.exports;
122
86
  var pc = /*@__PURE__*/ getDefaultExportFromCjs(picocolorsExports);
123
87
 
88
+ const availableExtensions = new Set([
89
+ 'js',
90
+ 'cjs',
91
+ 'mjs',
92
+ 'jsx',
93
+ 'ts',
94
+ 'tsx',
95
+ 'cts',
96
+ 'mts'
97
+ ]);
98
+ const nodeResolveExtensions = [
99
+ '.mjs',
100
+ '.cjs',
101
+ '.js',
102
+ '.json',
103
+ '.node',
104
+ '.jsx'
105
+ ];
106
+ const suffixedExportConventions = new Set([
107
+ 'react-server',
108
+ 'react-native',
109
+ 'edge-light',
110
+ 'development',
111
+ 'production'
112
+ ]);
113
+ const availableESExtensionsRegex = /\.(m|c)?[jt]sx?$/;
114
+ const SRC = 'src';
115
+ const dtsExtensionsMap = {
116
+ js: 'd.ts',
117
+ cjs: 'd.cts',
118
+ mjs: 'd.mts'
119
+ };
120
+ const disabledWarnings = new Set([
121
+ 'MIXED_EXPORTS',
122
+ 'PREFER_NAMED_EXPORTS',
123
+ 'UNRESOLVED_IMPORT',
124
+ 'THIS_IS_UNDEFINED',
125
+ 'INVALID_ANNOTATION',
126
+ 'UNUSED_EXTERNAL_IMPORT'
127
+ ]);
128
+ const tsExtensions = new Set([
129
+ 'ts',
130
+ 'tsx',
131
+ 'cts',
132
+ 'mts'
133
+ ]);
134
+ const DEFAULT_TS_CONFIG = {
135
+ compilerOptions: {
136
+ module: 'ESNext',
137
+ moduleResolution: 'bundler'
138
+ }
139
+ };
140
+
124
141
  const defaultColorFn = (text)=>text;
125
142
  function color(prefixColor) {
126
143
  return pc.isColorSupported ? pc[prefixColor] : defaultColorFn;
@@ -154,15 +171,24 @@ async function getPackageMeta(cwd) {
154
171
  } catch (_) {}
155
172
  return targetPackageJson;
156
173
  }
174
+ function isTypescriptFile(filename) {
175
+ const ext = path__default.default.extname(filename).slice(1);
176
+ return tsExtensions.has(ext);
177
+ }
157
178
  function fileExists(filePath) {
158
179
  return fs__default.default.existsSync(filePath);
159
180
  }
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);
181
+ async function removeDir(dirPath) {
182
+ try {
183
+ const dirStat = await fsp__default.default.stat(dirPath);
184
+ if (dirStat.isDirectory()) {
185
+ await rimraf.rimraf(dirPath);
186
+ }
187
+ } catch (err) {
188
+ if (err.code !== 'ENOENT') {
189
+ throw err;
190
+ }
191
+ }
166
192
  }
167
193
  const isNotNull = (n)=>Boolean(n);
168
194
  function resolveSourceFile(cwd, filename) {
@@ -191,7 +217,7 @@ async function getSourcePathFromExportPath(cwd, exportPath, exportType) {
191
217
  if (exportPath === '.') exportPath = './index';
192
218
  // Find convention-based source file for specific export types
193
219
  // $binary represents `pkg.bin`
194
- if (availableExportConventions.has(exportType) && exportType !== '$binary') {
220
+ if (suffixedExportConventions.has(exportType) && exportType !== '$binary') {
195
221
  const filename = await findSourceEntryFile(cwd, exportPath, exportType, ext);
196
222
  if (filename) return filename;
197
223
  }
@@ -200,13 +226,15 @@ async function getSourcePathFromExportPath(cwd, exportPath, exportType) {
200
226
  }
201
227
  return;
202
228
  }
229
+ // TODO: add unit test
203
230
  // Unlike path.basename, forcedly removing extension
204
231
  function filePathWithoutExtension(file) {
205
232
  return file ? file.replace(new RegExp(`${path__default.default.extname(file)}$`), '') : undefined;
206
233
  }
207
234
  const nonNullable = (n)=>Boolean(n);
208
235
  const hasAvailableExtension = (filename)=>availableExtensions.has(path__default.default.extname(filename).slice(1));
209
- const hasCjsExtension = (filename)=>path__default.default.extname(filename) === '.cjs';
236
+ // TODO: add unit test
237
+ const baseNameWithoutExtension = (filename)=>path__default.default.basename(filename, path__default.default.extname(filename));
210
238
 
211
239
  let hasLoggedTsWarning = false;
212
240
  function resolveTypescript(cwd) {
@@ -246,14 +274,6 @@ async function convertCompilerOptions(cwd, json) {
246
274
  return ts.convertCompilerOptionsFromJson(json, './');
247
275
  }
248
276
 
249
- function minifyCSS(content) {
250
- return content.replace(/\/\*[\s\S]*?\*\/|([^:]|^)\/\/.*$|(?:^|\s)(\s+)|\s*([\{\};,:])\s*|\s+(!)\s+/g, (match, p1, p2, p3, p4)=>{
251
- if (p1) return p1 === ' ' ? '' : p1;
252
- if (p2) return ' ';
253
- if (p3) return p3;
254
- if (p4) return '!';
255
- });
256
- }
257
277
  const helpers = {
258
278
  cssImport: {
259
279
  // have to assign r.type = 'text/css' to make it work in Safari
@@ -281,6 +301,10 @@ export default sheet`;
281
301
  }
282
302
  }
283
303
  };
304
+ const cleanCssInstance = new CleanCSS__default.default({});
305
+ function minify(code) {
306
+ return cleanCssInstance.minify(code).styles;
307
+ }
284
308
  function inlineCss(options) {
285
309
  const cssIds = new Set();
286
310
  var _options_exclude;
@@ -293,7 +317,7 @@ function inlineCss(options) {
293
317
  transform (code, id) {
294
318
  if (!filter(id)) return;
295
319
  if (options.skip) return '';
296
- const cssCode = minifyCSS(code);
320
+ const cssCode = minify(code);
297
321
  cssIds.add(id);
298
322
  return {
299
323
  code: helpers.cssImport.create(cssCode),
@@ -302,7 +326,7 @@ function inlineCss(options) {
302
326
  }
303
327
  };
304
328
  },
305
- renderChunk (code, options) {
329
+ renderChunk (code) {
306
330
  const dependenciesIds = this.getModuleIds();
307
331
  let foundCss = false;
308
332
  for (const depId of dependenciesIds){
@@ -391,9 +415,6 @@ function prependDirectives() {
391
415
  function getTypings(pkg) {
392
416
  return pkg.types || pkg.typings;
393
417
  }
394
- function getDistPath(distPath, cwd) {
395
- return path.resolve(cwd, distPath);
396
- }
397
418
  // Reached the end of the export path
398
419
  function isExportLike(field) {
399
420
  if (typeof field === 'string') return true;
@@ -428,6 +449,18 @@ function joinRelativePath(...segments) {
428
449
  }
429
450
  return result;
430
451
  }
452
+ const getFirstExportPath = (fullExportCondition)=>{
453
+ // Handle all export cond { <require|import|default>: ... }
454
+ if (typeof fullExportCondition === 'object') {
455
+ for (const key of Object.keys(fullExportCondition)){
456
+ if (key.startsWith('.') || key === 'types') {
457
+ continue;
458
+ }
459
+ return fullExportCondition[key];
460
+ }
461
+ }
462
+ return fullExportCondition;
463
+ };
431
464
  function findExport(exportPath, exportCondition, paths, packageType, currentPath) {
432
465
  // Skip `types` field, it cannot be the entry point
433
466
  if (exportPath === 'types') return;
@@ -439,11 +472,12 @@ function findExport(exportPath, exportCondition, paths, packageType, currentPath
439
472
  ...fullExportCondition
440
473
  };
441
474
  } else {
475
+ const exportJsBundlePath = getFirstExportPath(fullExportCondition);
442
476
  // exportPath is exportType, import, require, ...
443
477
  // merge to currentPath
444
478
  paths[currentPath] = {
445
479
  ...paths[currentPath],
446
- [exportPath]: fullExportCondition.default
480
+ [exportPath]: exportJsBundlePath
447
481
  };
448
482
  }
449
483
  return;
@@ -545,10 +579,10 @@ function findExport(exportPath, exportCondition, paths, packageType, currentPath
545
579
  *
546
580
  *
547
581
  * pkg.main and pkg.module will be added to ['.'] if exists
548
- */ function getExportPaths(pkg, pkgType, resolvedWildcardExports) {
582
+ */ function getExportPaths(pkg, resolvedWildcardExports) {
549
583
  var _pathsMap_;
550
584
  let pathsMap = {};
551
- const packageType = pkgType != null ? pkgType : getPackageType(pkg);
585
+ const packageType = getPackageType(pkg);
552
586
  const isEsmPackage = isESModulePackage(packageType);
553
587
  const exportsConditions = resolvedWildcardExports != null ? resolvedWildcardExports : pkg.exports;
554
588
  if (exportsConditions) {
@@ -558,9 +592,6 @@ function findExport(exportPath, exportCondition, paths, packageType, currentPath
558
592
  ...paths
559
593
  };
560
594
  }
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
595
  // main export '.' from main/module/typings
565
596
  const defaultMainExport = constructFullExportCondition({
566
597
  [isEsmPackage ? 'import' : 'require']: pkg.main,
@@ -585,31 +616,6 @@ function findExport(exportPath, exportCondition, paths, packageType, currentPath
585
616
  }
586
617
  return pathsMap;
587
618
  }
588
- const getExportTypeDist = (parsedExportCondition, cwd)=>{
589
- const existed = new Set();
590
- const exportTypes = Object.keys(parsedExportCondition.export);
591
- for (const key of exportTypes){
592
- if (key === 'module') {
593
- continue;
594
- }
595
- const filePath = parsedExportCondition.export[key];
596
- if (key === 'types') {
597
- const typeFile = getDistPath(filePath, cwd);
598
- if (existed.has(typeFile)) {
599
- continue;
600
- }
601
- existed.add(typeFile);
602
- continue;
603
- }
604
- const ext = path.extname(filePath).slice(1);
605
- const typeFile = getDistPath(`${filePathWithoutExtension(filePath) || ''}.${dtsExtensionsMap[ext]}`, cwd);
606
- if (existed.has(typeFile)) {
607
- continue;
608
- }
609
- existed.add(typeFile);
610
- }
611
- return Array.from(existed);
612
- };
613
619
  function getPackageType(pkg) {
614
620
  return pkg.type || 'commonjs';
615
621
  }
@@ -638,55 +644,43 @@ function isEsmExportName(name, ext) {
638
644
  'module'
639
645
  ].includes(name) || ext === 'mjs';
640
646
  }
641
- function isCjsExportName(pkg, name, ext) {
647
+ function isCjsExportName(pkg, exportCondition, ext) {
642
648
  const isESModule = isESModulePackage(pkg.type);
643
649
  return !isESModule && [
644
650
  'require',
645
- 'main',
646
- 'node'
647
- ].includes(name) && ext !== 'mjs' || ext === 'cjs';
651
+ 'main'
652
+ ].includes(exportCondition) && ext !== 'mjs' || ext === 'cjs';
648
653
  }
649
- function getExportConditionDist(pkg, parsedExportCondition, cwd) {
654
+ function getExportsDistFilesOfCondition(pkg, parsedExportCondition, cwd) {
650
655
  const dist = [];
651
- const existed = new Set();
652
- const exportTypes = Object.keys(parsedExportCondition.export);
653
- for (const exportType of exportTypes){
654
- if (exportType === 'types') {
656
+ const exportConditionNames = Object.keys(parsedExportCondition.export);
657
+ const uniqueFiles = new Set();
658
+ for (const exportCondition of exportConditionNames){
659
+ if (exportCondition === 'types') {
655
660
  continue;
656
661
  }
657
- const filePath = parsedExportCondition.export[exportType];
662
+ const filePath = parsedExportCondition.export[exportCondition];
658
663
  const ext = path.extname(filePath).slice(1);
659
- const relativePath = parsedExportCondition.export[exportType];
660
- const distFile = getDistPath(relativePath, cwd);
661
- let format = 'esm';
662
- if (isCjsExportName(pkg, exportType, ext)) {
663
- format = 'cjs';
664
- }
665
- // Deduplicate the same path jobs
666
- // TODO: detect conflicts paths but with different format
667
- if (existed.has(distFile)) {
664
+ const relativePath = parsedExportCondition.export[exportCondition];
665
+ const distFile = path.resolve(cwd, relativePath);
666
+ const format = isCjsExportName(pkg, exportCondition, ext) ? 'cjs' : 'esm';
667
+ if (uniqueFiles.has(distFile)) {
668
668
  continue;
669
669
  }
670
- existed.add(distFile);
670
+ uniqueFiles.add(distFile);
671
671
  dist.push({
672
672
  format,
673
673
  file: distFile
674
674
  });
675
675
  }
676
- if (dist.length === 0 && !pkg.bin) {
677
- const defaultFormat = isESModulePackage(pkg.type) ? 'esm' : 'cjs';
678
- dist.push({
679
- format: defaultFormat,
680
- file: getDistPath('dist/index.js', cwd)
681
- });
682
- }
683
676
  return dist;
684
677
  }
685
- function getTypeFilePath(entryFilePath, exportCondition, cwd) {
686
- const name = filePathWithoutExtension(entryFilePath);
687
- const firstDistPath = exportCondition ? Object.values(exportCondition.export)[0] : undefined;
688
- const exportName = (exportCondition == null ? void 0 : exportCondition.name) || 'index';
689
- return entryFilePath ? name + '.d.ts' : path.resolve(firstDistPath ? path.dirname(firstDistPath) : path.join(cwd, 'dist'), (exportName === '.' ? 'index' : exportName) + '.d.ts');
678
+ function getExportFileTypePath(absoluteJsBundlePath) {
679
+ const dirName = path.dirname(absoluteJsBundlePath);
680
+ const baseName = baseNameWithoutExtension(absoluteJsBundlePath);
681
+ const ext = path.extname(absoluteJsBundlePath).slice(1);
682
+ const typeExtension = dtsExtensionsMap[ext];
683
+ return path.join(dirName, baseName + '.' + typeExtension);
690
684
  }
691
685
  function getExportTypeFromFile(filename, pkgType) {
692
686
  const isESModule = isESModulePackage(pkgType);
@@ -705,7 +699,8 @@ const swcMinifyOptions = {
705
699
  toplevel: true
706
700
  }
707
701
  };
708
- function getBuildEnv(envs) {
702
+ // return { 'process.env.<key>': '<value>' }
703
+ function getBuildEnv(envs, exportConditions) {
709
704
  if (!envs.includes('NODE_ENV')) {
710
705
  envs.push('NODE_ENV');
711
706
  }
@@ -716,10 +711,19 @@ function getBuildEnv(envs) {
716
711
  }
717
712
  return acc;
718
713
  }, {});
714
+ // For development and production convention, we override the NODE_ENV value
715
+ const exportConditionNames = new Set(Object.keys(exportConditions));
716
+ if (exportConditionNames.has('development')) {
717
+ envVars['process.env.NODE_ENV'] = JSON.stringify('development');
718
+ } else if (exportConditionNames.has('production')) {
719
+ envVars['process.env.NODE_ENV'] = JSON.stringify('production');
720
+ }
719
721
  return envVars;
720
722
  }
721
723
  /**
722
- * return { '<absolute source path>': '<pkg>/<export>' }
724
+ * return {
725
+ * <absolute source path>: <pkg>/<export>
726
+ * }
723
727
  */ function getReversedAlias(entries) {
724
728
  const alias = {};
725
729
  for (const [entryImportPath, exportCondition] of Object.entries(entries)){
@@ -731,7 +735,7 @@ function getBuildEnv(envs) {
731
735
  }
732
736
  return alias;
733
737
  }
734
- async function buildInputConfig(entry, options, buildContext, dts) {
738
+ async function buildInputConfig(entry, options, buildContext, exportCondition, dts) {
735
739
  const { entries, pkg, cwd, tsOptions: { tsConfigPath, tsCompilerOptions }, pluginContext } = buildContext;
736
740
  const hasNoExternal = options.external === null;
737
741
  var _options_external;
@@ -747,11 +751,13 @@ async function buildInputConfig(entry, options, buildContext, dts) {
747
751
  externals.push(entryFilePath);
748
752
  }
749
753
  }
750
- const { useTypescript, runtime, target: jscTarget, minify: shouldMinify } = options;
754
+ const envValues = getBuildEnv(options.env || [], exportCondition.export);
755
+ const { useTypeScript } = buildContext;
756
+ const { runtime, target: jscTarget, minify: shouldMinify } = options;
751
757
  const hasSpecifiedTsTarget = Boolean(tsCompilerOptions.target && tsConfigPath);
752
758
  const swcParserConfig = {
753
- syntax: useTypescript ? 'typescript' : 'ecmascript',
754
- [useTypescript ? 'tsx' : 'jsx']: true,
759
+ syntax: useTypeScript ? 'typescript' : 'ecmascript',
760
+ [useTypeScript ? 'tsx' : 'jsx']: true,
755
761
  exportDefaultFrom: true
756
762
  };
757
763
  const swcOptions = {
@@ -791,7 +797,7 @@ async function buildInputConfig(entry, options, buildContext, dts) {
791
797
  skip: true
792
798
  })
793
799
  ];
794
- if (useTypescript) {
800
+ if (useTypeScript) {
795
801
  const { options: overrideResolvedTsOptions } = await convertCompilerOptions(cwd, {
796
802
  declaration: true,
797
803
  noEmit: false,
@@ -801,16 +807,14 @@ async function buildInputConfig(entry, options, buildContext, dts) {
801
807
  declarationMap: false,
802
808
  skipLibCheck: true,
803
809
  target: 'ESNext',
804
- // Some react types required this to be false by default.
805
- // Some type package like express might need this as it has other dependencies.
806
- // Let users able to toggle this in tsconfig.
807
- preserveSymlinks: 'preserveSymlinks' in tsCompilerOptions ? tsCompilerOptions.preserveSymlinks : false,
808
810
  ...!tsCompilerOptions.jsx ? {
809
811
  jsx: 'react-jsx'
810
812
  } : undefined,
811
813
  // error TS5074: Option '--incremental' can only be specified using tsconfig, emitting to single
812
814
  // file or when option '--tsBuildInfoFile' is specified.
813
- incremental: false
815
+ ...tsCompilerOptions.incremental && !tsCompilerOptions.tsBuildInfoFile ? {
816
+ incremental: false
817
+ } : undefined
814
818
  });
815
819
  const dtsPlugin = require('rollup-plugin-dts').default({
816
820
  tsconfig: tsConfigPath,
@@ -830,7 +834,7 @@ async function buildInputConfig(entry, options, buildContext, dts) {
830
834
  preserveDirectives__default.default(),
831
835
  prependDirectives(),
832
836
  replace__default.default({
833
- values: getBuildEnv(options.env || []),
837
+ values: envValues,
834
838
  preventAssignment: true
835
839
  }),
836
840
  pluginNodeResolve.nodeResolve({
@@ -960,22 +964,17 @@ function buildOutputConfigs(options, exportCondition, buildContext, dts) {
960
964
  const { entries, pkg, exportPaths, cwd, tsOptions: { tsCompilerOptions }, pluginContext } = buildContext;
961
965
  // Add esm mark and interop helper if esm export is detected
962
966
  const useEsModuleMark = hasEsmExport(exportPaths, tsCompilerOptions);
963
- const typings = getTypings(pkg);
964
- const file = options.file && path.resolve(cwd, options.file);
965
- const dtsDir = typings ? path.dirname(path.resolve(cwd, typings)) : path.resolve(cwd, 'dist');
966
- const name = filePathWithoutExtension(file);
967
- // TODO: simplify dts file name detection
968
- const dtsFile = file ? file : exportCondition.export['types'] ? path.resolve(cwd, exportCondition.export['types']) : path.resolve(dtsDir, (exportCondition.name === '.' ? 'index' : exportCondition.name) + '.d.ts');
969
- const dtsPathConfig = {
970
- dir: dtsFile ? path.dirname(dtsFile) : dtsDir
971
- };
972
- const outputFile = dtsFile || file;
967
+ const absoluteOutputFile = path.resolve(cwd, options.file);
968
+ const name = filePathWithoutExtension(absoluteOutputFile);
969
+ var _exportCondition_export_types;
970
+ const dtsFile = path.resolve(cwd, dts ? options.file : (_exportCondition_export_types = exportCondition.export.types) != null ? _exportCondition_export_types : getExportFileTypePath(options.file));
971
+ const typesDir = path.dirname(dtsFile);
972
+ const jsDir = path.dirname(absoluteOutputFile);
973
+ const outputFile = dts ? dtsFile : absoluteOutputFile;
973
974
  const entryFiles = new Set(Object.values(entries).map((entry)=>entry.source));
974
975
  return {
975
976
  name: pkg.name || name,
976
- ...dts ? dtsPathConfig : {
977
- dir: path.dirname(outputFile)
978
- },
977
+ dir: dts ? typesDir : jsDir,
979
978
  format,
980
979
  exports: 'named',
981
980
  esModule: useEsModuleMark || 'if-default-prop',
@@ -1000,48 +999,48 @@ async function buildEntryConfig(bundleConfig, pluginContext, dts) {
1000
999
  }
1001
1000
  return await Promise.all(configs);
1002
1001
  }
1002
+ async function collectEntry(// export type, e.g. react-server, edge-light those special cases required suffix
1003
+ exportType, options) {
1004
+ const { cwd, pkg, entries, entryPath, exportCondRef, entryExport } = options;
1005
+ let exportCondForType = {
1006
+ ...exportCondRef
1007
+ };
1008
+ // Special cases of export type, only pass down the exportPaths for the type
1009
+ if (suffixedExportConventions.has(exportType)) {
1010
+ exportCondForType = {
1011
+ [exportType]: exportCondRef[exportType]
1012
+ };
1013
+ // Basic export type, pass down the exportPaths with erasing the special ones
1014
+ } else {
1015
+ for (const exportType of suffixedExportConventions){
1016
+ delete exportCondForType[exportType];
1017
+ }
1018
+ }
1019
+ let source = entryPath;
1020
+ if (source) {
1021
+ source = resolveSourceFile(cwd, source);
1022
+ } else {
1023
+ source = await getSourcePathFromExportPath(cwd, entryExport, exportType);
1024
+ }
1025
+ if (!source) {
1026
+ return;
1027
+ }
1028
+ const exportCondition = {
1029
+ source,
1030
+ name: entryExport,
1031
+ export: exportCondForType
1032
+ };
1033
+ const nameWithExportPath = pkg.name ? path__default.default.join(pkg.name, exportCondition.name) : exportCondition.name;
1034
+ const needsDelimiter = !nameWithExportPath.endsWith('.') && exportType;
1035
+ const entryImportPath = nameWithExportPath + (needsDelimiter ? '.' : '') + exportType;
1036
+ entries[entryImportPath] = exportCondition;
1037
+ }
1003
1038
  /*
1004
1039
  * build configs for each entry from package exports
1005
1040
  *
1006
1041
  * return { <pkg>/<export>: { input: InputOptions, output: OutputOptions[] }
1007
1042
  */ async function collectEntries(pkg, entryPath, exportPaths, cwd) {
1008
1043
  const entries = {};
1009
- async function collectEntry(// export type, e.g. react-server, edge-light those special cases required suffix
1010
- exportType, exportCondRef, // export name, e.g. ./<export-path> in exports field of package.json
1011
- entryExport) {
1012
- let exportCondForType = {
1013
- ...exportCondRef
1014
- };
1015
- // Special cases of export type, only pass down the exportPaths for the type
1016
- if (availableExportConventions.has(exportType)) {
1017
- exportCondForType = {
1018
- [entryExport]: exportCondRef[exportType]
1019
- };
1020
- // Basic export type, pass down the exportPaths with erasing the special ones
1021
- } else {
1022
- for (const exportType of availableExportConventions){
1023
- delete exportCondForType[exportType];
1024
- }
1025
- }
1026
- let source = entryPath;
1027
- if (source) {
1028
- source = resolveSourceFile(cwd, source);
1029
- } else {
1030
- source = await getSourcePathFromExportPath(cwd, entryExport, exportType);
1031
- }
1032
- if (!source) {
1033
- return undefined;
1034
- }
1035
- const exportCondition = {
1036
- source,
1037
- name: entryExport,
1038
- export: exportCondForType
1039
- };
1040
- const nameWithExportPath = pkg.name ? path__default.default.join(pkg.name, exportCondition.name) : exportCondition.name;
1041
- const needsDelimiter = !nameWithExportPath.endsWith('.') && exportType;
1042
- const entryImportPath = nameWithExportPath + (needsDelimiter ? '.' : '') + exportType;
1043
- entries[entryImportPath] = exportCondition;
1044
- }
1045
1044
  const binaryExports = pkg.bin;
1046
1045
  if (binaryExports) {
1047
1046
  // binDistPaths: [ [ 'bin1', './dist/bin1.js'], [ 'bin2', './dist/bin2.js'] ]
@@ -1077,11 +1076,19 @@ async function buildEntryConfig(bundleConfig, pluginContext, dts) {
1077
1076
  }
1078
1077
  const collectEntriesPromises = Object.keys(exportPaths).map(async (entryExport)=>{
1079
1078
  const exportCond = exportPaths[entryExport];
1079
+ const collectEntryOptions = {
1080
+ cwd,
1081
+ pkg,
1082
+ entries,
1083
+ entryPath,
1084
+ exportCondRef: exportCond,
1085
+ entryExport
1086
+ };
1080
1087
  if (entryExport.startsWith('.')) {
1081
- await collectEntry('', exportCond, entryExport);
1082
- for (const exportType of availableExportConventions){
1083
- if (exportCond[exportType]) {
1084
- await collectEntry(exportType, exportCond, entryExport);
1088
+ await collectEntry('', collectEntryOptions);
1089
+ for (const exportCondType of suffixedExportConventions){
1090
+ if (exportCond[exportCondType]) {
1091
+ await collectEntry(exportCondType, collectEntryOptions);
1085
1092
  }
1086
1093
  }
1087
1094
  }
@@ -1098,42 +1105,61 @@ async function buildConfig(bundleConfig, exportCondition, pluginContext, dts) {
1098
1105
  useTypescript
1099
1106
  };
1100
1107
  const entry = exportCondition.source;
1101
- const inputOptions = await buildInputConfig(entry, options, pluginContext, dts);
1102
- const outputExports = getExportConditionDist(pkg, exportCondition, cwd);
1103
- let outputConfigs = [];
1104
- // Generate dts job - single config
1105
- if (dts) {
1106
- const typeOutputExports = getExportTypeDist(exportCondition, cwd);
1107
- outputConfigs = typeOutputExports.map((typeFile)=>buildOutputConfigs({
1108
- ...bundleConfig,
1109
- format: 'es',
1110
- useTypescript,
1111
- file: typeFile
1112
- }, exportCondition, pluginContext, dts));
1108
+ const inputOptions = await buildInputConfig(entry, options, pluginContext, exportCondition, dts);
1109
+ const outputExports = getExportsDistFilesOfCondition(pkg, exportCondition, cwd);
1110
+ // If there's nothing found, give a default output
1111
+ if (outputExports.length === 0 && !pkg.bin) {
1112
+ const defaultFormat = isESModulePackage(pkg.type) ? 'esm' : 'cjs';
1113
+ outputExports.push({
1114
+ format: defaultFormat,
1115
+ file: path.join(cwd, 'dist/index.js')
1116
+ });
1117
+ }
1118
+ let bundleOptions = [];
1119
+ // multi outputs with specified format
1120
+ // CLI output option is always prioritized
1121
+ if (file) {
1122
+ var _outputExports_;
1123
+ const fallbackFormat = (_outputExports_ = outputExports[0]) == null ? void 0 : _outputExports_.format;
1124
+ bundleOptions = [
1125
+ {
1126
+ resolvedFile: path.resolve(cwd, file),
1127
+ format: bundleConfig.format || fallbackFormat
1128
+ }
1129
+ ];
1113
1130
  } else {
1114
- // multi outputs with specified format
1115
- outputConfigs = outputExports.map((exportDist)=>{
1116
- return buildOutputConfigs({
1117
- ...bundleConfig,
1118
- file: exportDist.file,
1119
- format: exportDist.format,
1120
- useTypescript
1121
- }, exportCondition, pluginContext, dts);
1131
+ bundleOptions = outputExports.map((exportDist)=>{
1132
+ return {
1133
+ resolvedFile: path.resolve(cwd, exportDist.file),
1134
+ format: exportDist.format
1135
+ };
1136
+ });
1137
+ }
1138
+ if (dts) {
1139
+ // types could have duplicates, dedupe them
1140
+ // e.g. { types, import, .. } use the same `types` condition with all conditions
1141
+ const uniqTypes = new Set();
1142
+ bundleOptions.forEach((bundleOption)=>{
1143
+ if (exportCondition.export.types) {
1144
+ uniqTypes.add(path.resolve(cwd, exportCondition.export.types));
1145
+ }
1146
+ const typeForExtension = getExportFileTypePath(bundleOption.resolvedFile);
1147
+ uniqTypes.add(typeForExtension);
1148
+ });
1149
+ bundleOptions = Array.from(uniqTypes).map((typeFile)=>{
1150
+ return {
1151
+ resolvedFile: typeFile,
1152
+ format: 'es'
1153
+ };
1122
1154
  });
1123
- // CLI output option is always prioritized
1124
- if (file) {
1125
- var _outputExports_;
1126
- const fallbackFormat = (_outputExports_ = outputExports[0]) == null ? void 0 : _outputExports_.format;
1127
- outputConfigs = [
1128
- buildOutputConfigs({
1129
- ...bundleConfig,
1130
- file,
1131
- format: bundleConfig.format || fallbackFormat,
1132
- useTypescript
1133
- }, exportCondition, pluginContext, dts)
1134
- ];
1135
- }
1136
1155
  }
1156
+ const outputConfigs = bundleOptions.map((bundleOption)=>{
1157
+ return buildOutputConfigs({
1158
+ ...bundleConfig,
1159
+ file: bundleOption.resolvedFile,
1160
+ format: bundleOption.format
1161
+ }, exportCondition, pluginContext, dts);
1162
+ });
1137
1163
  return {
1138
1164
  input: inputOptions,
1139
1165
  output: outputConfigs,
@@ -1226,6 +1252,10 @@ function getExportNameWithoutExportCondition(exportName) {
1226
1252
  }
1227
1253
  function logOutputState(sizeCollector) {
1228
1254
  const stats = sizeCollector.getSizeStats();
1255
+ if (stats.size === 0) {
1256
+ logger.warn('No build info can be logged');
1257
+ return;
1258
+ }
1229
1259
  const allFileNameLengths = Array.from(stats.values()).flat(1).map(([filename])=>filename.length);
1230
1260
  const maxFilenameLength = Math.max(...allFileNameLengths);
1231
1261
  const statsArray = [
@@ -1335,14 +1365,12 @@ async function bundle(entryPath, { cwd: _cwd, ...options } = {}) {
1335
1365
  const pkg = await getPackageMeta(cwd);
1336
1366
  const resolvedWildcardExports = await resolveWildcardExports(pkg.exports, cwd);
1337
1367
  const packageType = getPackageType(pkg);
1338
- const exportPaths = getExportPaths(pkg, packageType, resolvedWildcardExports);
1339
- const exportKeys = Object.keys(exportPaths).filter((key)=>key !== './package.json');
1340
- // const exportPathsLength = Object.keys(exportPaths).length
1368
+ const exportPaths = getExportPaths(pkg, resolvedWildcardExports);
1341
1369
  const isMultiEntries = hasMultiEntryExport(exportPaths) // exportPathsLength > 1
1342
1370
  ;
1343
1371
  const hasBin = Boolean(pkg.bin);
1344
- const tsConfig = await resolveTsConfig(cwd);
1345
- const hasTsConfig = Boolean(tsConfig == null ? void 0 : tsConfig.tsConfigPath);
1372
+ let tsConfig = await resolveTsConfig(cwd);
1373
+ let hasTsConfig = Boolean(tsConfig == null ? void 0 : tsConfig.tsConfigPath);
1346
1374
  const defaultTsOptions = {
1347
1375
  tsConfigPath: tsConfig == null ? void 0 : tsConfig.tsConfigPath,
1348
1376
  tsCompilerOptions: (tsConfig == null ? void 0 : tsConfig.tsCompilerOptions) || {}
@@ -1353,18 +1381,17 @@ async function bundle(entryPath, { cwd: _cwd, ...options } = {}) {
1353
1381
  // e.g. "exports": "./dist/index.js" -> use "./index.<ext>" as entry
1354
1382
  entryPath = entryPath || await getSourcePathFromExportPath(cwd, '.', 'default') || '';
1355
1383
  }
1384
+ // Handle CLI input
1356
1385
  if (entryPath) {
1357
1386
  let mainEntryPath;
1358
1387
  let typesEntryPath;
1359
1388
  // with -o option
1360
1389
  if (options.file) {
1361
1390
  mainEntryPath = options.file;
1362
- } else if (exportKeys.length === 0) {
1363
- mainEntryPath = path.resolve(cwd, 'dist/index.js');
1364
1391
  }
1365
1392
  if (mainEntryPath) {
1366
1393
  if (options.dts) {
1367
- typesEntryPath = getTypeFilePath(mainEntryPath, undefined, cwd);
1394
+ typesEntryPath = getExportFileTypePath(mainEntryPath);
1368
1395
  }
1369
1396
  exportPaths['.'] = constructDefaultExportCondition({
1370
1397
  main: mainEntryPath,
@@ -1372,11 +1399,10 @@ async function bundle(entryPath, { cwd: _cwd, ...options } = {}) {
1372
1399
  }, packageType);
1373
1400
  }
1374
1401
  }
1375
- const bundleOrWatch = (rollupConfig)=>{
1376
- const { input, exportName } = rollupConfig;
1377
- const exportPath = getExportPath(pkg, cwd, exportName);
1378
- // Log original entry file relative path
1379
- typeof input.input === 'string' ? path.relative(cwd, input.input) : exportPath;
1402
+ const bundleOrWatch = async (rollupConfig)=>{
1403
+ if (options.clean) {
1404
+ await removeOutputDir(rollupConfig.output);
1405
+ }
1380
1406
  if (options.watch) {
1381
1407
  return Promise.resolve(runWatch(rollupConfig));
1382
1408
  }
@@ -1399,6 +1425,14 @@ async function bundle(entryPath, { cwd: _cwd, ...options } = {}) {
1399
1425
  }
1400
1426
  }
1401
1427
  const entries = await collectEntries(pkg, entryPath, exportPaths, cwd);
1428
+ const hasTypeScriptFiles = Object.values(entries).some((entry)=>isTypescriptFile(entry.source));
1429
+ if (hasTypeScriptFiles && !hasTsConfig) {
1430
+ const tsConfigPath = path.resolve(cwd, 'tsconfig.json');
1431
+ defaultTsOptions.tsConfigPath = tsConfigPath;
1432
+ await fsp__default.default.writeFile(tsConfigPath, JSON.stringify(DEFAULT_TS_CONFIG, null, 2), 'utf-8');
1433
+ logger.log(`Detected using TypeScript but tsconfig.json is missing, created a ${pc.blue('tsconfig.json')} for you.`);
1434
+ hasTsConfig = true;
1435
+ }
1402
1436
  const sizeCollector = createOutputState({
1403
1437
  entries
1404
1438
  });
@@ -1409,6 +1443,7 @@ async function bundle(entryPath, { cwd: _cwd, ...options } = {}) {
1409
1443
  exportPaths,
1410
1444
  cwd,
1411
1445
  tsOptions: defaultTsOptions,
1446
+ useTypeScript: hasTsConfig,
1412
1447
  pluginContext: {
1413
1448
  outputState: sizeCollector,
1414
1449
  moduleDirectiveLayerMap: new Map(),
@@ -1422,10 +1457,12 @@ async function bundle(entryPath, { cwd: _cwd, ...options } = {}) {
1422
1457
  if (result.length === 0) {
1423
1458
  logger.warn('The "src" directory does not contain any entry files. ' + 'For proper usage, please refer to the following link: ' + 'https://github.com/huozhi/bunchee#usage');
1424
1459
  }
1425
- logOutputState(sizeCollector);
1460
+ if (!options.watch) {
1461
+ logOutputState(sizeCollector);
1462
+ }
1426
1463
  return result;
1427
1464
  }
1428
- function runWatch({ input, output }, metadata) {
1465
+ function runWatch({ input, output }) {
1429
1466
  const watchOptions = [
1430
1467
  {
1431
1468
  ...input,
@@ -1459,6 +1496,12 @@ function runWatch({ input, output }, metadata) {
1459
1496
  });
1460
1497
  return watcher;
1461
1498
  }
1499
+ async function removeOutputDir(output) {
1500
+ const dirs = new Set(output.map(({ dir })=>dir));
1501
+ for (const dir of dirs){
1502
+ if (dir) await removeDir(dir);
1503
+ }
1504
+ }
1462
1505
  function runBundle({ input, output }) {
1463
1506
  return rollup.rollup(input).then((bundle)=>{
1464
1507
  const writeJobs = output.map((options)=>bundle.write(options));