Skip to content

Commit 0ae039b

Browse files
committed
Standalone: Introduce @herb-tools/standalone package for CLI
1 parent f4bf4c6 commit 0ae039b

File tree

3 files changed

+139
-0
lines changed

3 files changed

+139
-0
lines changed
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
"name": "@herb-tools/standalone",
3+
"version": "0.7.5",
4+
"description": "Standalone executables for Herb CLI (no Node.js required)",
5+
"license": "MIT",
6+
"private": true,
7+
"homepage": "https://herb-tools.dev",
8+
"bugs": "https://github.com/marcoroth/herb/issues/new?title=Package%20%60@herb-tools/standalone%60:%20",
9+
"repository": {
10+
"type": "git",
11+
"url": "https://github.com/marcoroth/herb.git",
12+
"directory": "javascript/packages/standalone"
13+
},
14+
"bin": {
15+
"herb": "./dist/index.mjs"
16+
},
17+
"scripts": {
18+
"build": "bun ./scripts/build.ts"
19+
},
20+
"dependencies": {
21+
"@herb-tools/cli": "0.7.5",
22+
"detect-libc": "1.0.3"
23+
},
24+
"devDependencies": {
25+
"@types/bun": "^1.3.0",
26+
"bun": "^1.3.0"
27+
},
28+
"files": [
29+
"package.json",
30+
"README.md",
31+
"dist/"
32+
]
33+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import { $ } from 'bun'
2+
import { mkdir, writeFile } from 'node:fs/promises'
3+
import { createHash } from 'node:crypto'
4+
import { readFileSync } from 'node:fs'
5+
import { resolve } from 'node:path'
6+
7+
const packageJson = JSON.parse(readFileSync(resolve(import.meta.dir, '../package.json'), 'utf-8'))
8+
const version = packageJson.version
9+
10+
async function buildForPlatform(triple: string, outfile: string) {
11+
console.log(`Building for ${triple}...`)
12+
13+
for (let i = 0; i < 5; ++i) {
14+
try {
15+
let cmd = $`bun build --compile --target=${triple} ./src/index.ts --outfile=${outfile} --env inline --define __VERSION__=${JSON.stringify(version)}`
16+
17+
cmd = cmd.env({
18+
PLATFORM_LIBC: triple.includes('-musl') ? 'musl' : 'glibc',
19+
})
20+
21+
await cmd
22+
console.log(`✓ Built ${outfile}`)
23+
return
24+
} catch (err) {
25+
if (i < 4) {
26+
console.log(` Retry ${i + 1}/5 for ${triple}`)
27+
continue
28+
}
29+
throw new Error(`Failed to build for platform ${triple}`, { cause: err })
30+
}
31+
}
32+
}
33+
34+
function sha256(filePath: string): string {
35+
const content = readFileSync(filePath)
36+
return createHash('sha256').update(content).digest('hex')
37+
}
38+
39+
async function main() {
40+
await mkdir('dist', { recursive: true })
41+
42+
const builds = [
43+
['bun-linux-arm64', './dist/herb-linux-arm64'],
44+
['bun-linux-arm64-musl', './dist/herb-linux-arm64-musl'],
45+
['bun-linux-x64-baseline', './dist/herb-linux-x64'],
46+
['bun-linux-x64-musl-baseline', './dist/herb-linux-x64-musl'],
47+
['bun-darwin-arm64', './dist/herb-macos-arm64'],
48+
['bun-darwin-x64-baseline', './dist/herb-macos-x64'],
49+
['bun-windows-x64-baseline', './dist/herb-windows-x64.exe'],
50+
] as const
51+
52+
await Promise.all(
53+
builds.map(([triple, outfile]) => buildForPlatform(triple, outfile))
54+
)
55+
56+
console.log('\nGenerating checksums...')
57+
const sums: string[] = []
58+
59+
for (const [, outfile] of builds) {
60+
const hash = sha256(outfile)
61+
const filename = outfile.split('/').pop()!
62+
sums.push(`${hash} ${filename}`)
63+
console.log(` ${filename}: ${hash}`)
64+
}
65+
66+
const sumsFile = resolve('dist', 'SHA256SUMS')
67+
await writeFile(sumsFile, sums.join('\n') + '\n')
68+
console.log(`\n✓ Checksums written to ${sumsFile}`)
69+
70+
console.log('\n✓ All builds completed successfully')
71+
}
72+
73+
main().catch((err) => {
74+
console.error('Build failed:', err)
75+
process.exit(1)
76+
})
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { Herb } from '@herb-tools/node-wasm'
2+
import packageJson from '../package.json'
3+
4+
await Herb.load()
5+
6+
globalThis.__herb_version = packageJson.version
7+
8+
Bun.plugin({
9+
name: 'bundle-herb-apis',
10+
target: 'bun',
11+
async setup(build) {
12+
let bundled = {
13+
'@herb-tools/core': await import('@herb-tools/core'),
14+
'@herb-tools/linter': await import('@herb-tools/linter'),
15+
'@herb-tools/formatter': await import('@herb-tools/formatter'),
16+
'@herb-tools/printer': await import('@herb-tools/printer'),
17+
'@herb-tools/highlighter': await import('@herb-tools/highlighter'),
18+
'@herb-tools/node-wasm': await import('@herb-tools/node-wasm'),
19+
}
20+
21+
for (let [id, exports] of Object.entries(bundled)) {
22+
build.module(id, () => ({
23+
loader: 'object',
24+
exports: { ...exports, __esModule: true }
25+
}))
26+
}
27+
}
28+
})
29+
30+
await import('@herb-tools/cli/src/index.ts')

0 commit comments

Comments
 (0)