bunchee 3.2.0 → 3.3.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.d.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  import { JscTarget } from '@swc/core';
2
2
  import { OutputOptions } from 'rollup';
3
3
 
4
- type ExportType = 'require' | 'export' | 'default' | string;
5
4
  type BundleConfig = {
6
5
  file?: string;
7
6
  cwd?: string;
@@ -15,13 +14,7 @@ type BundleConfig = {
15
14
  env?: string[];
16
15
  dts?: boolean;
17
16
  runtime?: string;
18
- exportCondition?: {
19
- source: string;
20
- name: string;
21
- export: ExportCondition;
22
- };
23
17
  };
24
- type ExportCondition = string | Record<ExportType, string>;
25
18
 
26
19
  declare function bundle(entryPath: string, { cwd: _cwd, ...options }?: BundleConfig): Promise<any>;
27
20
 
package/dist/index.js CHANGED
@@ -39,7 +39,8 @@ function chunkSizeCollector() {
39
39
  const dir = options.dir || options.file && path__default.default.dirname(options.file);
40
40
  let fileName = chunk.fileName;
41
41
  if (dir) {
42
- fileName = path__default.default.relative(cwd, path__default.default.join(dir, fileName));
42
+ const filePath = path__default.default.join(dir, fileName);
43
+ fileName = filePath.startsWith(cwd) ? path__default.default.relative(cwd, filePath) : filePath;
43
44
  }
44
45
  addSize(fileName, code.length);
45
46
  return null;
@@ -66,20 +67,88 @@ function getTypings(pkg) {
66
67
  function getDistPath(distPath, cwd) {
67
68
  return path.resolve(cwd, distPath);
68
69
  }
69
- function findExport(field) {
70
- if (!field) return;
71
- if (typeof field === 'string') return field;
72
- const value = field['.'] || field['import'] || field['module'] || field['default'];
73
- return findExport(value);
70
+ // Reached the end of the export path
71
+ function isExportLike(field) {
72
+ if (typeof field === 'string') return true;
73
+ return Object.entries(field).every(// Every value is string and key is not start with '.'
74
+ // TODO: check key is ExportType
75
+ ([key, value])=>typeof value === 'string' && !key.startsWith('.'));
76
+ }
77
+ function constructFullExportCondition(value, packageType) {
78
+ const isCommonjs = packageType === 'commonjs';
79
+ let result;
80
+ if (typeof value === 'string') {
81
+ // TODO: determine cjs or esm by "type" field in package.json
82
+ result = {
83
+ [isCommonjs ? 'require' : 'import']: value
84
+ };
85
+ } else {
86
+ // TODO: valid export condition, warn if it's not valid
87
+ const keys = Object.keys(value);
88
+ result = {};
89
+ keys.forEach((key)=>{
90
+ // Filter out nullable value
91
+ if (key in value && value[key]) {
92
+ result[key] = value[key];
93
+ }
94
+ });
95
+ }
96
+ return result;
97
+ }
98
+ function joinRelativePath(...segments) {
99
+ let result = path.join(...segments);
100
+ // If the first segment starts with './', ensure the result does too.
101
+ if (segments[0] === '.' && !result.startsWith('./')) {
102
+ result = './' + result;
103
+ }
104
+ return result;
74
105
  }
75
- function parseExport(exportsCondition) {
106
+ function findExport(name, value, paths, packageType) {
107
+ // TODO: handle export condition based on package.type
108
+ if (isExportLike(value)) {
109
+ paths[name] = constructFullExportCondition(value, packageType);
110
+ return;
111
+ }
112
+ Object.keys(value).forEach((subpath)=>{
113
+ const nextName = joinRelativePath(name, subpath);
114
+ const nestedValue = value[subpath];
115
+ findExport(nextName, nestedValue, paths, packageType);
116
+ });
117
+ }
118
+ /**
119
+ *
120
+ * Convert package.exports field to paths mapping
121
+ * Example
122
+ *
123
+ * Input:
124
+ * {
125
+ * ".": {
126
+ * "sub": {
127
+ * "import": "./sub.js",
128
+ * "require": "./sub.cjs",
129
+ * "types": "./sub.d.ts
130
+ * }
131
+ * }
132
+ * }
133
+ *
134
+ * Output:
135
+ * {
136
+ * "./sub": {
137
+ * "import": "./sub.js",
138
+ * "require": "./sub.cjs",
139
+ * "types": "./sub.d.ts,
140
+ * }
141
+ * }
142
+ *
143
+ */ function parseExport(exportsCondition, packageType) {
76
144
  const paths = {};
77
145
  if (typeof exportsCondition === 'string') {
78
- paths.export = exportsCondition;
79
- } else {
80
- paths.main = paths.main || exportsCondition['require'] || exportsCondition['node'] || exportsCondition['default'];
81
- paths.module = paths.module || exportsCondition['module'];
82
- paths.export = findExport(exportsCondition);
146
+ paths['.'] = constructFullExportCondition(exportsCondition, packageType);
147
+ } else if (typeof exportsCondition === 'object') {
148
+ Object.keys(exportsCondition).forEach((key)=>{
149
+ const value = exportsCondition[key];
150
+ findExport(key, value, paths, packageType);
151
+ });
83
152
  }
84
153
  return paths;
85
154
  }
@@ -124,55 +193,83 @@ function parseExport(exportsCondition) {
124
193
  * pkg.main and pkg.module will be added to ['.'] if exists
125
194
  */ function getExportPaths(pkg) {
126
195
  const pathsMap = {};
127
- const mainExport = {};
128
- if (pkg.main) {
129
- mainExport.main = pkg.main;
130
- }
131
- if (pkg.module) {
132
- mainExport.module = pkg.module;
133
- }
134
- pathsMap['.'] = mainExport;
196
+ const packageType = getPackageType(pkg);
135
197
  const { exports: exportsConditions } = pkg;
136
198
  if (exportsConditions) {
137
- if (typeof exportsConditions === 'string') {
138
- mainExport.export = exportsConditions;
139
- } else {
140
- const exportKeys = Object.keys(exportsConditions);
141
- if (exportKeys.some((key)=>key.startsWith('.'))) {
142
- exportKeys.forEach((subExport)=>{
143
- pathsMap[subExport] = parseExport(exportsConditions[subExport]);
144
- });
145
- } else {
146
- Object.assign(mainExport, parseExport(exportsConditions));
147
- }
148
- }
199
+ const paths = parseExport(exportsConditions, packageType);
200
+ Object.assign(pathsMap, paths);
201
+ }
202
+ // main export '.' from main/module/typings
203
+ const defaultMainExport = constructFullExportCondition({
204
+ [packageType === 'commonjs' ? 'require' : 'import']: pkg.main,
205
+ module: pkg.module,
206
+ types: getTypings(pkg)
207
+ }, packageType);
208
+ // Merge the main export into '.' paths
209
+ const mainExport = Object.assign({}, pathsMap['.'], defaultMainExport);
210
+ // main export is not empty
211
+ if (Object.keys(mainExport).length > 0) {
212
+ pathsMap['.'] = mainExport;
149
213
  }
150
- pathsMap['.'] = mainExport;
151
214
  return pathsMap;
152
215
  }
153
- function getExportDist(pkg, cwd) {
154
- const paths = getExportPaths(pkg)['.'];
216
+ function getPackageType(pkg) {
217
+ return pkg.type || 'commonjs';
218
+ }
219
+ function constructDefaultExportCondition(value, packageType) {
220
+ const objValue = typeof value === 'string' ? {
221
+ [packageType === 'commonjs' ? 'require' : 'import']: value,
222
+ types: getTypings(value)
223
+ } : value;
224
+ return constructFullExportCondition(objValue, packageType);
225
+ }
226
+ function isEsmExportName(name) {
227
+ return [
228
+ 'import',
229
+ 'module',
230
+ 'react-native',
231
+ 'react-server',
232
+ 'edge-light'
233
+ ].includes(name);
234
+ }
235
+ function isCjsExportName(name) {
236
+ return [
237
+ 'require',
238
+ 'main',
239
+ 'node',
240
+ 'default'
241
+ ].includes(name);
242
+ }
243
+ function getExportConditionDist(pkg, parsedExportCondition, cwd) {
155
244
  const dist = [];
156
- if (paths.main) {
157
- dist.push({
158
- format: 'cjs',
159
- file: getDistPath(paths.main, cwd)
160
- });
161
- }
162
- if (paths.module) {
163
- dist.push({
164
- format: 'esm',
165
- file: getDistPath(paths.module, cwd)
166
- });
167
- }
168
- if (paths.export) {
245
+ const existed = new Set();
246
+ const exportTypes = Object.keys(parsedExportCondition.export);
247
+ for (const key of exportTypes){
248
+ if (key === 'types') {
249
+ continue;
250
+ }
251
+ const relativePath = parsedExportCondition.export[key];
252
+ const distFile = getDistPath(relativePath, cwd);
253
+ let format = 'esm';
254
+ if (isEsmExportName(key)) {
255
+ format = 'esm';
256
+ } else if (isCjsExportName(key)) {
257
+ format = 'cjs';
258
+ }
259
+ // Deduplicate the same path jobs
260
+ // TODO: detect conflicts paths but with different format
261
+ if (existed.has(distFile)) {
262
+ continue;
263
+ }
264
+ existed.add(distFile);
169
265
  dist.push({
170
- format: 'esm',
171
- file: getDistPath(paths.export, cwd)
266
+ format,
267
+ file: distFile
172
268
  });
173
269
  }
174
- // default fallback to output `dist/index.js` in default esm format
175
270
  if (dist.length === 0) {
271
+ // TODO: Deprecate this warning and behavior in v3
272
+ console.error(`Doesn't fin any exports in ${pkg.name}, using default dist path dist/index.js`);
176
273
  dist.push({
177
274
  format: 'esm',
178
275
  file: getDistPath('dist/index.js', cwd)
@@ -180,40 +277,6 @@ function getExportDist(pkg, cwd) {
180
277
  }
181
278
  return dist;
182
279
  }
183
- function getExportConditionDist(pkg, exportCondition, cwd) {
184
- const dist = [];
185
- // "exports": "..."
186
- if (typeof exportCondition === 'string') {
187
- dist.push({
188
- format: pkg.type === 'module' ? 'esm' : 'cjs',
189
- file: getDistPath(exportCondition, cwd)
190
- });
191
- } else {
192
- // "./<subexport>": { }
193
- const subExports = exportCondition;
194
- // Ignore json exports, like "./package.json"
195
- if (typeof subExports === 'string') {
196
- dist.push({
197
- format: 'esm',
198
- file: getDistPath(subExports, cwd)
199
- });
200
- } else {
201
- if (subExports.require) {
202
- dist.push({
203
- format: 'cjs',
204
- file: getDistPath(subExports.require, cwd)
205
- });
206
- }
207
- if (subExports.import) {
208
- dist.push({
209
- format: 'esm',
210
- file: getDistPath(subExports.import, cwd)
211
- });
212
- }
213
- }
214
- }
215
- return dist;
216
- }
217
280
 
218
281
  function asyncGeneratorStep$3(gen, resolve, reject, _next, _throw, key, arg) {
219
282
  try {
@@ -448,6 +511,7 @@ function buildInputConfig(entry, pkg, options, cwd, { tsConfigPath , tsCompilerO
448
511
  preferBuiltins: runtime === 'node',
449
512
  extensions: [
450
513
  '.mjs',
514
+ '.cjs',
451
515
  '.js',
452
516
  '.json',
453
517
  '.node',
@@ -515,16 +579,16 @@ function hasEsmExport(exportPaths, tsCompilerOptions) {
515
579
  let hasEsm = false;
516
580
  for(const key in exportPaths){
517
581
  const exportInfo = exportPaths[key];
518
- if (exportInfo.import || exportInfo.module) {
582
+ const exportNames = Object.keys(exportInfo);
583
+ if (exportNames.some((name)=>isEsmExportName(name))) {
519
584
  hasEsm = true;
520
585
  break;
521
586
  }
522
587
  }
523
588
  return Boolean(hasEsm || (tsCompilerOptions == null ? void 0 : tsCompilerOptions.esModuleInterop));
524
589
  }
525
- function buildOutputConfigs(pkg, options, cwd, { tsCompilerOptions }, dtsOnly) {
526
- const { format , exportCondition } = options;
527
- const exportPaths = getExportPaths(pkg);
590
+ function buildOutputConfigs(pkg, exportPaths, options, exportCondition, cwd, { tsCompilerOptions }, dtsOnly) {
591
+ const { format } = options;
528
592
  // Add esm mark and interop helper if esm export is detected
529
593
  const useEsModuleMark = hasEsmExport(exportPaths, tsCompilerOptions);
530
594
  const typings = getTypings(pkg);
@@ -532,7 +596,8 @@ function buildOutputConfigs(pkg, options, cwd, { tsCompilerOptions }, dtsOnly)
532
596
  const dtsDir = typings ? path.dirname(path.resolve(cwd, typings)) : path.resolve(cwd, 'dist');
533
597
  // file base name without extension
534
598
  const name = file ? file.replace(new RegExp(`${path.extname(file)}$`), '') : undefined;
535
- const dtsFile = file ? name + '.d.ts' : (exportCondition == null ? void 0 : exportCondition.name) ? path.resolve(dtsDir, (exportCondition.name === '.' ? 'index' : exportCondition.name) + '.d.ts') : typings && path.resolve(cwd, typings);
599
+ // TODO: simplify dts file name detection
600
+ const dtsFile = exportCondition.export['types'] ? path.resolve(cwd, exportCondition.export['types']) : file ? name + '.d.ts' : (exportCondition == null ? void 0 : exportCondition.name) ? path.resolve(dtsDir, (exportCondition.name === '.' ? 'index' : exportCondition.name) + '.d.ts') : typings && path.resolve(cwd, typings);
536
601
  // If there's dts file, use `output.file`
537
602
  const dtsPathConfig = dtsFile ? {
538
603
  file: dtsFile
@@ -554,73 +619,71 @@ function buildOutputConfigs(pkg, options, cwd, { tsCompilerOptions }, dtsOnly)
554
619
  });
555
620
  }
556
621
  // build configs for each entry from package exports
557
- function buildEntryConfig(pkg, bundleConfig, cwd, tsOptions, dtsOnly) {
622
+ function buildEntryConfig(pkg, entryPath, exportPaths, bundleConfig, cwd, tsOptions, dtsOnly) {
558
623
  return _buildEntryConfig.apply(this, arguments);
559
624
  }
560
625
  function _buildEntryConfig() {
561
- _buildEntryConfig = _async_to_generator$2(function*(pkg, bundleConfig, cwd, tsOptions, dtsOnly) {
562
- const packageExports = pkg.exports || {};
563
- const configs = Object.keys(packageExports).map(/*#__PURE__*/ _async_to_generator$2(function*(entryExport) {
564
- const source = yield getSourcePathFromExportPath(cwd, entryExport);
626
+ _buildEntryConfig = _async_to_generator$2(function*(pkg, entryPath, exportPaths, bundleConfig, cwd, tsOptions, dtsOnly) {
627
+ const configs = Object.keys(exportPaths).map(/*#__PURE__*/ _async_to_generator$2(function*(entryExport) {
628
+ // TODO: improve the source detection
629
+ const source = (yield getSourcePathFromExportPath(cwd, entryExport)) || entryPath;
565
630
  if (!source) return undefined;
566
- if (dtsOnly && !(tsOptions == null ? void 0 : tsOptions.tsConfigPath)) return;
567
- bundleConfig.exportCondition = {
631
+ const exportCondition = {
568
632
  source,
569
633
  name: entryExport,
570
- export: packageExports[entryExport]
634
+ export: exportPaths[entryExport]
571
635
  };
572
636
  const entry = resolveSourceFile(cwd, source);
573
- const rollupConfig = buildConfig(entry, pkg, bundleConfig, cwd, tsOptions, dtsOnly);
637
+ const rollupConfig = buildConfig(entry, pkg, exportPaths, bundleConfig, exportCondition, cwd, tsOptions, dtsOnly);
574
638
  return rollupConfig;
575
639
  }));
576
640
  return (yield Promise.all(configs)).filter((n)=>Boolean(n));
577
641
  });
578
642
  return _buildEntryConfig.apply(this, arguments);
579
643
  }
580
- function buildConfig(entry, pkg, bundleConfig, cwd, tsOptions, dtsOnly) {
581
- var _options_exportCondition;
644
+ function buildConfig(entry, pkg, exportPaths, bundleConfig, exportCondition, cwd, tsOptions, dtsOnly) {
582
645
  const { file } = bundleConfig;
583
646
  const useTypescript = Boolean(tsOptions.tsConfigPath);
584
647
  const options = _extends$1({}, bundleConfig, {
585
648
  useTypescript
586
649
  });
587
650
  const inputOptions = buildInputConfig(entry, pkg, options, cwd, tsOptions, dtsOnly);
588
- const outputExports = options.exportCondition ? getExportConditionDist(pkg, options.exportCondition.export, cwd) : getExportDist(pkg, cwd);
651
+ const outputExports = getExportConditionDist(pkg, exportCondition, cwd);
589
652
  let outputConfigs = [];
590
653
  // Generate dts job - single config
591
654
  if (dtsOnly) {
592
655
  outputConfigs = [
593
- buildOutputConfigs(pkg, _extends$1({}, bundleConfig, {
656
+ buildOutputConfigs(pkg, exportPaths, _extends$1({}, bundleConfig, {
594
657
  format: 'es',
595
658
  useTypescript
596
- }), cwd, tsOptions, dtsOnly)
659
+ }), exportCondition, cwd, tsOptions, dtsOnly)
597
660
  ];
598
661
  } else {
599
662
  // multi outputs with specified format
600
663
  outputConfigs = outputExports.map((exportDist)=>{
601
- return buildOutputConfigs(pkg, _extends$1({}, bundleConfig, {
664
+ return buildOutputConfigs(pkg, exportPaths, _extends$1({}, bundleConfig, {
602
665
  file: exportDist.file,
603
666
  format: exportDist.format,
604
667
  useTypescript
605
- }), cwd, tsOptions, dtsOnly);
668
+ }), exportCondition, cwd, tsOptions, dtsOnly);
606
669
  });
607
670
  // CLI output option is always prioritized
608
671
  if (file) {
609
672
  var _outputExports_;
610
673
  const fallbackFormat = (_outputExports_ = outputExports[0]) == null ? void 0 : _outputExports_.format;
611
674
  outputConfigs = [
612
- buildOutputConfigs(pkg, _extends$1({}, bundleConfig, {
675
+ buildOutputConfigs(pkg, exportPaths, _extends$1({}, bundleConfig, {
613
676
  file,
614
677
  format: bundleConfig.format || fallbackFormat,
615
678
  useTypescript
616
- }), cwd, tsOptions, dtsOnly)
679
+ }), exportCondition, cwd, tsOptions, dtsOnly)
617
680
  ];
618
681
  }
619
682
  }
620
683
  return {
621
684
  input: inputOptions,
622
685
  output: outputConfigs,
623
- exportName: ((_options_exportCondition = options.exportCondition) == null ? void 0 : _options_exportCondition.name) || '.'
686
+ exportName: exportCondition.name || '.'
624
687
  };
625
688
  }
626
689
 
@@ -764,10 +827,8 @@ function assignDefault(options, name, defaultValue) {
764
827
  options[name] = defaultValue;
765
828
  }
766
829
  }
767
- function hasMultiEntryExport(pkg) {
768
- const packageExportsField = pkg.exports || {};
769
- if (typeof packageExportsField === 'string') return false;
770
- const exportKeys = (packageExportsField ? Object.keys(packageExportsField) : []).filter((key)=>key !== './package.json');
830
+ function hasMultiEntryExport(exportPaths) {
831
+ const exportKeys = Object.keys(exportPaths).filter((key)=>key !== './package.json');
771
832
  return exportKeys.length > 0 && exportKeys.every((name)=>name.startsWith('.'));
772
833
  }
773
834
  function bundle(entryPath) {
@@ -783,8 +844,12 @@ function _bundle() {
783
844
  assignDefault(options, 'minify', false);
784
845
  assignDefault(options, 'target', 'es2015');
785
846
  const pkg = yield getPackageMeta(cwd);
786
- const packageExportsField = pkg.exports || {};
787
- const isMultiEntries = hasMultiEntryExport(pkg);
847
+ const packageType = getPackageType(pkg);
848
+ const exportPaths = getExportPaths(pkg);
849
+ const exportKeys = Object.keys(exportPaths).filter((key)=>key !== './package.json');
850
+ // const exportPathsLength = Object.keys(exportPaths).length
851
+ const isMultiEntries = hasMultiEntryExport(exportPaths) // exportPathsLength > 1
852
+ ;
788
853
  const tsConfig = yield resolveTsConfig(cwd);
789
854
  const hasTsConfig = Boolean(tsConfig == null ? void 0 : tsConfig.tsConfigPath);
790
855
  const defaultTsOptions = {
@@ -797,6 +862,9 @@ function _bundle() {
797
862
  // e.g. "exports": "./dist/index.js" -> use "./index.<ext>" as entry
798
863
  entryPath = entryPath || (yield getSourcePathFromExportPath(cwd, '.')) || '';
799
864
  }
865
+ if (exportKeys.length === 0 && entryPath) {
866
+ exportPaths['.'] = constructDefaultExportCondition(entryPath, packageType);
867
+ }
800
868
  const bundleOrWatch = (rollupConfig)=>{
801
869
  const { input , exportName } = rollupConfig;
802
870
  const exportPath = getExportPath(pkg, cwd, exportName);
@@ -817,25 +885,16 @@ function _bundle() {
817
885
  return Promise.reject(err);
818
886
  }
819
887
  // has `types` field in package.json or has `types` exports in any export condition for multi-entries
820
- const hasTypings = !!getTypings(pkg) || typeof packageExportsField === 'object' && Array.from(Object.values(packageExportsField || {})).some((condition)=>condition.hasOwnProperty('types'));
888
+ const hasTypings = Object.values(exportPaths).some((condition)=>condition.hasOwnProperty('types'));
821
889
  // Enable types generation if it's types field specified in package.json
822
890
  if (hasTypings) {
823
891
  options.dts = hasTypings;
824
892
  }
825
893
  let result;
826
- if (isMultiEntries) {
827
- const buildConfigs = yield buildEntryConfig(pkg, options, cwd, defaultTsOptions, false);
828
- const assetsJobs = buildConfigs.map((rollupConfig)=>bundleOrWatch(rollupConfig));
829
- const typesJobs = options.dts ? (yield buildEntryConfig(pkg, options, cwd, defaultTsOptions, true)).map((rollupConfig)=>bundleOrWatch(rollupConfig)) : [];
830
- result = yield Promise.all(assetsJobs.concat(typesJobs));
831
- } else {
832
- // Generate types
833
- if (hasTsConfig && options.dts) {
834
- yield bundleOrWatch(buildConfig(entryPath, pkg, options, cwd, defaultTsOptions, true));
835
- }
836
- const rollupConfig = buildConfig(entryPath, pkg, options, cwd, defaultTsOptions, false);
837
- result = yield bundleOrWatch(rollupConfig);
838
- }
894
+ const buildConfigs = yield buildEntryConfig(pkg, entryPath, exportPaths, options, cwd, defaultTsOptions, false);
895
+ const assetsJobs = buildConfigs.map((rollupConfig)=>bundleOrWatch(rollupConfig));
896
+ const typesJobs = hasTsConfig && options.dts ? (yield buildEntryConfig(pkg, entryPath, exportPaths, options, cwd, defaultTsOptions, true)).map((rollupConfig)=>bundleOrWatch(rollupConfig)) : [];
897
+ result = yield Promise.all(assetsJobs.concat(typesJobs));
839
898
  logSizeStats();
840
899
  return result;
841
900
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bunchee",
3
- "version": "3.2.0",
3
+ "version": "3.3.0",
4
4
  "description": "zero config bundler for js/ts/jsx libraries",
5
5
  "bin": {
6
6
  "bunchee": "./dist/cli.js"
package/dist/cli.d.ts DELETED
@@ -1 +0,0 @@
1
- #!/usr/bin/env node