Skip to content

Commit 8940e93

Browse files
committed
feat: add build bun cmd
1 parent 2ba76a3 commit 8940e93

File tree

4 files changed

+90
-5
lines changed

4 files changed

+90
-5
lines changed

.changeset/bitter-baboons-dance.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@repo/tools': minor
3+
---
4+
5+
feat: add build bun cmd

packages/tools/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
"empathic": "2.0.0",
2727
"esbuild": "0.25.10",
2828
"memoize-one": "6.0.0",
29+
"p-map": "7.0.3",
2930
"smol-toml": "1.4.2",
3031
"ts-pattern": "5.8.0",
3132
"tsx": "4.20.6",

packages/tools/src/cmd/build.cmd.ts

Lines changed: 75 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { inspect } from 'node:util'
22
import { Command } from '@commander-js/extra-typings'
33
import { validateArg } from '@jahands/cli-tools/args'
44
import * as esbuild from 'esbuild'
5+
import pMap from 'p-map'
56
import { match } from 'ts-pattern'
67
import { z } from 'zod'
78

@@ -11,6 +12,9 @@ import type { CompilerOptions as TSCompilerOptions } from 'typescript'
1112

1213
export const buildCmd = new Command('build').description('Scripts to build things')
1314

15+
type Format = z.infer<typeof Format>
16+
const Format = z.enum(['esm', 'cjs'])
17+
1418
buildCmd
1519
.command('tsc')
1620
.description('Build a library with tsc')
@@ -75,12 +79,9 @@ buildCmd
7579
.string()
7680
.array()
7781
.min(1)
78-
.parse(entryPoints)
82+
.decode(entryPoints)
7983
.map((d) => path.join(rootDir ?? '.', d))
8084

81-
type Format = z.infer<typeof Format>
82-
const Format = z.enum(['esm', 'cjs'])
83-
8485
const formats = Format.array().parse(moduleFormats)
8586

8687
await fs.rm('./dist/', { force: true, recursive: true })
@@ -148,7 +149,7 @@ buildCmd
148149
.action(async (entryPoints) => {
149150
const tsHelpers = await new TSHelpers().init()
150151
const { ts } = tsHelpers
151-
z.string().array().min(1).parse(entryPoints)
152+
z.string().array().min(1).decode(entryPoints)
152153

153154
const tsconfig = ts.readConfigFile('./tsconfig.json', ts.sys.readFile)
154155
if (tsconfig.error) {
@@ -167,3 +168,72 @@ buildCmd
167168
const program = ts.createProgram(entryPoints, tsCompOpts)
168169
program.emit()
169170
})
171+
172+
buildCmd
173+
.command('bun')
174+
.description('Bundle with Bun')
175+
176+
.argument('<entrypoints...>', 'Entrypoint(s) of the app. e.g. src/index.ts')
177+
.option('-f, --format <format...>', 'Formats to use (options: esm, cjs)', ['esm'])
178+
.option('--no-minify', `Don't minify output`)
179+
.option('--no-sourcemap', `Don't include sourcemaps`)
180+
181+
.action(async (entryPoints, { format, minify, sourcemap }) => {
182+
await fs.rm('./dist/', { force: true, recursive: true })
183+
184+
const formats = await z
185+
.array(Format)
186+
.parseAsync(format)
187+
.catch((e) => {
188+
throw new Error(`Invalid format: ${z.prettifyError(e)}`)
189+
})
190+
191+
await Promise.all([
192+
$({
193+
stdio: 'inherit',
194+
})`runx build bundle-lib-build-types ${entryPoints}`,
195+
196+
...formats.map(async (fmt) => {
197+
const distDir = `./dist/${fmt}`
198+
199+
await Bun.build({
200+
entrypoints: entryPoints,
201+
outdir: distDir,
202+
target: 'node',
203+
minify,
204+
format: fmt,
205+
})
206+
207+
const outExt = match(fmt)
208+
.with('esm', () => '.mjs')
209+
.with('cjs', () => '.cjs')
210+
.exhaustive()
211+
212+
// change output files to mjs/cjs
213+
await pMap(await glob(`${distDir}/**/*.js`), async (file) => {
214+
await fs.rename(file, file.replace(/\.js$/, outExt))
215+
})
216+
}),
217+
])
218+
219+
const cleanupSourcemaps = async () => {
220+
if (sourcemap === false) {
221+
const files = await glob('dist/**/*.map')
222+
await Promise.all(files.map((file) => fs.rm(file)))
223+
}
224+
}
225+
226+
// executables don't need declaration files
227+
const cleanupBin = async () => {
228+
const files = await glob('dist/bin/*.d.ts')
229+
await Promise.all(files.map((file) => fs.rm(file)))
230+
}
231+
232+
await Promise.all([cleanupSourcemaps(), cleanupBin()])
233+
234+
// check if bin is empty
235+
const files = await glob('dist/bin/*')
236+
if (files.length === 0) {
237+
await fs.rm('dist/bin', { recursive: true })
238+
}
239+
})

pnpm-lock.yaml

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)