Comparing version 4.3.4 to 4.4.0
@@ -6,2 +6,3 @@ #!/usr/bin/env node | ||
var fsp = require('fs/promises'); | ||
require('rimraf'); | ||
var require$$0 = require('tty'); | ||
@@ -29,2 +30,3 @@ var bunchee = require('bunchee'); | ||
const SRC = 'src'; | ||
const DIST = 'dist'; | ||
const dtsExtensionsMap = { | ||
@@ -41,2 +43,8 @@ js: 'd.ts', | ||
]); | ||
const DEFAULT_TS_CONFIG = { | ||
compilerOptions: { | ||
module: 'ESNext', | ||
moduleResolution: 'bundler' | ||
} | ||
}; | ||
@@ -146,7 +154,364 @@ function getDefaultExportFromCjs (x) { | ||
const hasAvailableExtension = (filename)=>availableExtensions.has(path__default.default.extname(filename).slice(1)); | ||
const hasCjsExtension = (filename)=>path__default.default.extname(filename) === '.cjs'; | ||
// TODO: add unit test | ||
const baseNameWithoutExtension = (filename)=>path__default.default.basename(filename, path__default.default.extname(filename)); | ||
const isTestFile = (filename)=>/\.(test|spec)$/.test(baseNameWithoutExtension(filename)); | ||
var version = "4.3.4"; | ||
function getTypings(pkg) { | ||
return pkg.types || pkg.typings; | ||
} | ||
// Reached the end of the export path | ||
function isExportLike(field) { | ||
if (typeof field === 'string') return true; | ||
return Object.entries(field).every(// Every value is string and key is not start with '.' | ||
([key, value])=>typeof value === 'string' && !key.startsWith('.')); | ||
} | ||
function constructFullExportCondition(exportCondition, packageType) { | ||
let fullExportCond; | ||
if (typeof exportCondition === 'string') { | ||
const exportType = getExportTypeFromFile(exportCondition, packageType); | ||
fullExportCond = { | ||
[exportType]: exportCondition | ||
}; | ||
} else { | ||
const exportTypes = Object.keys(exportCondition); | ||
fullExportCond = {}; | ||
exportTypes.forEach((exportType)=>{ | ||
const condition = exportCondition[exportType]; | ||
// Filter out nullable value | ||
if (condition) { | ||
fullExportCond[exportType] = condition; | ||
} | ||
}); | ||
} | ||
return fullExportCond; | ||
} | ||
function joinRelativePath(...segments) { | ||
let result = path.join(...segments); | ||
// If the first segment starts with '.', ensure the result does too. | ||
if (segments[0] === '.' && !result.startsWith('.')) { | ||
result = './' + result; | ||
} | ||
return result; | ||
} | ||
const getFirstExportPath = (fullExportCondition)=>{ | ||
// Handle all export cond { <require|import|default>: ... } | ||
if (typeof fullExportCondition === 'object') { | ||
for (const key of Object.keys(fullExportCondition)){ | ||
if (key.startsWith('.') || key === 'types') { | ||
continue; | ||
} | ||
return fullExportCondition[key]; | ||
} | ||
} | ||
return fullExportCondition; | ||
}; | ||
function findExport(exportPath, exportCondition, paths, packageType, currentPath) { | ||
// Skip `types` field, it cannot be the entry point | ||
if (exportPath === 'types') return; | ||
if (isExportLike(exportCondition)) { | ||
const fullExportCondition = constructFullExportCondition(exportCondition, packageType); | ||
if (exportPath.startsWith('.')) { | ||
paths[exportPath] = { | ||
...paths[exportPath], | ||
...fullExportCondition | ||
}; | ||
} else { | ||
const exportJsBundlePath = getFirstExportPath(fullExportCondition); | ||
// exportPath is exportType, import, require, ... | ||
// merge to currentPath | ||
paths[currentPath] = { | ||
...paths[currentPath], | ||
[exportPath]: exportJsBundlePath | ||
}; | ||
} | ||
return; | ||
} | ||
Object.keys(exportCondition).forEach((subpath)=>{ | ||
if (subpath.startsWith('.')) { | ||
// subpath is actual export path, ./a, ./b, ... | ||
const nestedExportPath = joinRelativePath(currentPath, subpath); | ||
const nestedExportCondition = exportCondition[subpath]; | ||
findExport(nestedExportPath, nestedExportCondition, paths, packageType, nestedExportPath); | ||
} else { | ||
// subpath is exportType, import, require, ... | ||
const exportType = subpath; | ||
const defaultPath = typeof exportCondition[subpath] === 'object' ? exportCondition[subpath].default : exportCondition[subpath]; | ||
const nestedExportCondition = { | ||
[exportType]: defaultPath | ||
}; | ||
findExport(exportPath, nestedExportCondition, paths, packageType, currentPath); | ||
} | ||
}); | ||
} | ||
/** | ||
* | ||
* Convert package.exports field to paths mapping | ||
* Example | ||
* | ||
* Input: | ||
* { | ||
* "./sub": { | ||
* "import": { | ||
* "types": "./sub.js", | ||
* "default": "./sub.cjs", | ||
* } | ||
* } | ||
* } | ||
* | ||
* Output: | ||
* { | ||
* "./sub": { | ||
* "import": "./sub.js", | ||
* "require": "./sub.cjs", | ||
* "types": "./sub.d.ts", | ||
* } | ||
* } | ||
* | ||
*/ function parseExport(exportsCondition, packageType) { | ||
const paths = {}; | ||
const initialPath = '.'; | ||
if (typeof exportsCondition === 'string') { | ||
paths[initialPath] = constructFullExportCondition(exportsCondition, packageType); | ||
} else if (typeof exportsCondition === 'object') { | ||
if (isExportLike(exportsCondition)) { | ||
paths[initialPath] = constructFullExportCondition(exportsCondition, packageType); | ||
} else { | ||
Object.keys(exportsCondition).forEach((key)=>{ | ||
const exportCondition = exportsCondition[key]; | ||
findExport(key, exportCondition, paths, packageType, initialPath); | ||
}); | ||
} | ||
} | ||
return paths; | ||
} | ||
/** | ||
* Get package exports paths | ||
* | ||
* Example: | ||
* | ||
* ```json | ||
* { | ||
* "exports": { | ||
* ".": { | ||
* "require": "./dist/index.cjs", | ||
* "module": "./dist/index.esm.js", | ||
* "default": "./dist/index.esm.js" | ||
* }, | ||
* "./foo": { | ||
* "require": "./dist/foo.cjs", | ||
* "module": "./dist/foo.esm.js", | ||
* "default": "./dist/foo.esm.js" | ||
* } | ||
* } | ||
* | ||
* ``` | ||
* | ||
* will be parsed to: | ||
* | ||
* ```js | ||
* { | ||
* '.': { | ||
* main: './dist/index.cjs', | ||
* module: './dist/index.esm.js', | ||
* export: './dist/index.esm.js' | ||
* }, | ||
* './foo': { | ||
* main: './dist/foo.cjs', | ||
* module: './dist/foo.esm.js', | ||
* export: './dist/foo.esm.js' | ||
* } | ||
* | ||
* | ||
* pkg.main and pkg.module will be added to ['.'] if exists | ||
*/ function getExportPaths(pkg, resolvedWildcardExports) { | ||
var _pathsMap_; | ||
let pathsMap = {}; | ||
const packageType = getPackageType(pkg); | ||
const isEsmPackage = isESModulePackage(packageType); | ||
const exportsConditions = resolvedWildcardExports != null ? resolvedWildcardExports : pkg.exports; | ||
if (exportsConditions) { | ||
const paths = parseExport(exportsConditions, packageType); | ||
pathsMap = { | ||
...pathsMap, | ||
...paths | ||
}; | ||
} | ||
// main export '.' from main/module/typings | ||
const defaultMainExport = constructFullExportCondition({ | ||
[isEsmPackage ? 'import' : 'require']: pkg.main, | ||
module: pkg.module, | ||
types: getTypings(pkg) | ||
}, packageType); | ||
if (!isEsmPackage && ((_pathsMap_ = pathsMap['.']) == null ? void 0 : _pathsMap_['require'])) { | ||
// pathsMap's exports.require are prioritized. | ||
defaultMainExport['require'] = pathsMap['.']['require']; | ||
} | ||
// Merge the main export into '.' paths | ||
const mainExport = { | ||
...pathsMap['.'], | ||
...defaultMainExport | ||
}; | ||
// main export is not empty | ||
if (Object.keys(mainExport).length > 0) { | ||
pathsMap['.'] = { | ||
...pathsMap['.'], | ||
...mainExport | ||
}; | ||
} | ||
return pathsMap; | ||
} | ||
function getPackageType(pkg) { | ||
return pkg.type || 'commonjs'; | ||
} | ||
function isESModulePackage(packageType) { | ||
return packageType === 'module'; | ||
} | ||
function getExportTypeFromFile(filename, pkgType) { | ||
const isESModule = isESModulePackage(pkgType); | ||
const isCjsExt = filename.endsWith('.cjs'); | ||
const isEsmExt = filename.endsWith('.mjs'); | ||
const exportType = isEsmExt ? 'import' : isCjsExt ? 'require' : isESModule ? 'import' : 'require'; | ||
return exportType; | ||
} | ||
function lint$1(pkg) { | ||
const { name, main, exports } = pkg; | ||
const isESM = isESModulePackage(pkg.type); | ||
const exportPaths = getExportPaths(pkg); | ||
if (!name) { | ||
logger.warn('Missing package name'); | ||
} | ||
const state = { | ||
badMainExtension: false, | ||
badMainExport: false, | ||
invalidExportsFieldType: false, | ||
badCjsRequireExport: { | ||
value: false, | ||
paths: [] | ||
}, | ||
badCjsImportExport: { | ||
value: false, | ||
paths: [] | ||
}, | ||
badEsmRequireExport: { | ||
value: false, | ||
paths: [] | ||
}, | ||
badEsmImportExport: { | ||
value: false, | ||
paths: [] | ||
} | ||
}; | ||
// Validate ESM package | ||
if (isESM) { | ||
if (main && hasCjsExtension(main)) { | ||
state.badMainExtension = true; | ||
} | ||
if (exports) { | ||
if (typeof exports === 'string') { | ||
if (hasCjsExtension(exports)) { | ||
state.badMainExport = true; | ||
} | ||
} | ||
if (typeof exports !== 'object') { | ||
state.invalidExportsFieldType = true; | ||
} else { | ||
Object.keys(exportPaths).forEach((key)=>{ | ||
const exportConditions = exportPaths[key]; | ||
if (typeof exportConditions === 'object') { | ||
var // @ts-ignore TODO: fix the type | ||
_exportConditions_require, // @ts-ignore TODO: fix the type | ||
_exportConditions_import; | ||
var _exportConditions_require_default; | ||
const requirePath = (_exportConditions_require_default = (_exportConditions_require = exportConditions.require) == null ? void 0 : _exportConditions_require.default) != null ? _exportConditions_require_default : exportConditions.require; | ||
var _exportConditions_import_default; | ||
const importPath = (_exportConditions_import_default = (_exportConditions_import = exportConditions.import) == null ? void 0 : _exportConditions_import.default) != null ? _exportConditions_import_default : exportConditions.import; | ||
const requireExt = requirePath && path__default.default.extname(requirePath); | ||
const importExt = importPath && path__default.default.extname(importPath); | ||
if (requireExt === '.mjs' || requireExt === '.js') { | ||
state.badEsmRequireExport.value = true; | ||
state.badEsmRequireExport.paths.push(requirePath); | ||
} | ||
if (importExt === '.cjs') { | ||
state.badEsmImportExport.value = true; | ||
state.badEsmImportExport.paths.push(importPath); | ||
} | ||
} | ||
}); | ||
} | ||
} | ||
} else { | ||
// Validate CJS package | ||
if (exports) { | ||
if (typeof exports === 'string') { | ||
if (!hasCjsExtension(exports)) { | ||
state.badMainExport = true; | ||
} | ||
} | ||
if (typeof exports !== 'object') { | ||
state.invalidExportsFieldType = true; | ||
} else { | ||
Object.keys(exportPaths).forEach((key)=>{ | ||
const exportConditions = exportPaths[key]; | ||
if (typeof exportConditions === 'object') { | ||
var // @ts-ignore TODO: fix the type | ||
_exportConditions_require, // @ts-ignore TODO: fix the type | ||
_exportConditions_import; | ||
var _exportConditions_require_default; | ||
const requirePath = (_exportConditions_require_default = (_exportConditions_require = exportConditions.require) == null ? void 0 : _exportConditions_require.default) != null ? _exportConditions_require_default : exportConditions.require; | ||
var _exportConditions_import_default; | ||
const importPath = (_exportConditions_import_default = (_exportConditions_import = exportConditions.import) == null ? void 0 : _exportConditions_import.default) != null ? _exportConditions_import_default : exportConditions.import; | ||
const requireExt = requirePath && path__default.default.extname(requirePath); | ||
const importExt = importPath && path__default.default.extname(importPath); | ||
if (requireExt === '.mjs') { | ||
state.badCjsRequireExport.value = true; | ||
state.badCjsRequireExport.paths.push(requirePath); | ||
} | ||
if (importExt === '.js' || importExt === '.cjs') { | ||
state.badCjsImportExport.value = true; | ||
state.badCjsImportExport.paths.push(importPath); | ||
} | ||
} | ||
}); | ||
} | ||
} | ||
} | ||
if (state.badMainExtension) { | ||
logger.warn('Cannot export `main` field with .cjs extension in ESM package, only .mjs and .js extensions are allowed'); | ||
} | ||
if (state.badMainExport) { | ||
logger.warn('Cannot export `exports` field with .cjs extension in ESM package, only .mjs and .js extensions are allowed'); | ||
} | ||
if (state.invalidExportsFieldType) { | ||
logger.warn('Invalid exports field type, only object or string is allowed'); | ||
} | ||
if (state.badCjsRequireExport.value) { | ||
logger.warn('Cannot export `require` field with .mjs extension in CJS package, only .cjs and .js extensions are allowed'); | ||
state.badCjsRequireExport.paths.forEach((p)=>{ | ||
logger.warn(` ${p}`); | ||
}); | ||
} | ||
if (state.badCjsImportExport.value) { | ||
logger.warn('Cannot export `import` field with .js or .cjs extension in CJS package, only .mjs extensions are allowed'); | ||
state.badCjsImportExport.paths.forEach((p)=>{ | ||
logger.warn(` ${p}`); | ||
}); | ||
} | ||
if (state.badEsmRequireExport.value) { | ||
logger.warn('Cannot export `require` field with .js or .mjs extension in ESM package, only .cjs extensions are allowed'); | ||
state.badEsmRequireExport.paths.forEach((p)=>{ | ||
logger.warn(` ${p}`); | ||
}); | ||
} | ||
if (state.badEsmImportExport.value) { | ||
logger.warn('Cannot export `import` field with .cjs extension in ESM package, only .js and .mjs extensions are allowed'); | ||
state.badEsmImportExport.paths.forEach((p)=>{ | ||
logger.warn(` ${p}`); | ||
}); | ||
} | ||
} | ||
var version = "4.4.0"; | ||
function relativify(path) { | ||
@@ -156,9 +521,2 @@ return path.startsWith('.') ? path : `./${path}`; | ||
const DIST = 'dist'; | ||
const DEFAULT_TS_CONFIG = { | ||
compilerOptions: { | ||
module: 'ESNext', | ||
moduleResolution: 'bundler' | ||
} | ||
}; | ||
// Output with posix style in package.json | ||
@@ -221,3 +579,3 @@ function getDistPath(...subPaths) { | ||
const indexFile = path__default.default.join(dirent.name, `index.${extension}`); | ||
if (fs__default.default.existsSync(indexFile)) { | ||
if (fs__default.default.existsSync(indexFile) && !isTestFile(indexFile)) { | ||
exportsEntries.set(dirent.name, indexFile); | ||
@@ -236,3 +594,3 @@ break; | ||
} else { | ||
if (hasAvailableExtension(dirent.name)) { | ||
if (hasAvailableExtension(dirent.name) && !isTestFile(dirent.name)) { | ||
exportsEntries.set(baseName, dirent.name); | ||
@@ -383,2 +741,3 @@ } | ||
--no-external do not bundle external dependencies | ||
--no-clean do not clean dist folder before building, default: false | ||
--target <target> js features target: swc target es versions. default: es2015 | ||
@@ -394,3 +753,3 @@ --runtime <runtime> build runtime (nodejs, browser). default: browser | ||
} | ||
async function lintPackage(cwd) { | ||
async function lint(cwd) { | ||
// Not package.json detected, skip package linting | ||
@@ -400,12 +759,3 @@ if (!await hasPackageJson(cwd)) { | ||
} | ||
const { publint } = await import('publint'); | ||
const { formatMessage } = await import('publint/utils'); | ||
const { messages } = await publint({ | ||
pkgDir: cwd, | ||
level: 'error' | ||
}); | ||
const pkg = await getPackageMeta(cwd); | ||
for (const message of messages){ | ||
console.log(formatMessage(message, pkg)); | ||
} | ||
await lint$1(await getPackageMeta(cwd)); | ||
} | ||
@@ -429,2 +779,3 @@ function parseCliArgs(argv) { | ||
'--no-external': Boolean, | ||
'--no-clean': Boolean, | ||
'--prepare': Boolean, | ||
@@ -456,2 +807,3 @@ '-h': '--help', | ||
external: !!args['--no-external'] ? null : args['--external'], | ||
clean: !args['--no-clean'], | ||
env: args['--env'], | ||
@@ -464,3 +816,3 @@ prepare: !!args['--prepare'] | ||
var _args_external; | ||
const { source, format, watch, minify, sourcemap, target, runtime, dts, env } = args; | ||
const { source, format, watch, minify, sourcemap, target, runtime, dts, env, clean } = args; | ||
const cwd = args.cwd || process.cwd(); | ||
@@ -479,3 +831,4 @@ const file = args.file ? path__default.default.resolve(cwd, args.file) : undefined; | ||
sourcemap: sourcemap === false ? false : true, | ||
env: (env == null ? void 0 : env.split(',')) || [] | ||
env: (env == null ? void 0 : env.split(',')) || [], | ||
clean | ||
}; | ||
@@ -492,2 +845,4 @@ if (args.version) { | ||
const entry = source ? path__default.default.resolve(cwd, source) : ''; | ||
// lint package | ||
await lint(cwd); | ||
try { | ||
@@ -510,3 +865,2 @@ await bunchee.bundle(entry, bundleConfig); | ||
paint('✓', 'green', `bunchee ${version} build completed`); | ||
await lintPackage(cwd); | ||
} | ||
@@ -513,0 +867,0 @@ async function main() { |
@@ -20,2 +20,3 @@ import { JscTarget } from '@swc/types'; | ||
pkg?: PackageMetadata; | ||
clean?: boolean; | ||
}; | ||
@@ -22,0 +23,0 @@ type PackageMetadata = { |
@@ -7,4 +7,5 @@ Object.defineProperty(exports, '__esModule', { value: true }); | ||
var path = require('path'); | ||
var require$$0 = require('tty'); | ||
var module$1 = require('module'); | ||
var require$$0 = require('tty'); | ||
var rimraf = require('rimraf'); | ||
var pluginWasm = require('@rollup/plugin-wasm'); | ||
@@ -18,2 +19,3 @@ var rollupPluginSwc3 = require('rollup-plugin-swc3'); | ||
var preserveDirectives = require('rollup-preserve-directives'); | ||
var CleanCSS = require('clean-css'); | ||
var pluginutils = require('@rollup/pluginutils'); | ||
@@ -33,43 +35,5 @@ var prettyBytes = require('pretty-bytes'); | ||
var preserveDirectives__default = /*#__PURE__*/_interopDefault(preserveDirectives); | ||
var CleanCSS__default = /*#__PURE__*/_interopDefault(CleanCSS); | ||
var prettyBytes__default = /*#__PURE__*/_interopDefault(prettyBytes); | ||
const availableExtensions = new Set([ | ||
'js', | ||
'cjs', | ||
'mjs', | ||
'jsx', | ||
'ts', | ||
'tsx', | ||
'cts', | ||
'mts' | ||
]); | ||
const nodeResolveExtensions = [ | ||
'.mjs', | ||
'.cjs', | ||
'.js', | ||
'.json', | ||
'.node', | ||
'.jsx' | ||
]; | ||
const availableExportConventions = new Set([ | ||
'react-server', | ||
'react-native', | ||
'edge-light' | ||
]); | ||
const availableESExtensionsRegex = /\.(m|c)?[jt]sx?$/; | ||
const SRC = 'src'; | ||
const dtsExtensionsMap = { | ||
js: 'd.ts', | ||
cjs: 'd.cts', | ||
mjs: 'd.mts' | ||
}; | ||
const disabledWarnings = new Set([ | ||
'MIXED_EXPORTS', | ||
'PREFER_NAMED_EXPORTS', | ||
'UNRESOLVED_IMPORT', | ||
'THIS_IS_UNDEFINED', | ||
'INVALID_ANNOTATION', | ||
'UNUSED_EXTERNAL_IMPORT' | ||
]); | ||
function getDefaultExportFromCjs (x) { | ||
@@ -127,2 +91,55 @@ return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; | ||
const availableExtensions = new Set([ | ||
'js', | ||
'cjs', | ||
'mjs', | ||
'jsx', | ||
'ts', | ||
'tsx', | ||
'cts', | ||
'mts' | ||
]); | ||
const nodeResolveExtensions = [ | ||
'.mjs', | ||
'.cjs', | ||
'.js', | ||
'.json', | ||
'.node', | ||
'.jsx' | ||
]; | ||
const suffixedExportConventions = new Set([ | ||
'react-server', | ||
'react-native', | ||
'edge-light', | ||
'development', | ||
'production' | ||
]); | ||
const availableESExtensionsRegex = /\.(m|c)?[jt]sx?$/; | ||
const SRC = 'src'; | ||
const dtsExtensionsMap = { | ||
js: 'd.ts', | ||
cjs: 'd.cts', | ||
mjs: 'd.mts' | ||
}; | ||
const disabledWarnings = new Set([ | ||
'MIXED_EXPORTS', | ||
'PREFER_NAMED_EXPORTS', | ||
'UNRESOLVED_IMPORT', | ||
'THIS_IS_UNDEFINED', | ||
'INVALID_ANNOTATION', | ||
'UNUSED_EXTERNAL_IMPORT' | ||
]); | ||
const tsExtensions = new Set([ | ||
'ts', | ||
'tsx', | ||
'cts', | ||
'mts' | ||
]); | ||
const DEFAULT_TS_CONFIG = { | ||
compilerOptions: { | ||
module: 'ESNext', | ||
moduleResolution: 'bundler' | ||
} | ||
}; | ||
const defaultColorFn = (text)=>text; | ||
@@ -161,11 +178,20 @@ function color(prefixColor) { | ||
} | ||
function isTypescriptFile(filename) { | ||
const ext = path__default.default.extname(filename).slice(1); | ||
return tsExtensions.has(ext); | ||
} | ||
function fileExists(filePath) { | ||
return fs__default.default.existsSync(filePath); | ||
} | ||
// . -> pkg name | ||
// ./lite -> <pkg name>/lite | ||
function getExportPath(pkg, cwd, exportName) { | ||
const name = pkg.name || path__default.default.basename(cwd); | ||
if (exportName === '.' || !exportName) return name; | ||
return path__default.default.join(name, exportName); | ||
async function removeDir(dirPath) { | ||
try { | ||
const dirStat = await fsp__default.default.stat(dirPath); | ||
if (dirStat.isDirectory()) { | ||
await rimraf.rimraf(dirPath); | ||
} | ||
} catch (err) { | ||
if (err.code !== 'ENOENT') { | ||
throw err; | ||
} | ||
} | ||
} | ||
@@ -199,3 +225,3 @@ const isNotNull = (n)=>Boolean(n); | ||
// $binary represents `pkg.bin` | ||
if (availableExportConventions.has(exportType) && exportType !== '$binary') { | ||
if (suffixedExportConventions.has(exportType) && exportType !== '$binary') { | ||
const filename = await findSourceEntryFile(cwd, exportPath, exportType, ext); | ||
@@ -216,3 +242,2 @@ if (filename) return filename; | ||
const hasAvailableExtension = (filename)=>availableExtensions.has(path__default.default.extname(filename).slice(1)); | ||
const hasCjsExtension = (filename)=>path__default.default.extname(filename) === '.cjs'; | ||
// TODO: add unit test | ||
@@ -259,10 +284,2 @@ const baseNameWithoutExtension = (filename)=>path__default.default.basename(filename, path__default.default.extname(filename)); | ||
function minifyCSS(content) { | ||
return content.replace(/\/\*[\s\S]*?\*\/|([^:]|^)\/\/.*$|(?:^|\s)(\s+)|\s*([\{\};,:])\s*|\s+(!)\s+/g, (match, p1, p2, p3, p4)=>{ | ||
if (p1) return p1 === ' ' ? '' : p1; | ||
if (p2) return ' '; | ||
if (p3) return p3; | ||
if (p4) return '!'; | ||
}); | ||
} | ||
const helpers = { | ||
@@ -295,2 +312,6 @@ cssImport: { | ||
}; | ||
const cleanCssInstance = new CleanCSS__default.default({}); | ||
function minify(code) { | ||
return cleanCssInstance.minify(code).styles; | ||
} | ||
function inlineCss(options) { | ||
@@ -308,3 +329,3 @@ const cssIds = new Set(); | ||
if (options.skip) return ''; | ||
const cssCode = minifyCSS(code); | ||
const cssCode = minify(code); | ||
cssIds.add(id); | ||
@@ -318,3 +339,3 @@ return { | ||
}, | ||
renderChunk (code, options) { | ||
renderChunk (code) { | ||
const dependenciesIds = this.getModuleIds(); | ||
@@ -442,2 +463,14 @@ let foundCss = false; | ||
} | ||
const getFirstExportPath = (fullExportCondition)=>{ | ||
// Handle all export cond { <require|import|default>: ... } | ||
if (typeof fullExportCondition === 'object') { | ||
for (const key of Object.keys(fullExportCondition)){ | ||
if (key.startsWith('.') || key === 'types') { | ||
continue; | ||
} | ||
return fullExportCondition[key]; | ||
} | ||
} | ||
return fullExportCondition; | ||
}; | ||
function findExport(exportPath, exportCondition, paths, packageType, currentPath) { | ||
@@ -454,2 +487,3 @@ // Skip `types` field, it cannot be the entry point | ||
} else { | ||
const exportJsBundlePath = getFirstExportPath(fullExportCondition); | ||
// exportPath is exportType, import, require, ... | ||
@@ -459,3 +493,3 @@ // merge to currentPath | ||
...paths[currentPath], | ||
[exportPath]: fullExportCondition.default | ||
[exportPath]: exportJsBundlePath | ||
}; | ||
@@ -562,6 +596,6 @@ } | ||
* pkg.main and pkg.module will be added to ['.'] if exists | ||
*/ function getExportPaths(pkg, pkgType, resolvedWildcardExports) { | ||
*/ function getExportPaths(pkg, resolvedWildcardExports) { | ||
var _pathsMap_; | ||
let pathsMap = {}; | ||
const packageType = pkgType != null ? pkgType : getPackageType(pkg); | ||
const packageType = getPackageType(pkg); | ||
const isEsmPackage = isESModulePackage(packageType); | ||
@@ -576,5 +610,2 @@ const exportsConditions = resolvedWildcardExports != null ? resolvedWildcardExports : pkg.exports; | ||
} | ||
if (isEsmPackage && pkg.main && hasCjsExtension(pkg.main)) { | ||
exit('Cannot export main field with .cjs extension in ESM package, only .mjs and .js extensions are allowed'); | ||
} | ||
// main export '.' from main/module/typings | ||
@@ -687,3 +718,4 @@ const defaultMainExport = constructFullExportCondition({ | ||
}; | ||
function getBuildEnv(envs) { | ||
// return { 'process.env.<key>': '<value>' } | ||
function getBuildEnv(envs, exportConditions) { | ||
if (!envs.includes('NODE_ENV')) { | ||
@@ -699,6 +731,13 @@ envs.push('NODE_ENV'); | ||
}, {}); | ||
// For development and production convention, we override the NODE_ENV value | ||
const exportConditionNames = new Set(Object.keys(exportConditions)); | ||
if (exportConditionNames.has('development')) { | ||
envVars['process.env.NODE_ENV'] = JSON.stringify('development'); | ||
} else if (exportConditionNames.has('production')) { | ||
envVars['process.env.NODE_ENV'] = JSON.stringify('production'); | ||
} | ||
return envVars; | ||
} | ||
/** | ||
* return { | ||
* return { | ||
* <absolute source path>: <pkg>/<export> | ||
@@ -733,2 +772,3 @@ * } | ||
} | ||
const envValues = getBuildEnv(options.env || [], exportCondition.export); | ||
const { useTypeScript } = buildContext; | ||
@@ -816,3 +856,3 @@ const { runtime, target: jscTarget, minify: shouldMinify } = options; | ||
replace__default.default({ | ||
values: getBuildEnv(options.env || []), | ||
values: envValues, | ||
preventAssignment: true | ||
@@ -982,2 +1022,38 @@ }), | ||
} | ||
async function collectEntry(// export type, e.g. react-server, edge-light those special cases required suffix | ||
exportType, options) { | ||
const { cwd, pkg, entries, entryPath, exportCondRef, entryExport } = options; | ||
let exportCondForType = { | ||
...exportCondRef | ||
}; | ||
// Special cases of export type, only pass down the exportPaths for the type | ||
if (suffixedExportConventions.has(exportType)) { | ||
exportCondForType = { | ||
[exportType]: exportCondRef[exportType] | ||
}; | ||
// Basic export type, pass down the exportPaths with erasing the special ones | ||
} else { | ||
for (const exportType of suffixedExportConventions){ | ||
delete exportCondForType[exportType]; | ||
} | ||
} | ||
let source = entryPath; | ||
if (source) { | ||
source = resolveSourceFile(cwd, source); | ||
} else { | ||
source = await getSourcePathFromExportPath(cwd, entryExport, exportType); | ||
} | ||
if (!source) { | ||
return; | ||
} | ||
const exportCondition = { | ||
source, | ||
name: entryExport, | ||
export: exportCondForType | ||
}; | ||
const nameWithExportPath = pkg.name ? path__default.default.join(pkg.name, exportCondition.name) : exportCondition.name; | ||
const needsDelimiter = !nameWithExportPath.endsWith('.') && exportType; | ||
const entryImportPath = nameWithExportPath + (needsDelimiter ? '.' : '') + exportType; | ||
entries[entryImportPath] = exportCondition; | ||
} | ||
/* | ||
@@ -989,38 +1065,2 @@ * build configs for each entry from package exports | ||
const entries = {}; | ||
async function collectEntry(// export type, e.g. react-server, edge-light those special cases required suffix | ||
exportType, exportCondRef, // export name, e.g. ./<export-path> in exports field of package.json | ||
entryExport) { | ||
let exportCondForType = { | ||
...exportCondRef | ||
}; | ||
// Special cases of export type, only pass down the exportPaths for the type | ||
if (availableExportConventions.has(exportType)) { | ||
exportCondForType = { | ||
[exportType]: exportCondRef[exportType] | ||
}; | ||
// Basic export type, pass down the exportPaths with erasing the special ones | ||
} else { | ||
for (const exportType of availableExportConventions){ | ||
delete exportCondForType[exportType]; | ||
} | ||
} | ||
let source = entryPath; | ||
if (source) { | ||
source = resolveSourceFile(cwd, source); | ||
} else { | ||
source = await getSourcePathFromExportPath(cwd, entryExport, exportType); | ||
} | ||
if (!source) { | ||
return undefined; | ||
} | ||
const exportCondition = { | ||
source, | ||
name: entryExport, | ||
export: exportCondForType | ||
}; | ||
const nameWithExportPath = pkg.name ? path__default.default.join(pkg.name, exportCondition.name) : exportCondition.name; | ||
const needsDelimiter = !nameWithExportPath.endsWith('.') && exportType; | ||
const entryImportPath = nameWithExportPath + (needsDelimiter ? '.' : '') + exportType; | ||
entries[entryImportPath] = exportCondition; | ||
} | ||
const binaryExports = pkg.bin; | ||
@@ -1061,7 +1101,15 @@ if (binaryExports) { | ||
const exportCond = exportPaths[entryExport]; | ||
const collectEntryOptions = { | ||
cwd, | ||
pkg, | ||
entries, | ||
entryPath, | ||
exportCondRef: exportCond, | ||
entryExport | ||
}; | ||
if (entryExport.startsWith('.')) { | ||
await collectEntry('', exportCond, entryExport); | ||
for (const exportType of availableExportConventions){ | ||
if (exportCond[exportType]) { | ||
await collectEntry(exportType, exportCond, entryExport); | ||
await collectEntry('', collectEntryOptions); | ||
for (const exportCondType of suffixedExportConventions){ | ||
if (exportCond[exportCondType]) { | ||
await collectEntry(exportCondType, collectEntryOptions); | ||
} | ||
@@ -1230,2 +1278,6 @@ } | ||
const stats = sizeCollector.getSizeStats(); | ||
if (stats.size === 0) { | ||
logger.warn('No build info can be logged'); | ||
return; | ||
} | ||
const allFileNameLengths = Array.from(stats.values()).flat(1).map(([filename])=>filename.length); | ||
@@ -1340,8 +1392,8 @@ const maxFilenameLength = Math.max(...allFileNameLengths); | ||
const packageType = getPackageType(pkg); | ||
const exportPaths = getExportPaths(pkg, packageType, resolvedWildcardExports); | ||
const exportPaths = getExportPaths(pkg, resolvedWildcardExports); | ||
const isMultiEntries = hasMultiEntryExport(exportPaths) // exportPathsLength > 1 | ||
; | ||
const hasBin = Boolean(pkg.bin); | ||
const tsConfig = await resolveTsConfig(cwd); | ||
const hasTsConfig = Boolean(tsConfig == null ? void 0 : tsConfig.tsConfigPath); | ||
let tsConfig = await resolveTsConfig(cwd); | ||
let hasTsConfig = Boolean(tsConfig == null ? void 0 : tsConfig.tsConfigPath); | ||
const defaultTsOptions = { | ||
@@ -1357,2 +1409,3 @@ tsConfigPath: tsConfig == null ? void 0 : tsConfig.tsConfigPath, | ||
} | ||
// Handle CLI input | ||
if (entryPath) { | ||
@@ -1375,7 +1428,6 @@ let mainEntryPath; | ||
} | ||
const bundleOrWatch = (rollupConfig)=>{ | ||
const { input, exportName } = rollupConfig; | ||
const exportPath = getExportPath(pkg, cwd, exportName); | ||
// Log original entry file relative path | ||
typeof input.input === 'string' ? path.relative(cwd, input.input) : exportPath; | ||
const bundleOrWatch = async (rollupConfig)=>{ | ||
if (options.clean) { | ||
await removeOutputDir(rollupConfig.output); | ||
} | ||
if (options.watch) { | ||
@@ -1403,2 +1455,10 @@ return Promise.resolve(runWatch(rollupConfig)); | ||
const entries = await collectEntries(pkg, entryPath, exportPaths, cwd); | ||
const hasTypeScriptFiles = Object.values(entries).some((entry)=>isTypescriptFile(entry.source)); | ||
if (hasTypeScriptFiles && !hasTsConfig) { | ||
const tsConfigPath = path.resolve(cwd, 'tsconfig.json'); | ||
defaultTsOptions.tsConfigPath = tsConfigPath; | ||
await fsp__default.default.writeFile(tsConfigPath, JSON.stringify(DEFAULT_TS_CONFIG, null, 2), 'utf-8'); | ||
logger.log(`Detected using TypeScript but tsconfig.json is missing, created a ${pc.blue('tsconfig.json')} for you.`); | ||
hasTsConfig = true; | ||
} | ||
const sizeCollector = createOutputState({ | ||
@@ -1433,3 +1493,3 @@ entries | ||
} | ||
function runWatch({ input, output }, metadata) { | ||
function runWatch({ input, output }) { | ||
const watchOptions = [ | ||
@@ -1468,2 +1528,8 @@ { | ||
} | ||
async function removeOutputDir(output) { | ||
const dirs = new Set(output.map(({ dir })=>dir)); | ||
for (const dir of dirs){ | ||
if (dir) await removeDir(dir); | ||
} | ||
} | ||
function runBundle({ input, output }) { | ||
@@ -1470,0 +1536,0 @@ return rollup.rollup(input).then((bundle)=>{ |
{ | ||
"name": "bunchee", | ||
"version": "4.3.4", | ||
"version": "4.4.0", | ||
"description": "zero config bundler for js/ts/jsx libraries", | ||
@@ -60,4 +60,5 @@ "bin": "./dist/bin/cli.js", | ||
"arg": "^5.0.2", | ||
"clean-css": "^5.3.3", | ||
"pretty-bytes": "^5.6.0", | ||
"publint": "~0.2.7", | ||
"rimraf": "^5.0.5", | ||
"rollup": "^4.9.4", | ||
@@ -84,2 +85,3 @@ "rollup-plugin-dts": "^6.1.0", | ||
"@swc/types": "^0.1.5", | ||
"@types/clean-css": "^4.2.11", | ||
"@types/jest": "29.0.0", | ||
@@ -111,5 +113,9 @@ "@types/node": "^20.4.1", | ||
] | ||
} | ||
}, | ||
"testPathIgnorePatterns": [ | ||
"/node_modules/", | ||
"<rootDir>/test/integration/.*/*src" | ||
] | ||
}, | ||
"packageManager": "pnpm@8.8.0" | ||
} |
@@ -67,3 +67,3 @@ # bunchee | ||
"import": "./dist/es/index.mjs", | ||
"require": "./dist/cjs/index.cjs" | ||
"require": "./dist/cjs/index.js" | ||
}, | ||
@@ -92,4 +92,4 @@ "scripts": { | ||
"require": { | ||
"types": "./dist/cjs/index.d.cts", | ||
"default": "./dist/cjs/index.cjs" | ||
"types": "./dist/cjs/index.d.ts", | ||
"default": "./dist/cjs/index.js" | ||
} | ||
@@ -112,3 +112,3 @@ }, | ||
"files": ["dist"], | ||
"main": "./dist/cjs/index.cjs", | ||
"main": "./dist/cjs/index.js", | ||
"module": "./dist/es/index.mjs", | ||
@@ -118,4 +118,4 @@ "types": "./dist/cjs/index.d.ts", | ||
"import": { | ||
"types": "./dist/es/index.d.mts", | ||
"default": "./dist/es/index.mjs" | ||
"types": "./dist/es/index.d.ts", | ||
"default": "./dist/es/index.js" | ||
}, | ||
@@ -275,2 +275,3 @@ "require": { | ||
- Watch (`-w`): Watch for source file changes. | ||
- No Clean(`--no-clean`): Do not clean the dist folder before building. (default: `false`) | ||
@@ -331,2 +332,17 @@ ```sh | ||
#### Auto Development and Production Mode | ||
`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. | ||
```json | ||
{ | ||
"exports": { | ||
"development": "./dist/index.development.js", | ||
"production": "./dist/index.production.js" | ||
} | ||
} | ||
``` | ||
Then you can use `bunchee` to build the development bundle and production bundle automatically. | ||
### Wildcard Exports | ||
@@ -448,2 +464,3 @@ | ||
cwd: process.cwd(), // string | ||
clean: true, // boolean | ||
}) | ||
@@ -450,0 +467,0 @@ ``` |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
108821
2391
477
2
19
15
+ Addedclean-css@^5.3.3
+ Addedrimraf@^5.0.5
+ Added@isaacs/cliui@8.0.2(transitive)
+ Added@pkgjs/parseargs@0.11.0(transitive)
+ Added@rollup/rollup-android-arm-eabi@4.22.5(transitive)
+ Added@rollup/rollup-android-arm64@4.22.5(transitive)
+ Added@rollup/rollup-darwin-arm64@4.22.5(transitive)
+ Added@rollup/rollup-darwin-x64@4.22.5(transitive)
+ Added@rollup/rollup-linux-arm-gnueabihf@4.22.5(transitive)
+ Added@rollup/rollup-linux-arm-musleabihf@4.22.5(transitive)
+ Added@rollup/rollup-linux-arm64-gnu@4.22.5(transitive)
+ Added@rollup/rollup-linux-arm64-musl@4.22.5(transitive)
+ Added@rollup/rollup-linux-powerpc64le-gnu@4.22.5(transitive)
+ Added@rollup/rollup-linux-riscv64-gnu@4.22.5(transitive)
+ Added@rollup/rollup-linux-s390x-gnu@4.22.5(transitive)
+ Added@rollup/rollup-linux-x64-gnu@4.22.5(transitive)
+ Added@rollup/rollup-linux-x64-musl@4.22.5(transitive)
+ Added@rollup/rollup-win32-arm64-msvc@4.22.5(transitive)
+ Added@rollup/rollup-win32-ia32-msvc@4.22.5(transitive)
+ Added@rollup/rollup-win32-x64-msvc@4.22.5(transitive)
+ Added@swc/types@0.1.12(transitive)
+ Addedansi-regex@5.0.16.1.0(transitive)
+ Addedansi-styles@4.3.06.2.1(transitive)
+ Addedclean-css@5.3.3(transitive)
+ Addedcolor-convert@2.0.1(transitive)
+ Addedcolor-name@1.1.4(transitive)
+ Addedcross-spawn@7.0.3(transitive)
+ Addedeastasianwidth@0.2.0(transitive)
+ Addedemoji-regex@8.0.09.2.2(transitive)
+ Addedforeground-child@3.3.0(transitive)
+ Addedglob@10.4.5(transitive)
+ Addedis-fullwidth-code-point@3.0.0(transitive)
+ Addedisexe@2.0.0(transitive)
+ Addedjackspeak@3.4.3(transitive)
+ Addedlru-cache@10.4.3(transitive)
+ Addedminimatch@9.0.5(transitive)
+ Addedminipass@7.1.2(transitive)
+ Addedpackage-json-from-dist@1.0.1(transitive)
+ Addedpath-key@3.1.1(transitive)
+ Addedpath-scurry@1.11.1(transitive)
+ Addedrimraf@5.0.10(transitive)
+ Addedrollup@4.22.5(transitive)
+ Addedshebang-command@2.0.0(transitive)
+ Addedshebang-regex@3.0.0(transitive)
+ Addedsignal-exit@4.1.0(transitive)
+ Addedsource-map@0.6.1(transitive)
+ Addedstring-width@4.2.35.1.2(transitive)
+ Addedstrip-ansi@6.0.17.1.0(transitive)
+ Addedwhich@2.0.2(transitive)
+ Addedwrap-ansi@7.0.08.1.0(transitive)
- Removedpublint@~0.2.7
- Removed@rollup/rollup-android-arm-eabi@4.24.0(transitive)
- Removed@rollup/rollup-android-arm64@4.24.0(transitive)
- Removed@rollup/rollup-darwin-arm64@4.24.0(transitive)
- Removed@rollup/rollup-darwin-x64@4.24.0(transitive)
- Removed@rollup/rollup-linux-arm-gnueabihf@4.24.0(transitive)
- Removed@rollup/rollup-linux-arm-musleabihf@4.24.0(transitive)
- Removed@rollup/rollup-linux-arm64-gnu@4.24.0(transitive)
- Removed@rollup/rollup-linux-arm64-musl@4.24.0(transitive)
- Removed@rollup/rollup-linux-powerpc64le-gnu@4.24.0(transitive)
- Removed@rollup/rollup-linux-riscv64-gnu@4.24.0(transitive)
- Removed@rollup/rollup-linux-s390x-gnu@4.24.0(transitive)
- Removed@rollup/rollup-linux-x64-gnu@4.24.0(transitive)
- Removed@rollup/rollup-linux-x64-musl@4.24.0(transitive)
- Removed@rollup/rollup-win32-arm64-msvc@4.24.0(transitive)
- Removed@rollup/rollup-win32-ia32-msvc@4.24.0(transitive)
- Removed@rollup/rollup-win32-x64-msvc@4.24.0(transitive)
- Removed@swc/types@0.1.13(transitive)
- Removedignore-walk@5.0.1(transitive)
- Removedmri@1.2.0(transitive)
- Removednpm-bundled@2.0.1(transitive)
- Removednpm-normalize-package-bin@2.0.0(transitive)
- Removednpm-packlist@5.1.3(transitive)
- Removedpublint@0.2.11(transitive)
- Removedrollup@4.24.0(transitive)
- Removedsade@1.8.1(transitive)