UNPKG

@hypernym/bundler

Version:
170 lines (169 loc) 4.75 kB
#!/usr/bin/env node import { createArgs } from "@hypernym/args"; import process, { cwd } from "node:process"; import { cyan, dim } from "@hypernym/colors"; import { isAbsolute, resolve } from "node:path"; import { exists, read, write } from "@hypernym/utils/fs"; import { build } from "rolldown"; import { build as build$1 } from "../build/index.js"; //#region src/bin/meta.ts const name = `Hyperbundler`; const version = `0.32.3`; //#endregion //#region src/utils/logger.ts const cl = console.log; const separator = `|`; const logger = { info: (...args) => { cl(name, dim(separator), ...args); }, error: (...args) => { cl(); cl(name, dim(separator), ...args); cl(); }, exit: (message) => { cl(); cl(name, dim(separator), message); cl(); return process.exit(); } }; //#endregion //#region src/utils/error.ts function error(err) { logger.error("Something went wrong..."); console.error(err); return process.exit(); } //#endregion //#region src/utils/format-ms.ts function formatMs(ms) { const s = 1e3; const m = s * 60; const h = m * 60; const msAbs = Math.abs(ms); if (msAbs >= h) return `${(ms / h).toFixed(2)}h`; if (msAbs >= m) return `${(ms / m).toFixed(2)}m`; if (msAbs >= s) return `${(ms / s).toFixed(2)}s`; return `${ms}ms`; } //#endregion //#region src/utils/format-bytes.ts function formatBytes(bytes) { const decimals = 2; const units = [ "B", "KB", "MB", "GB", "TB" ]; if (bytes === 0) return `0 B`; const k = 1024; const dm = decimals; const i = Math.floor(Math.log(bytes) / Math.log(k)); return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${units[i]}`; } //#endregion //#region src/config.ts const externals = [ /^node:/, /^@types/, /^@rollup/, /^@rolldown/, /^@hypernym/, /^rollup/, /^rolldown/ ]; //#endregion //#region src/bin/loader.ts async function getTSConfigPath(cwd, filePath = "tsconfig.json") { const tsconfigPath = resolve(cwd, filePath); if (await exists(tsconfigPath)) return tsconfigPath; } async function loadConfig(filePath, defaults) { const cwd = defaults.cwd; const result = await build({ input: resolve(cwd, filePath), write: false, external: (id) => !(isAbsolute(id) || /^(\.|@\/|~\/)/.test(id)), tsconfig: defaults.tsconfig, output: { format: "esm" } }); const tempConfig = resolve(cwd, "node_modules/.hypernym/bundler/config.js"); await write(tempConfig, result.output[0].code); const config = (await import(tempConfig)).default; return { options: { ...defaults, ...config }, path: filePath }; } async function createConfigLoader(args) { const cwdir = args.cwd && args.cwd.trim() !== "" ? resolve(args.cwd) : cwd(); const tsconfig = await getTSConfigPath(cwdir, args.tsconfig); const pkgFile = await read(resolve(cwdir, "package.json")).catch(error); const { dependencies } = JSON.parse(pkgFile); const defaults = { cwd: cwdir, tsconfig, externals: [...Object.keys(dependencies || {}), ...externals], entries: [] }; const warnMessage = `Missing required configuration. To start bundling, add the ${cyan(`'bundler.config.{js,mjs,ts,mts}'`)} file to the project's root.`; if (args.config) { const path = resolve(args.config); if (await exists(path)) return await loadConfig(path, defaults); else return logger.exit(warnMessage); } const configName = "bundler.config"; for (const ext of [ ".ts", ".mts", ".mjs", ".js" ]) { const path = resolve(cwdir, `${configName}${ext}`); if (await exists(path)) return await loadConfig(path, defaults); } return logger.exit(warnMessage); } //#endregion //#region src/bin/builder.ts async function createBuilder(config) { const { options, path: configPath } = config; const { hooks } = options; const cl = console.log; await hooks?.["bundle:start"]?.(options); cl(); logger.info(dim(`v${version}`)); cl("Config", dim(configPath)); cl(); cl("Processing specified entries..."); cl(); await build$1(options).then((stats) => { const entriesLength = options.entries.length; const totalEntries = `${entriesLength} ${entriesLength > 1 ? "entries" : "entry"}`; const filesLength = stats.files.length; const totalFiles = `${stats.files.length} file${filesLength > 1 ? "s" : ""}`; const buildTime = formatMs(stats.buildTime); const buildSize = formatBytes(stats.size); cl(); cl("Stats:", dim(`${totalEntries}, ${totalFiles}, ${buildSize}, ${buildTime}`)); cl(); cl("All entries successfully processed."); cl("Bundle is optimized and ready for production."); cl(); }).catch(error); await hooks?.["bundle:end"]?.(options); } //#endregion //#region src/bin/index.ts async function main() { await createBuilder(await createConfigLoader(createArgs({ alias: { config: "c" } }))); } main().catch(error); //#endregion