Skip to content

Commit c51ef37

Browse files
tobeycodesbeeman
authored andcommitted
feat: add bun support
1 parent c67b929 commit c51ef37

File tree

6 files changed

+45
-21
lines changed

6 files changed

+45
-21
lines changed

.changeset/warm-toys-check.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'create-solana-dapp': minor
3+
---
4+
5+
add bun support

src/utils/create-app-task-install-dependencies.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export function createAppTaskInstallDependencies(args: GetArgsResult): Task {
1616
if (args.verbose) {
1717
log.warn(`Installing via ${pm}`)
1818
}
19-
const deleteLockFiles = ['package-lock.json', 'pnpm-lock.yaml', 'yarn.lock']
19+
const deleteLockFiles = ['package-lock.json', 'pnpm-lock.yaml', 'yarn.lock', 'bun.lock']
2020
// We don't want to delete the lock file for the current package manager
2121
.filter((item) => item !== lockFile)
2222
// We only want to delete the lock file if it exists

src/utils/final-note.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export function finalNote(args: FinalNoteArgs): string {
1616
`That's it!`,
1717
`Change to your new directory and start developing:`,
1818
msg(`cd ${args.target}`),
19-
...(args.skipInstall ? [`Install dependencies:`, cmd(args.packageManager, 'install')] : []),
19+
...(args.skipInstall ? [`Install dependencies:`, msg(`${args.packageManager} install`)] : []),
2020
...(startScript ? [`Start the app:`, cmd(args.packageManager, startScript)] : []),
2121
...args.instructions.map((line) => (line.startsWith('+') ? msg(line.slice(1)) : line)),
2222
]

src/utils/get-args.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export async function getArgs(argv: string[], app: AppInfo, pm: PackageManager =
1616
.option('--pm, --package-manager <package-manager>', help(`Package manager to use (default: npm)`))
1717
.option('--yarn', help(`Use yarn as the package manager`), false)
1818
.option('--pnpm', help(`Use pnpm as the package manager`), false)
19+
.option('--bun', help(`Use bun as the package manager`), false)
1920
.option('-d, --dry-run', help('Dry run (default: false)'))
2021
.option('-t, --template <template-name>', help('Use a template'))
2122
.option('--list-templates', help('List available templates'))
@@ -55,17 +56,21 @@ Examples:
5556
}
5657
let packageManager = result.packageManager ?? pm
5758

58-
// The 'yarn' and 'pnpm' options are mutually exclusive, and will override the 'packageManager' option
59-
if (result.pnpm && result.yarn) {
60-
log.error(`Both pnpm and yarn were specified. Please specify only one.`)
61-
throw new Error(`Both pnpm and yarn were specified. Please specify only one.`)
59+
// The 'yarn', 'pnpm' and 'bun' options are mutually exclusive, and will override the 'packageManager' option
60+
const managers = [result.pnpm && 'pnpm', result.yarn && 'yarn', result.bun && 'bun'].filter(Boolean)
61+
if (managers.length > 1) {
62+
log.error(`Multiple package managers were specified: ${managers.join(', ')}. Please specify only one.`)
63+
throw new Error(`Multiple package managers were specified: ${managers.join(', ')}. Please specify only one.`)
6264
}
6365
if (result.pnpm) {
6466
packageManager = 'pnpm'
6567
}
6668
if (result.yarn) {
6769
packageManager = 'yarn'
6870
}
71+
if (result.bun) {
72+
packageManager = 'bun'
73+
}
6974

7075
// Display the intro
7176
intro(`${app.name} ${app.version}`)

src/utils/vendor/package-manager.ts

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,26 +11,28 @@
1111
*/
1212
import { execSync } from 'node:child_process'
1313
import { existsSync } from 'node:fs'
14-
import { join } from 'node:path'
14+
import { join, sep } from 'node:path'
1515

16-
export const packageManagers = ['pnpm', 'npm', 'yarn'] as const
16+
export const packageManagers = ['pnpm', 'npm', 'yarn', 'bun'] as const
1717
export type PackageManager = (typeof packageManagers)[number]
1818

1919
export function detectInvokedPackageManager(): PackageManager {
20-
let detectedPackageManager: PackageManager = 'npm'
21-
const invoker = require.main
22-
23-
if (!invoker) {
24-
return detectedPackageManager
20+
if (process.env.npm_config_user_agent) {
21+
for (const pm of packageManagers) {
22+
if (process.env.npm_config_user_agent.startsWith(`${pm}/`)) {
23+
return pm
24+
}
25+
}
2526
}
2627

27-
for (const pkgManager of packageManagers) {
28-
if (invoker.path.includes(pkgManager)) {
29-
detectedPackageManager = pkgManager
30-
break
28+
if (process.env.npm_execpath) {
29+
for (const pm of packageManagers) {
30+
if (process.env.npm_execpath.split(sep).includes(pm)) {
31+
return pm
32+
}
3133
}
3234
}
33-
return detectedPackageManager
35+
return 'npm'
3436
}
3537

3638
/**
@@ -99,6 +101,15 @@ export function getPackageManagerCommand(
99101
lockFile: 'package-lock.json',
100102
}
101103
}
104+
105+
case 'bun': {
106+
return {
107+
install: `bun install ${silent}`,
108+
exec: 'bun',
109+
globalAdd: 'bun add -g',
110+
lockFile: 'bun.lock',
111+
}
112+
}
102113
}
103114
}
104115
const pmVersionCache = new Map<PackageManager, string>()
@@ -123,6 +134,9 @@ export function detectPackageManager(dir: string = ''): PackageManager {
123134
if (existsSync(join(dir, 'pnpm-lock.yaml'))) {
124135
return 'pnpm'
125136
}
137+
if (existsSync(join(dir, 'bun.lock'))) {
138+
return 'bun'
139+
}
126140

127141
return 'npm'
128142
}

test/final-note.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ describe('finalNote', () => {
3333
const result = finalNote({ ...baseArgs, skipInstall: true })
3434

3535
expect(result).toContain('Install dependencies:')
36-
expect(result).toContain('npm run install')
36+
expect(result).toContain('npm install')
3737
})
3838

3939
it('should not include install instructions when skipInstall is false', () => {
@@ -44,7 +44,7 @@ describe('finalNote', () => {
4444
const result = finalNote({ ...baseArgs, skipInstall: false })
4545

4646
expect(result).not.toContain('Install dependencies:')
47-
expect(result).not.toContain('npm run install')
47+
expect(result).not.toContain('npm install')
4848
})
4949

5050
it('should use yarn when packageManager is yarn and skipInstall is true', () => {
@@ -58,6 +58,6 @@ describe('finalNote', () => {
5858
packageManager: 'yarn' as FinalNoteArgs['packageManager'],
5959
})
6060

61-
expect(result).toContain('yarn run install')
61+
expect(result).toContain('yarn install')
6262
})
6363
})

0 commit comments

Comments
 (0)