tochibuild
Version:
An extremely fast JavaScript/Typescript and CSS bundler with minimal configuration.
11 lines (10 loc) • 16.2 kB
JavaScript
import{a,b as _,c as E,d as Q,e as T,f as Y,g as Z,h as R}from"./chunk-6PP37QSZ.mjs";import Oe from"node:fs";import je from"node:path";import v from"chalk";import ve from"cac";import{build as Le}from"tsup";var H={name:"tochibuild",version:"3.0.1",description:"An extremely fast JavaScript/Typescript and CSS bundler with minimal configuration.",repository:"https://github.com/tochiResources/project/tree/main/packages/build/tochibuild.git",license:"MIT",keywords:["bundler","build","typescript","javascript","tsup","esbuild","glob","publish","lifecycle","hooks","cli","node","tochi","tochiResources"],bin:"./dist/cli.mjs",scripts:{dev:"tsx cli.ts"},dependencies:{"@npmcli/arborist":"^9.1.1","bundle-require":"5.1.0",cac:"^6.7.14",chalk:"^5.4.1","cross-spawn":"^7.0.6",deepmerge:"^4.3.1","fast-glob":"^3.3.3",flat:"^6.0.1",joycon:"3.1.1","npm-packlist":"^10.0.0","strip-json-comments":"5.0.1",tar:"^7.4.3",tsup:"8.4.0"},devDependencies:{"@types/cross-spawn":"^6.0.6","@types/node":"^22.15.17",tsx:"^4.19.4",typescript:"^5.8.3"},files:["dist"],engines:{node:">=18.17.0"}};function A(e,r){return r.command("[...files]","Bundle files",{ignoreOptionDefaultValue:!0}).option("--entry.* <file>","Use a key-value pair as entry files").option("-d, --out-dir <dir>","Output directory",{default:"dist"}).option("--format <format>",'Bundle format, "cjs", "iife", "esm"',{default:"cjs"}).option("--minify [terser]","Minify bundle").option("--minify-whitespace","Minify whitespace").option("--minify-identifiers","Minify identifiers").option("--minify-syntax","Minify syntax").option("--keep-names","Keep original function and class names in minified code").option("--target <target>",'Bundle target, "es20XX" or "esnext"',{default:"es2017"}).option("--legacy-output","Output different formats to different folder instead of using different extensions").option("--dts [entry]","Generate declaration file").option("--dts-resolve","Resolve externals types used for d.ts files").option("--dts-only","Emit declaration files only").option("--experimental-dts [entry]","Generate declaration file (experimental)").option("--sourcemap [inline]","Generate external sourcemap, or inline source: --sourcemap inline").option("--watch [path]",'Watch mode, if path is not specified, it watches the current folder ".". Repeat "--watch" for more than one path').option("--ignore-watch <path>","Ignore custom paths in watch mode").option("--onSuccess <command>","Execute command after successful build, specially useful for watch mode").option("--env.* <value>","Define compile-time env variables").option("--inject <file>","Replace a global variable with an import from another file").option("--define.* <value>","Define compile-time constants").option("--external <name>","Mark specific packages / package.json (dependencies and peerDependencies) as external").option("--global-name <name>","Global variable name for iife format").option("--jsxFactory <jsxFactory>","Name of JSX factory function",{default:"React.createElement"}).option("--jsxFragment <jsxFragment>","Name of JSX fragment function",{default:"React.Fragment"}).option("--replaceNodeEnv","Replace process.env.NODE_ENV").option("--no-splitting","Disable code splitting").option("--clean","Clean output directory").option("--silent",'Suppress non-error logs (excluding "onSuccess" process output)').option("--pure <express>","Mark specific expressions as pure").option("--metafile","Emit esbuild metafile (a JSON file)").option("--platform <platform>","Target platform",{default:"node"}).option("--loader <ext=loader>","Specify the loader for a file extension").option("--tsconfig <filename>","Use a custom tsconfig").option("--config <filename>","Use a custom config file").option("--no-config","Disable config file").option("--shims","Enable cjs and esm shims").option("--inject-style","Inject style tag to document head").option("--treeshake [strategy]",'Using Rollup for treeshaking instead, "recommended" or "smallest" or "safest"').option("--publicDir [dir]","Copy public directory to output directory").option("--killSignal <signal>",'Signal to kill child process, "SIGTERM" or "SIGKILL"').option("--cjsInterop","Enable cjs interop")}function F(e,r){r.command("config","Generate config files").option("--ext <string>","The file extension to use (excluding the dot, defaults to '.ts')",{default:".ts"}).option("-f, --filename <string>","The file name to use (defaults to tochibuild.config)",{default:"tochibuild.config"}).option("-o, --overwrite","Overwrite existing config file",{default:!1}).option("--outDir <string>","Output directory paths to create the config in",{default:["."],type:[]}).action(t=>R.generateConfig(e,t,!1,!0))}import ke from"node:path";import S from"chalk";import N from"node:fs";import C from"node:path";import P from"chalk";import ee from"joycon";import{bundleRequire as de}from"bundle-require";import ge from"strip-json-comments";import M from"chalk";import{flatten as pe}from"flat";function J(e){return Array.isArray(e)?e:e.split(",")}function ue(e){return e.startsWith("\\\\?\\")?e:e.replace(/\\/g,"/")}async function V(e,r,t,o,n){let i={},l=t.config===!1;if(Object.assign(i,{...t}),!i.entry&&r.length>0&&(i.entry=r.map(ue)),t.format){let c=J(t.format);i.format=c}if(t.external){let c=J(t.external);i.external=c}if(t.target&&(i.target=t.target.includes(",")?t.target.split(","):t.target),(t.dts||t.dtsResolve||t.dtsOnly)&&(i.dts={},typeof t.dts=="string"&&(i.dts.entry=t.dts),t.dtsResolve&&(i.dts.resolve=t.dtsResolve),t.dtsOnly&&(i.dts.only=!0)),t.inject){let c=J(t.inject);i.inject=c}if(t.define){let c=pe(t.define);i.define=c}if(t.loader){let c=J(t.loader);i.loader=c.reduce((y,u)=>{let p=u.split("=");return{...y,[p[0]]:p[1]}},{})}let s=!l&&o?await Z.mergeBuildOptionsAsync(o,{execute:!0,overrideOptions:i},!1,n):i,f=c=>Array.isArray(c)?c.length>0:Object.keys(c||{}).length>0;return(Array.isArray(s)?!s.some(c=>f(c.entry)):!f(s.entry))?(a.custom("error",`${M.red("No input files, try")} '${M.magenta(e)} ${M.gray("[...files]")}' ${M.red("instead")}`),n&&process.exit(1),[]):s}var k=process.cwd(),G=new ee,te=async e=>{try{return me(await N.promises.readFile(e,"utf8"))}catch(r){throw r instanceof Error?new Error(`Failed to parse ${C.relative(k,e)}: ${r.message}`):r}};function me(e){try{return new Function(`return ${ge(e).trim()}`)()}catch{return{}}}var ye={test:/\.json$/,load(e){return te(e)}};G.addLoader(ye);async function he(e){let r=new ee,t=await r.resolve({files:e?[e]:["tochibuild.config.ts","tochibuild.config.cts","tochibuild.config.mts","tochibuild.config.js","tochibuild.config.cjs","tochibuild.config.mjs","tochibuild.config.json","package.json"],cwd:k,stopDir:C.parse(k).root,packageKey:"tochibuild"}),o=await r.resolve({files:e?[e]:["tsup.config.ts","tsup.config.cts","tsup.config.mts","tsup.config.js","tsup.config.cjs","tsup.config.mjs","tsup.config.json","package.json"],cwd:k,stopDir:C.parse(k).root,packageKey:"tsup"}),n=t||o;if(n){if(n.endsWith(".json")){let f=await te(n);return n.endsWith("package.json")&&(f=f.tochibuild||f.tsup),f?{path:n,data:f}:{}}let i=await de({filepath:n}),l=i.mod.tochibuild||i.mod.tsup||i.mod.default||i.mod,s=typeof l=="function"?await l():await l;return{path:n,data:s}}return{}}async function D(e=!1){return await O(["package.json"],e)}async function O(e,r=!1){r&&G.clearCache();let t=await G.load(e,k,C.dirname(k));return{...t,data:t.data||{}}}async function be(e,r,t,o,n){let i=o?process.argv.slice(2):[],l=o?i.includes("--config"):!1,s=o?t.config===!1:!1,f=[...[".ts",".js",".cjs",".json"].map(x=>C.join(k,`tochibuild.config${x}`)),...[".ts",".js",".cjs",".json"].map(x=>C.join(k,`tsup.config${x}`))],c=n??await D(!0),y=c.data?.tochibuild,u=c.data?.tsup,p=y||u,h=!!Object.keys(p||{}).length,g=f.find(x=>N.existsSync(x)),d=h||!!g,m=g?C.relative(k,g).replace(/\\/g,"/"):void 0,b;if(!s&&g&&!l)b=g,a.log(`using existing configuration file: ${P.gray(m)}`);else if(!s&&!g&&l){if(b=i[i.indexOf("--config")+1],!N.existsSync(b)){a.error(void 0,`config file '${b}' does not exist`),a.info(`try running '${P.magenta(e)} ${P.blue("config")} ${P.gray("-h")}' to get help on how to generate a config file`);return}a.log(`using configuration file: ${P.gray(b)}`)}else if(!s&&!d&&!l){a.error(void 0,"no configuration file found"),a.info(`try running '${P.magenta(e)} ${P.blue("config")} ${P.gray("-h")}' to get help on how to generate a config file`);return}let le=await(async()=>{if(p)return p;if(!s&&(g||b))return(await he(g||b)).data})(),B=await V(e,r,t,le,o).catch(x=>a.error(void 0,x?.message));if(B)return Array.isArray(B)?B:[B]}var oe=be,ie=async(e,r)=>{let t=r||(await D(!0)).data;if(!e)return t;if(typeof e=="string")return(await O([e],!0)).data;if(typeof e=="function")return e(t);if(typeof e=="object"){let o=e,n=t;return o.path&&(n=(await O([o.path],!0)).data),typeof o.data=="function"?o.data(n):typeof o.data=="object"&&o.data!==null?{...n,...o.data}:{...n,...e}}return t};function W(e,r){r.command("pack","Create a tarball (.tgz file) of the package").option("--dir <string>","Path to the original package directory (relative/absolute)",{default:"."}).option("-p, --pkg <string>","Custom path to package.json (relative/absolute)",{default:"package.json"}).option("-o, --out <string>","Output tarball path (relative/absolute)",{default:"tochibuild.package.tgz"}).action(async t=>{let o={...t,dir:t.dir||ke.relative(process.cwd(),".")||"."};o["--"]&&delete o["--"],a.info(`creating tarball with options:
${Object.entries(o).map(([s,f])=>`- ${s}: ${S.gray(f)}`).join(`
`)}`);let n;o.pkg&&o.pkg!=="package.json"&&(a.info(`loading custom package.json from ${S.gray(o.pkg)}`),n=await O([o.pkg],!0).then(s=>s.data));let i=await T({packageDir:process.cwd(),packageJsonData:n}),l=i.fileList.map(s=>`- ${S.gray(s)}`).join(`
`);a.success(`successfully created tarball from ${i.fileList.length} files:
${l}`),a.success(`tarball created at ${S.gray(i.tarballPath)}`)})}function U(e,r){r.command("merge <outFile> <...files>","Merge the contents of all files into a single file").action(async(t,o)=>{try{await Y(o,t)}catch(n){a.error(void 0,n?.message)}})}var we=[F,W,U],ne=we;import X from"chalk";import xe from"cross-spawn";import j from"chalk";function re(e,r=[],t){return new Promise((o,n)=>{let i=xe(e,r,{stdio:"inherit",shell:!0,cwd:process.cwd(),env:process.env,...t});i.on("exit",l=>{l===0?o():n(new Error(`${e} exited with code ${l}`))}),i.on("error",n),process.on("SIGINT",()=>{n(),i.kill("SIGINT")}),process.on("SIGTERM",()=>{n(),i.kill("SIGTERM")})})}async function Pe(e,r,t,o,n){let i=n!=null?` #${n}`:"";if("cli"in e){let l=e.cli.name??r.packageManager,s=e.cli.args;return a.info(`${j.bold(`running hook${i}:`)} ${j.magenta(`${l}`)}${s.length?" ":""}${j.gray(s.join(" "))}`),await re(l,s)}else if("action"in e){let l=e.name||"unnamed";return a.info(`${j.bold(`running hook${i}:`)} ${j.magenta(`${l}`)}`),await e.action(R,t,o)}}var w={cli:re,hook:Pe};import ae from"chalk";async function z(e){let r=e.packageManager||"npm",t=e.command||"deprecate",o=e.args||[];return a.info(`running hook: ${ae.magenta(`${r} ${t}`)}${o.length?" ":""}${ae.gray(o.join(" "))}`),w.cli(r,[t].concat(o))}import $e from"node:fs";import Ce from"node:path";import I from"chalk";async function K(e,r){let t=e.packageManager||"npm",o=e.command||"publish",n=e.args||[];a.info(`running hook: ${I.magenta(`${t} ${o}`)}${n.length?" ":""}${I.gray(n.join(" "))}`);let i="",l="";if(n.length&&typeof n[0]=="string"&&!n[0].startsWith("-")&&n[0].endsWith(".tgz")&&(i=n[0].replace(/\\/g,"/"),l=Ce.relative(process.cwd(),i).replace(/\\/g,"/")),i)a.info(`using custom tarball ${l}`);else{a.info("creating tarball...");let s=await T({packageDir:process.cwd(),packageJsonData:r});i=s.tarballPath.replace(/\\/g,"/"),l=s.tarballRelativePath.replace(/\\/g,"/");let f=s.fileList.map(c=>`- ${I.gray(c)}`).join(`
`);a.success(`successfully created tarball from ${s.fileList.length} files:
${f}`),a.info(`tarball created at ${I.gray(s.tarballRelativePath)}`)}if(!$e.existsSync(i))throw new Error(`tarball not found at ${l}`);return a.info("publishing package from tarball..."),w.cli(t,[o].concat(i).concat(n))}async function $(e,r,t,o){return Array.isArray(e)?await Promise.all(e.map((n,i)=>w.hook(n,r,t,o,i+1))):await w.hook(e,r,t,o,1)}async function q(e,r){let t=e?.tochibuildConfig,o=t?.lifecycle,n=o?.access||"restricted",i=o?.packageManager||"npm",l=o?.registry||"https://registry.npmjs.org/",s=await ie(o?.packageJson,r),f=o?.hooks,c={publish:f?.publish?{access:n,packageManager:i,command:"publish",...f?.publish,args:f?.publish?.args||[]}:void 0,deprecate:f?.deprecate?{access:n,packageManager:i,command:"deprecate",...f?.deprecate,args:f?.deprecate?.args||[]}:void 0,custom:Array.isArray(f?.custom)?f?.custom:[]},y={access:n,packageManager:i,registry:l,packageJson:s,hooks:c},u={beforeBuild:c.custom.filter(p=>p.position==="before.build"),beforePublish:c.custom.filter(p=>p.position==="before.publish"),beforeDeprecate:c.custom.filter(p=>p.position==="before.deprecate"),afterBuild:c.custom.filter(p=>p.position==="after.build"),afterPublish:c.custom.filter(p=>p.position==="after.publish"),afterDeprecate:c.custom.filter(p=>p.position==="after.deprecate")};return{access:n,packageManager:i,registry:l,packageJson:s,hooks:{...c,custom:u},runner:w,runHooks:async p=>new Promise(async(h,g)=>{try{let d=t,m;switch(p){case"publish":if(!c.publish)break;m=K(c.publish,s);break;case"deprecate":if(!c.deprecate)break;m=z(c.deprecate);break;case"custom.before.build":if(!u.beforeBuild.length)break;m=$(u.beforeBuild,y,d);break;case"custom.before.publish":if(!u.beforePublish.length)break;m=$(u.beforePublish,y,d);break;case"custom.before.deprecate":if(!u.beforeDeprecate.length)break;m=$(u.beforeDeprecate,y,d);break;case"custom.after.build":if(!u.afterBuild.length)break;m=$(u.afterBuild,y,d);break;case"custom.after.publish":if(!u.afterPublish.length)break;m=$(u.afterPublish,y,d);break;case"custom.after.deprecate":if(!u.afterDeprecate.length)break;m=$(u.afterDeprecate,y,d);break;default:throw new Error(`Unknown lifecycle hook: ${X.magenta(p)}`)}let b=await m?.then(()=>a.success(`successfully ran lifecycle hook(s): ${X.magenta(p)}`));h(b)}catch(d){throw a.error(void 0,`failed to run lifecycle hook(s) ${X.magenta(p)}:`),d}})}}var L=process.cwd(),se=L.replace(/\\/g,"/").includes("packages/build");a.initialize(L,H.version);async function ce(e){try{let r=ve("tochibuild");for(let o of ne)await o(e,r);A(e,r).action(async(o,n)=>t(o,n)),r.help(),r.version(H.version),r.parse(process.argv,{run:!1}),await r.runMatchedCommand();async function t(o,n){return new Promise(async(i,l)=>{let s;try{let f=n.config===!1,c=await D(!0),y=await oe(e,o,n,!0).catch(u=>{a.error(void 0,u?.message),l()});if(!y)return;a.log(`running build${se||c.data?.name?` for ${v.magenta(se?e:c.data.name)}`:""}...`);for(let u=0;u<y.length;u++){if(s=_(`config.tmp-${Date.now()}.json`),!s)throw new Error("Temp config path is undefined.");let p=je.relative(L,s).replace(/\\/g,"/"),h=y[u];typeof h.config=="string"&&(Oe.existsSync(h.config)||(a.error(void 0,`config file '${h.config}' does not exist`),a.info(`try running '${v.magenta(e)} ${v.blue("config")} ${v.gray("-h")}' to get help on how to generate a config file`),process.exit(1)));let g=await q(h,c.data);await g.runHooks("custom.before.build");let d={...h};if(d["--"]!=null&&delete d["--"],!f&&(d.config!=null&&delete d.config,d.tochibuildConfig!=null&&delete d.tochibuildConfig,s=Q(s,JSON.stringify(d,null,4),{overwrite:!0,fsOptions:{encoding:"utf-8"}}),!s))throw new Error("Failed to create temp config file.");a.debug("options:",`
${Object.entries(d).map(([m,b])=>`- ${m}: ${v.gray(JSON.stringify(b,null,4))}`).join(`
`)}`),await Le({config:f?!1:p,...f?d:{},skipNodeModulesBundle:h.skipNodeModulesBundle??!0,clean:u>0?!1:h.clean}).catch(m=>{a.error(void 0,m?.message),l()}),await g.runHooks("custom.after.build"),await g.runHooks("custom.before.publish"),await g.runHooks("publish"),await g.runHooks("custom.after.publish"),await g.runHooks("custom.before.deprecate"),await g.runHooks("deprecate"),await g.runHooks("custom.after.deprecate"),E(L)}i()}catch(f){a.error(f),E(L),l()}})}}catch(r){a.error(r),process.exit(1)}}ce("tochibuild");