bunchee
Advanced tools
Comparing version 4.1.1 to 4.2.0
@@ -57,3 +57,3 @@ #!/usr/bin/env node | ||
var version = "4.1.1"; | ||
var version = "4.2.0"; | ||
@@ -60,0 +60,0 @@ const helpMessage = ` |
@@ -13,5 +13,5 @@ Object.defineProperty(exports, '__esModule', { value: true }); | ||
var esmShim = require('@rollup/plugin-esm-shim'); | ||
var preserveDirectives = require('rollup-preserve-directives'); | ||
var pluginutils = require('@rollup/pluginutils'); | ||
var prettyBytes = require('pretty-bytes'); | ||
var pluginutils = require('@rollup/pluginutils'); | ||
var preserveDirectives = require('rollup-preserve-directives'); | ||
var module$1 = require('module'); | ||
@@ -27,93 +27,5 @@ | ||
var esmShim__default = /*#__PURE__*/_interopDefault(esmShim); | ||
var preserveDirectives__default = /*#__PURE__*/_interopDefault(preserveDirectives); | ||
var prettyBytes__default = /*#__PURE__*/_interopDefault(prettyBytes); | ||
var preserveDirectives__default = /*#__PURE__*/_interopDefault(preserveDirectives); | ||
const availableExtensions = [ | ||
'js', | ||
'cjs', | ||
'mjs', | ||
'jsx', | ||
'ts', | ||
'tsx', | ||
'cts', | ||
'mts' | ||
]; | ||
const availableExportConventions = [ | ||
'react-server', | ||
'react-native', | ||
'edge-light' | ||
]; | ||
const availableESExtensionsRegex = /\.(m|c)?[jt]sx?$/; | ||
const dtsExtensionRegex = /\.d\.(m|c)?ts$/; | ||
const SRC = 'src'; | ||
const dtsExtensions = { | ||
js: '.d.ts', | ||
cjs: '.d.cts', | ||
mjs: '.d.mts' | ||
}; | ||
const logger = { | ||
log (...arg) { | ||
console.log(' ', ...arg); | ||
}, | ||
warn (...arg) { | ||
console.warn(' ⚠️', ...arg); | ||
}, | ||
error (...arg) { | ||
console.error(' ⨯', ...arg); | ||
}, | ||
info (...arg) { | ||
console.log(' ✓', ...arg); | ||
} | ||
}; | ||
function createChunkSizeCollector() { | ||
const sizes = new Map(); | ||
function addSize(name, size) { | ||
sizes.set(name, size); | ||
} | ||
return { | ||
plugin: (cwd)=>{ | ||
return { | ||
name: 'collect-sizes', | ||
augmentChunkHash () { | ||
// Do nothing, but use the hook to keep the plugin instance alive | ||
}, | ||
renderChunk (code, chunk, options) { | ||
const dir = options.dir || options.file && path__default.default.dirname(options.file); | ||
let fileName = chunk.fileName; | ||
if (dir) { | ||
const filePath = path__default.default.join(dir, fileName); | ||
fileName = filePath.startsWith(cwd) ? path__default.default.relative(cwd, filePath) : filePath; | ||
} | ||
addSize(fileName, code.length); | ||
return null; | ||
} | ||
}; | ||
}, | ||
getSizeStats () { | ||
const sizeStats = []; | ||
sizes.forEach((size, name)=>{ | ||
sizeStats.push([ | ||
name, | ||
prettyBytes__default.default(size), | ||
size | ||
]); | ||
}); | ||
return sizeStats; | ||
} | ||
}; | ||
} | ||
// This can also be passed down as stats from top level | ||
const sizeCollector = createChunkSizeCollector(); | ||
function logSizeStats() { | ||
const stats = sizeCollector.getSizeStats(); | ||
const maxLength = Math.max(...stats.map(([filename])=>filename.length)); | ||
stats.forEach(([filename, prettiedSize])=>{ | ||
const padding = ' '.repeat(maxLength - filename.length); | ||
const action = dtsExtensionRegex.test(filename) ? 'Typed' : 'Built'; | ||
logger.info(`${action} ${filename}${padding} - ${prettiedSize}`); | ||
}); | ||
} | ||
function minifyCSS(content) { | ||
@@ -211,2 +123,27 @@ return content.replace(/\/\*[\s\S]*?\*\/|([^:]|^)\/\/.*$|(?:^|\s)(\s+)|\s*([\{\};,:])\s*|\s+(!)\s+/g, (match, p1, p2, p3, p4)=>{ | ||
// Alias entries to import path | ||
// e.g. | ||
// For a resolved file, if it's one of the entries, | ||
// aliases it as export path, such as <absolute file> -> <pkg>/<export path> | ||
function aliasEntries({ entries }) { | ||
return { | ||
name: 'alias', | ||
resolveId: { | ||
async handler (source, importer, options) { | ||
const resolvedId = await this.resolve(source, importer, options); | ||
if (resolvedId != null) { | ||
const aliasedId = entries[resolvedId.id]; | ||
if (aliasedId != null) { | ||
return { | ||
id: aliasedId, | ||
external: true | ||
}; | ||
} | ||
} | ||
return null; | ||
} | ||
} | ||
}; | ||
} | ||
function prependDirectives() { | ||
@@ -237,2 +174,49 @@ return { | ||
const availableExtensions = [ | ||
'js', | ||
'cjs', | ||
'mjs', | ||
'jsx', | ||
'ts', | ||
'tsx', | ||
'cts', | ||
'mts' | ||
]; | ||
const nodeResolveExtensions = [ | ||
'.mjs', | ||
'.cjs', | ||
'.js', | ||
'.json', | ||
'.node', | ||
'.jsx' | ||
]; | ||
const availableExportConventions = [ | ||
'react-server', | ||
'react-native', | ||
'edge-light' | ||
]; | ||
const availableESExtensionsRegex = /\.(m|c)?[jt]sx?$/; | ||
const dtsExtensionRegex = /\.d\.(m|c)?ts$/; | ||
const SRC = 'src'; | ||
const dtsExtensions = { | ||
js: '.d.ts', | ||
cjs: '.d.cts', | ||
mjs: '.d.mts' | ||
}; | ||
const logger = { | ||
log (...arg) { | ||
console.log(' ', ...arg); | ||
}, | ||
warn (...arg) { | ||
console.warn(' ⚠️', ...arg); | ||
}, | ||
error (...arg) { | ||
console.error(' ⨯', ...arg); | ||
}, | ||
info (...arg) { | ||
console.log(' ✓', ...arg); | ||
} | ||
}; | ||
function exit(err) { | ||
@@ -528,4 +512,5 @@ logger.error(err); | ||
} | ||
function isCjsExportName(name, ext) { | ||
return [ | ||
function isCjsExportName(pkg, name, ext) { | ||
const isESModule = isESModulePackage(pkg.type); | ||
return !isESModule && [ | ||
'require', | ||
@@ -535,3 +520,3 @@ 'main', | ||
'default' | ||
].includes(name) || ext === 'cjs'; | ||
].includes(name) && ext !== 'mjs' || ext === 'cjs'; | ||
} | ||
@@ -542,12 +527,12 @@ function getExportConditionDist(pkg, parsedExportCondition, cwd) { | ||
const exportTypes = Object.keys(parsedExportCondition.export); | ||
for (const key of exportTypes){ | ||
if (key === 'types') { | ||
for (const exportType of exportTypes){ | ||
if (exportType === 'types') { | ||
continue; | ||
} | ||
const filePath = parsedExportCondition.export[key]; | ||
const filePath = parsedExportCondition.export[exportType]; | ||
const ext = path.extname(filePath).slice(1); | ||
const relativePath = parsedExportCondition.export[key]; | ||
const relativePath = parsedExportCondition.export[exportType]; | ||
const distFile = getDistPath(relativePath, cwd); | ||
let format = 'esm'; | ||
if (isCjsExportName(key, ext)) { | ||
if (isCjsExportName(pkg, exportType, ext)) { | ||
format = 'cjs'; | ||
@@ -605,3 +590,13 @@ } | ||
} | ||
async function buildInputConfig(entry, pkg, options, cwd, { tsConfigPath, tsCompilerOptions }, dts) { | ||
/** | ||
* return { '<pkg>/<export>': '<absolute source path> } | ||
*/ function getEntriesAlias(entries) { | ||
const alias = {}; | ||
for (const [entryImportPath, exportCondition] of Object.entries(entries)){ | ||
alias[entryImportPath] = exportCondition.source; | ||
} | ||
return alias; | ||
} | ||
async function buildInputConfig(entry, entries, pkg, options, cwd, { tsConfigPath, tsCompilerOptions }, pluginContext, dts) { | ||
const entriesAlias = getEntriesAlias(entries); | ||
const hasNoExternal = options.external === null; | ||
@@ -613,5 +608,9 @@ var _options_external; | ||
pkg.peerDependenciesMeta | ||
].filter((n)=>Boolean(n)).map((o)=>Object.keys(o)).reduce((a, b)=>a.concat(b), []).concat(((_options_external = options.external) != null ? _options_external : []).concat(pkg.name ? [ | ||
pkg.name | ||
] : [])); | ||
].filter((n)=>Boolean(n)).map((o)=>Object.keys(o)).reduce((a, b)=>a.concat(b), []).concat((_options_external = options.external) != null ? _options_external : []); | ||
for (const [exportImportPath, entryFilePath] of Object.entries(entriesAlias)){ | ||
if (entryFilePath !== entry) { | ||
externals.push(exportImportPath); | ||
externals.push(entryFilePath); | ||
} | ||
} | ||
const { useTypescript, runtime, target: jscTarget, minify: shouldMinify } = options; | ||
@@ -643,6 +642,15 @@ const hasSpecifiedTsTarget = Boolean(tsCompilerOptions.target && tsConfigPath); | ||
}; | ||
const sizePlugin = sizeCollector.plugin(cwd); | ||
const sizePlugin = pluginContext.sizeCollector.plugin(cwd); | ||
const reversedAlias = {}; | ||
for (const [key, value] of Object.entries(entriesAlias)){ | ||
if (value !== entry) { | ||
reversedAlias[value] = key; | ||
} | ||
} | ||
// common plugins for both dts and ts assets that need to be processed | ||
const commonPlugins = [ | ||
sizePlugin | ||
sizePlugin, | ||
aliasEntries({ | ||
entries: reversedAlias | ||
}) | ||
]; | ||
@@ -705,10 +713,3 @@ const baseResolvedTsOptions = { | ||
preferBuiltins: runtime === 'node', | ||
extensions: [ | ||
'.mjs', | ||
'.cjs', | ||
'.js', | ||
'.json', | ||
'.node', | ||
'.jsx' | ||
] | ||
extensions: nodeResolveExtensions | ||
}), | ||
@@ -769,6 +770,9 @@ commonjs__default.default({ | ||
const moduleInfo = ctx.getModuleInfo(id); | ||
const moduleMeta = moduleInfo == null ? void 0 : moduleInfo.meta; | ||
if (!moduleInfo || !moduleMeta) { | ||
if (!moduleInfo) { | ||
return; | ||
} | ||
const moduleMeta = moduleInfo.meta; | ||
if (!moduleMeta) { | ||
return; | ||
} | ||
const directives = (moduleMeta.preserveDirectives || { | ||
@@ -818,52 +822,50 @@ directives: [] | ||
} | ||
// build configs for each entry from package exports | ||
async function buildEntryConfig(pkg, entryPath, exportPaths, bundleConfig, cwd, tsOptions, dts) { | ||
async function buildEntryConfig(entries, pkg, exportPaths, bundleConfig, cwd, tsOptions, pluginContext, dts) { | ||
const configs = []; | ||
Object.keys(exportPaths).forEach(async (entryExport)=>{ | ||
const exportCond = exportPaths[entryExport]; | ||
const buildConfigs = [ | ||
createBuildConfig('', exportCond) | ||
]; | ||
// For dts job, only build the default config. | ||
// For assets job, build all configs. | ||
if (!dts) { | ||
for (const exportCondition of Object.values(entries)){ | ||
const rollupConfig = buildConfig(entries, pkg, exportPaths, bundleConfig, exportCondition, cwd, tsOptions, pluginContext, dts); | ||
configs.push(rollupConfig); | ||
} | ||
return await Promise.all(configs); | ||
} | ||
/* | ||
* build configs for each entry from package exports | ||
* | ||
* return { <pkg>/<export>: { input: InputOptions, output: OutputOptions[] } | ||
*/ async function collectEntries(pkg, entryPath, exportPaths, cwd) { | ||
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.includes(exportType)) { | ||
exportCondForType = { | ||
[entryExport]: exportCondRef[exportType] | ||
}; | ||
// Basic export type, pass down the exportPaths with erasing the special ones | ||
} else { | ||
for (const exportType of availableExportConventions){ | ||
if (exportCond[exportType]) { | ||
buildConfigs.push(createBuildConfig(exportType, exportCond)); | ||
} | ||
delete exportCondForType[exportType]; | ||
} | ||
} | ||
async function createBuildConfig(exportType, exportCondRef) { | ||
let exportCondForType = { | ||
...exportCondRef | ||
}; | ||
// Special cases of export type, only pass down the exportPaths for the type | ||
if (availableExportConventions.includes(exportType)) { | ||
exportCondForType = { | ||
[entryExport]: 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 = await getSourcePathFromExportPath(cwd, entryExport, exportType); | ||
} | ||
if (!source) { | ||
return undefined; | ||
} | ||
const exportCondition = { | ||
source, | ||
name: entryExport, | ||
export: exportCondForType | ||
}; | ||
const entry = resolveSourceFile(cwd, source); | ||
const rollupConfig = buildConfig(entry, pkg, exportPaths, bundleConfig, exportCondition, cwd, tsOptions, dts); | ||
return rollupConfig; | ||
let source = entryPath; | ||
if (source) { | ||
source = resolveSourceFile(cwd, source); | ||
} else { | ||
source = await getSourcePathFromExportPath(cwd, entryExport, exportType); | ||
} | ||
configs.push(...buildConfigs); | ||
}); | ||
if (!source) { | ||
return undefined; | ||
} | ||
const exportCondition = { | ||
source, | ||
name: entryExport, | ||
export: exportCondForType | ||
}; | ||
const entryImportPath = path__default.default.join(pkg.name || '', exportCondition.name) + (exportType ? `.${exportType}` : ''); | ||
entries[entryImportPath] = exportCondition; | ||
} | ||
const binaryExports = pkg.bin; | ||
@@ -899,13 +901,22 @@ if (binaryExports) { | ||
const binEntryPath = await resolveSourceFile(cwd, source); | ||
const binEntryConfig = buildConfig(binEntryPath, pkg, binExportPaths, bundleConfig, { | ||
entries[binName] = { | ||
source: binEntryPath, | ||
name: binName, | ||
export: binExportPaths[binName] | ||
}, cwd, tsOptions, dts); | ||
configs.push(binEntryConfig); | ||
}; | ||
} | ||
} | ||
return (await Promise.all(configs)).filter(nonNullable); | ||
const collectEntriesPromises = Object.keys(exportPaths).map(async (entryExport)=>{ | ||
const exportCond = exportPaths[entryExport]; | ||
await collectEntry('', exportCond, entryExport); | ||
for (const exportType of availableExportConventions){ | ||
if (exportCond[exportType]) { | ||
await collectEntry(exportType, exportCond, entryExport); | ||
} | ||
} | ||
}); | ||
await Promise.all(collectEntriesPromises); | ||
return entries; | ||
} | ||
async function buildConfig(entry, pkg, exportPaths, bundleConfig, exportCondition, cwd, tsOptions, dts) { | ||
async function buildConfig(entries, pkg, exportPaths, bundleConfig, exportCondition, cwd, tsOptions, pluginContext, dts) { | ||
const { file } = bundleConfig; | ||
@@ -917,3 +928,3 @@ const useTypescript = Boolean(tsOptions.tsConfigPath); | ||
}; | ||
const inputOptions = await buildInputConfig(entry, pkg, options, cwd, tsOptions, dts); | ||
const inputOptions = await buildInputConfig(exportCondition.source, entries, pkg, options, cwd, tsOptions, pluginContext, dts); | ||
const outputExports = getExportConditionDist(pkg, exportCondition, cwd); | ||
@@ -961,2 +972,68 @@ let outputConfigs = []; | ||
function createChunkSizeCollector({ entries }) { | ||
const sizeStats = new Map(); | ||
function addSize({ fileName, size, sourceFileName, exportPath }) { | ||
if (!sizeStats.has(exportPath)) { | ||
sizeStats.set(exportPath, []); | ||
} | ||
const distFilesStats = sizeStats.get(exportPath); | ||
if (distFilesStats) { | ||
distFilesStats.push([ | ||
fileName, | ||
sourceFileName, | ||
size | ||
]); | ||
} | ||
} | ||
const reversedMapping = new Map(); | ||
Object.entries(entries).forEach(([, entry])=>{ | ||
reversedMapping.set(entry.source, entry.name || '.'); | ||
}); | ||
return { | ||
plugin: (cwd)=>{ | ||
return { | ||
name: 'collect-sizes', | ||
augmentChunkHash () { | ||
// Do nothing, but use the hook to keep the plugin instance alive | ||
}, | ||
renderChunk (code, chunk, options) { | ||
const sourceId = chunk.facadeModuleId || ''; | ||
const dir = options.dir || options.file && path__default.default.dirname(options.file); | ||
let fileName = chunk.fileName; | ||
if (dir) { | ||
const filePath = path__default.default.join(dir, fileName); | ||
fileName = filePath.startsWith(cwd) ? path__default.default.relative(cwd, filePath) : filePath; | ||
} | ||
addSize({ | ||
fileName, | ||
size: code.length, | ||
sourceFileName: sourceId, | ||
exportPath: reversedMapping.get(sourceId) || '.' | ||
}); | ||
return null; | ||
} | ||
}; | ||
}, | ||
getSizeStats () { | ||
return sizeStats; | ||
} | ||
}; | ||
} | ||
function logSizeStats(sizeCollector) { | ||
const stats = sizeCollector.getSizeStats(); | ||
const allFileNameLengths = Array.from(stats.values()).flat(1).map(([filename])=>filename.length); | ||
const maxLength = Math.max(...allFileNameLengths); | ||
[ | ||
...stats.entries() | ||
].sort(([a], [b])=>a.length - b.length).forEach(([, filesList])=>{ | ||
filesList.forEach((item)=>{ | ||
const [filename, , size] = item; | ||
const padding = ' '.repeat(maxLength - filename.length); | ||
const action = dtsExtensionRegex.test(filename) ? 'Typed' : 'Built'; | ||
const prettiedSize = prettyBytes__default.default(size); | ||
logger.info(`${action} ${filename}${padding} - ${prettiedSize}`); | ||
}); | ||
}); | ||
} | ||
let hasLoggedTsWarning = false; | ||
@@ -1126,11 +1203,17 @@ function resolveTypescript(cwd) { | ||
} | ||
let result; | ||
const buildConfigs = await buildEntryConfig(pkg, entryPath, exportPaths, options, cwd, defaultTsOptions, false); | ||
const entries = await collectEntries(pkg, entryPath, exportPaths, cwd); | ||
const sizeCollector = createChunkSizeCollector({ | ||
entries | ||
}); | ||
const pluginContext = { | ||
sizeCollector | ||
}; | ||
const buildConfigs = await buildEntryConfig(entries, pkg, exportPaths, options, cwd, defaultTsOptions, pluginContext, false); | ||
const assetsJobs = buildConfigs.map((rollupConfig)=>bundleOrWatch(rollupConfig)); | ||
const typesJobs = hasTsConfig ? (await buildEntryConfig(pkg, entryPath, exportPaths, options, cwd, defaultTsOptions, true)).map((rollupConfig)=>bundleOrWatch(rollupConfig)) : []; | ||
result = await Promise.all(assetsJobs.concat(typesJobs)); | ||
const typesJobs = hasTsConfig ? (await buildEntryConfig(entries, pkg, exportPaths, options, cwd, defaultTsOptions, pluginContext, true)).map((rollupConfig)=>bundleOrWatch(rollupConfig)) : []; | ||
const result = await Promise.all(assetsJobs.concat(typesJobs)); | ||
if (result.length === 0) { | ||
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'); | ||
} | ||
logSizeStats(); | ||
logSizeStats(sizeCollector); | ||
return result; | ||
@@ -1137,0 +1220,0 @@ } |
{ | ||
"name": "bunchee", | ||
"version": "4.1.1", | ||
"version": "4.2.0", | ||
"description": "zero config bundler for js/ts/jsx libraries", | ||
@@ -50,3 +50,3 @@ "bin": "./dist/bin/cli.js", | ||
"@rollup/plugin-esm-shim": "^0.1.5", | ||
"@rollup/plugin-json": "^6.0.1", | ||
"@rollup/plugin-json": "^6.1.0", | ||
"@rollup/plugin-node-resolve": "^15.2.3", | ||
@@ -60,4 +60,4 @@ "@rollup/plugin-replace": "^5.0.5", | ||
"pretty-bytes": "^5.6.0", | ||
"publint": "~0.2.6", | ||
"rollup": "^4.6.1", | ||
"publint": "~0.2.7", | ||
"rollup": "^4.9.1", | ||
"rollup-plugin-dts": "^6.1.0", | ||
@@ -64,0 +64,0 @@ "rollup-plugin-swc3": "^0.11.0", |
66277
1454
Updated@rollup/plugin-json@^6.1.0
Updatedpublint@~0.2.7
Updatedrollup@^4.9.1