|
| 1 | +function replaceName(filename, name) { |
| 2 | + return resolve( |
| 3 | + dirname(filename), |
| 4 | + name + basename(filename).replace(/^[^.]+/, ''), |
| 5 | + ); |
| 6 | +} |
| 7 | + |
| 8 | +/** |
| 9 | + * @param {any} exports - package.json "exports" field value |
| 10 | + * @param {string} exportPath - the export to look up (eg: '.', './a', './b/c') |
| 11 | + * @param {string[]} conditions - conditional export keys to use (note: unlike in resolution, order here *does* define precedence!) |
| 12 | + * @param {RegExp|string} [defaultPattern] - only use (resolved) default export filenames that match this pattern |
| 13 | + * @param {string} [condition] - (internal) the nearest condition key on the stack |
| 14 | + */ |
| 15 | +function walk(exports, exportPath, conditions, defaultPattern, condition) { |
| 16 | + if (!exports) return; |
| 17 | + if (typeof exports === 'string') { |
| 18 | + if ( |
| 19 | + condition === 'default' && |
| 20 | + defaultPattern && |
| 21 | + !exports.match(defaultPattern) |
| 22 | + ) { |
| 23 | + return; |
| 24 | + } |
| 25 | + return exports; |
| 26 | + } |
| 27 | + if (Array.isArray(exports)) { |
| 28 | + for (const map of exports) { |
| 29 | + const r = walk(map, exportPath, conditions, defaultPattern, condition); |
| 30 | + if (r) return r; |
| 31 | + } |
| 32 | + return; |
| 33 | + } |
| 34 | + const map = exports[exportPath]; |
| 35 | + if (map) { |
| 36 | + const r = walk(map, exportPath, conditions, defaultPattern, condition); |
| 37 | + if (r) return r; |
| 38 | + } |
| 39 | + for (const condition of conditions) { |
| 40 | + const map = exports[condition]; |
| 41 | + if (!map) continue; |
| 42 | + const r = walk(map, exportPath, conditions, defaultPattern, condition); |
| 43 | + if (r) return r; |
| 44 | + } |
| 45 | + // return walk(exports['.'] || exports.import || exports.module); |
| 46 | +} |
| 47 | + |
| 48 | +function getMain({ options, entry, format }) { |
| 49 | + const { pkg } = options; |
| 50 | + const pkgMain = options['pkg-main']; |
| 51 | + |
| 52 | + if (!pkgMain) { |
| 53 | + return options.output; |
| 54 | + } |
| 55 | + |
| 56 | + // package.json export name (see https://nodejs.org/api/packages.html#packages_subpath_exports) |
| 57 | + let exportPath = '.'; |
| 58 | + let mainNoExtension = options.output; |
| 59 | + if (options.multipleEntries) { |
| 60 | + const commonDir = options.entries |
| 61 | + .reduce((acc, entry) => { |
| 62 | + entry = dirname(entry).split(sep); |
| 63 | + if (!acc) return entry; |
| 64 | + if (entry.length < acc.length) acc.length = entry.length; |
| 65 | + let last = entry.length - 1; |
| 66 | + while (entry[last] !== acc[last]) { |
| 67 | + last--; |
| 68 | + acc.pop(); |
| 69 | + } |
| 70 | + return acc; |
| 71 | + }, undefined) |
| 72 | + .join(sep); |
| 73 | + console.log('>>>>>', { first: options.entries[0], commonDir }); |
| 74 | + |
| 75 | + const isMainEntry = entry.match( |
| 76 | + /([\\/])index(\.(umd|cjs|es|m))?\.(mjs|cjs|[tj]sx?)$/, |
| 77 | + ); |
| 78 | + let name = isMainEntry ? mainNoExtension : entry; |
| 79 | + mainNoExtension = resolve(dirname(mainNoExtension), basename(name)); |
| 80 | + if (!isMainEntry) { |
| 81 | + exportPath = |
| 82 | + './' + |
| 83 | + posix.relative(commonDir, entry.replace(/\.([mc]js|[tj]sx?)$/g, '')); |
| 84 | + } |
| 85 | + } |
| 86 | + mainNoExtension = mainNoExtension.replace( |
| 87 | + /(\.(umd|cjs|es|m))?\.(mjs|cjs|[tj]sx?)$/, |
| 88 | + '', |
| 89 | + ); |
| 90 | + |
| 91 | + const mainsByFormat = {}; |
| 92 | + |
| 93 | + const MJS = pkg.type === 'module' ? /\.m?js$/i : /\.mjs$/i; |
| 94 | + const CJS = pkg.type === 'module' ? /\.cjs$/i : /\.js$/i; |
| 95 | + const UMD = /[.-]umd\.c?js$/i; |
| 96 | + const CONDITIONS_MJS = ['import', 'module', 'default']; |
| 97 | + const CONDITIONS_MODERN = ['modern', 'esmodules', ...CONDITIONS_MJS]; |
| 98 | + const CONDITIONS_CJS = ['require', 'default']; |
| 99 | + const CONDITIONS_UMD = ['umd', 'default']; |
| 100 | + |
| 101 | + mainsByFormat.modern = |
| 102 | + walk(pkg.exports, exportPath, CONDITIONS_MODERN, MJS) || |
| 103 | + (pkg.syntax && pkg.syntax.esmodules) || |
| 104 | + pkg.esmodule || |
| 105 | + replaceName('x.modern.js', mainNoExtension); |
| 106 | + |
| 107 | + mainsByFormat.es = walk(pkg.exports, exportPath, CONDITIONS_MJS, MJS); |
| 108 | + if (!mainsByFormat.es || mainsByFormat.es === mainsByFormat.modern) { |
| 109 | + mainsByFormat.es = |
| 110 | + pkg.module && !pkg.module.match(/src\//) |
| 111 | + ? pkg.module |
| 112 | + : pkg['jsnext:main'] || replaceName('x.esm.js', mainNoExtension); |
| 113 | + } |
| 114 | + |
| 115 | + mainsByFormat.umd = |
| 116 | + walk(pkg.exports, exportPath, CONDITIONS_UMD, UMD) || |
| 117 | + pkg['umd:main'] || |
| 118 | + pkg.unpkg || |
| 119 | + replaceName('x.umd.js', mainNoExtension); |
| 120 | + |
| 121 | + mainsByFormat.cjs = walk(pkg.exports, exportPath, CONDITIONS_CJS, CJS); |
| 122 | + if (!mainsByFormat.cjs || mainsByFormat.cjs === mainsByFormat.umd) { |
| 123 | + mainsByFormat.cjs = |
| 124 | + pkg['cjs:main'] || |
| 125 | + replaceName(pkg.type === 'module' ? 'x.cjs' : 'x.js', mainNoExtension); |
| 126 | + } |
| 127 | + |
| 128 | + if (pkg.type === 'module') { |
| 129 | + let errors = []; |
| 130 | + let filenames = []; |
| 131 | + if (mainsByFormat.cjs.endsWith('.js')) { |
| 132 | + errors.push('CommonJS'); |
| 133 | + filenames.push(` "cjs:main": "${mainsByFormat.cjs}",`); |
| 134 | + } |
| 135 | + if (mainsByFormat.umd.endsWith('.js')) { |
| 136 | + errors.push('CommonJS'); |
| 137 | + const field = pkg['umd:main'] ? 'umd:main' : 'unpkg'; |
| 138 | + filenames.push(` "${field}": "${mainsByFormat.umd}",`); |
| 139 | + } |
| 140 | + if (errors.length) { |
| 141 | + const warning = |
| 142 | + `Warning: A package.json with {"type":"module"} should use .cjs file extensions for` + |
| 143 | + ` ${errors.join(' and ')} filename${errors.length == 1 ? '' : 's'}:` + |
| 144 | + `\n${filenames.join('\n')}`; |
| 145 | + stderr(yellow(warning)); |
| 146 | + } |
| 147 | + } |
| 148 | + |
| 149 | + console.log('>> MAIN: ', format, entry, exportPath, mainsByFormat[format]); |
| 150 | + |
| 151 | + return mainsByFormat[format] || mainsByFormat.cjs; |
| 152 | +} |
0 commit comments