Skip to content

Commit 7d78fc6

Browse files
frankcalisesemantic-release-botjamonholmgren
authored
feat(cli): add bun support (#2497 by @frankcalise @jamonholmgren)
* chore(release): 8.8.7 [skip ci] ## [8.8.7](v8.8.6...v8.8.7) (2023-08-08) ### Bug Fixes * **cli:** correct cd command when targetPath has changed ([#2488](#2488) by bradherman) ([19a161e](19a161e)) * feat(cli): add bun support * fix: Specifies version of @expo/webpack-config to avoid dependency failure. (#2502 by @jamonholmgren) * chore(release): 8.8.8 [skip ci] ## [8.8.8](v8.8.7...v8.8.8) (2023-09-19) ### Bug Fixes * Specifies version of @expo/webpack-config to avoid dependency failure. ([#2502](#2502) by [@jamonholmgren](https://github.com/jamonholmgren)) ([94ddb85](94ddb85)) * docs: Update README.md -- add Getting Started video link (#2501 by @jamonholmgren) [skip ci] * Switch to bun for boilerplate scripts * Use bun for CI tests * Bump for ci * remove demo app * Bump bun-orb version * bump bun-orb * fix: removed ios remnants merge from main probably * fix(cli): display bun run command --------- Co-authored-by: semantic-release-bot <[email protected]> Co-authored-by: Jamon Holmgren <[email protected]> Co-authored-by: Jamon Holmgren <[email protected]>
1 parent eecac88 commit 7d78fc6

File tree

14 files changed

+2940
-3199
lines changed

14 files changed

+2940
-3199
lines changed

.circleci/config.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,20 @@
66
defaults: &defaults
77
docker:
88
# Choose the version of Node you want here
9-
- image: cimg/node:18.15.0
9+
- image: cimg/node:18.17.1
1010
working_directory: /mnt/ramdisk/repo
1111

1212
version: 2.1
13+
orbs:
14+
# https://circleci.com/developer/orbs/orb/cmgriffing/bun-orb
15+
bun-orb: cmgriffing/[email protected]
1316
jobs:
1417
tests:
1518
<<: *defaults
1619
resource_class: large
1720
steps:
1821
- checkout
22+
- bun-orb/setup
1923
- restore_cache:
2024
name: Restore node modules
2125
keys:

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ coverage
1818
# newly spun-up apps, but we do want to ignore it in
1919
# Ignite's source repo.
2020
boilerplate/yarn.lock
21+
boilerplate/bun.lockb
2122
boilerplate/.gitignore.template
2223

2324
# flame CLI

README.md

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,20 @@
77
![Twitter Follow](https://img.shields.io/twitter/follow/ir_ignite)
88
[![CircleCI](https://dl.circleci.com/status-badge/img/gh/infinitered/ignite/tree/master.svg?style=svg)](https://dl.circleci.com/status-badge/redirect/gh/infinitered/ignite/tree/master)
99

10-
## Battle-tested React Native boilerplate
10+
## Proven React Native boilerplate
1111

12-
The culmination of over six years of constant React Native development, Ignite is the most popular React Native app boilerplate for both Expo and bare React Native.
12+
The culmination of over seven years of constant React Native development, Ignite is the most popular React Native app boilerplate for both Expo and bare React Native.
1313

1414
This is the React Native boilerplate that the [Infinite Red](https://infinite.red) team uses on a day-to-day basis to build client apps. Developers who use Ignite report that it saves them two to four weeks of time on average off the beginning of their React Native project!
1515

1616
## [Full Documentation](https://github.com/infinitered/ignite/blob/master/docs)
1717

1818
We've put great effort into the documentation as a team, please [read through it here](https://github.com/infinitered/ignite/blob/master/docs). If you're unsure why a certain decision was made related to this boilerplate or how to proceed with a particular feature, it's likely documented. If it still isn't clear, go through the proper [help channels](#reporting-bugs--getting-help) and we always welcome PRs to improve the docs!
1919

20+
## Intro Video
21+
22+
Check out the [Getting Started with Ignite](https://www.youtube.com/watch?v=KOSvDlFyg20) video for a 13 minute overview!
23+
2024
## Tech Stack
2125

2226
Nothing makes it into Ignite unless it's been proven on projects that Infinite Red works on. Ignite apps include the following rock-solid technical decisions out of the box:
@@ -103,14 +107,14 @@ If you need battle-tested solutions from Infinite Red experts on everything from
103107

104108
## No time to learn React Native? Hire Infinite Red for your next project
105109

106-
We get it – sometimes there just isn’t enough time on a project to learn the ins and outs of a new framework. Infinite Red’s here to help! Our experienced team of React Native engineers have worked with companies like GasBuddy, Zoom, and Mercari to bring even some of the most complex projects to life.
110+
We get it – sometimes there just isn’t enough time on a project to learn the ins and outs of a new framework. Infinite Red’s here to help! Our experienced team of React Native engineers have worked with companies like Microsoft, GasBuddy, Zoom, and Mercari to bring some of the most complex React Native projects to life.
107111

108112
Whether it’s running a full project or training a team on React Native, we can help you solve your company’s toughest engineering challenges – and make it a great experience at the same time.
109113

110-
Ready to see how we can work together? [Send us a message](mailto:hello@infinite.red)
114+
Ready to see how we can work together? [Send us a message](https://infinite.red/contact)
111115

112116
## Further Reading
113117

114-
- Watch Jamon Holmgren's talk at React Live Amsterdam where he uses Ignite to build an app in less than 30 minutes: [https://www.youtube.com/watch?v=OgiFKMd_TeY](https://www.youtube.com/watch?v=OgiFKMd_TeY)
118+
- Watch Jamon Holmgren's talk at React Live Amsterdam 2019 where he uses Ignite to build an app in less than 30 minutes: [https://www.youtube.com/watch?v=OgiFKMd_TeY](https://www.youtube.com/watch?v=OgiFKMd_TeY)
115119
- Prior art includes [Ignite Andross](https://github.com/infinitered/ignite-andross) and [Ignite Bowser](https://github.com/infinitered/ignite-bowser) (which is very similar to the current version of Ignite).
116120
- [Who are We?](https://infinite.red) - Learn More About Infinite Red

boilerplate/bun.lockb

513 KB
Binary file not shown.

boilerplate/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
"dependencies": {
3232
"@expo-google-fonts/space-grotesk": "^0.2.2",
3333
"@react-native-async-storage/async-storage": "1.18.2",
34+
"@expo/metro-config": "^0.7.1",
35+
"@expo/webpack-config": "18.1.2",
3436
"@react-navigation/bottom-tabs": "^6.3.2",
3537
"@react-navigation/native": "^6.0.2",
3638
"@react-navigation/native-stack": "^6.0.2",

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "ignite-cli",
3-
"version": "8.8.6",
3+
"version": "8.8.8",
44
"description": "Infinite Red's hottest boilerplate for React Native.",
55
"bin": {
66
"ignite": "bin/ignite",
@@ -32,7 +32,7 @@
3232
"format:write": "yarn format --write",
3333
"format:check": "yarn format --check",
3434
"lint": "eslint 'src/**' 'test/**'",
35-
"test": "jest",
35+
"test": "TS_JEST_DISABLE_VER_CHECKER=true jest",
3636
"watch": "jest --watch",
3737
"watch:debug": "yarn watch --runInBand --verbose",
3838
"coverage": "jest --coverage",

src/commands/new.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ export interface Options {
8484
*
8585
* Input Source: `prompt.ask`| `parameter.option`
8686
*/
87-
packager?: "npm" | "yarn" | "pnpm"
87+
packager?: "npm" | "yarn" | "pnpm" | "bun"
8888
/**
8989
* The target directory where the project will be created.
9090
*
@@ -133,7 +133,7 @@ export interface Options {
133133
workflow?: Workflow
134134
}
135135

136-
export default {
136+
module.exports = {
137137
run: async (toolbox: GluegunToolbox) => {
138138
// #region Toolbox
139139
const { print, filesystem, system, meta, parameters, strings, prompt } = toolbox
@@ -335,15 +335,20 @@ export default {
335335
// we pass in expo because we can't use pnpm if we're using expo
336336

337337
const availablePackagers = packager.availablePackagers()
338+
log(`availablePackagers: ${availablePackagers}`)
338339
const defaultPackagerName = availablePackagers.includes("yarn") ? "yarn" : "npm"
339340
let packagerName = useDefault(options.packager) ? defaultPackagerName : options.packager
340341

341342
const validatePackagerName = (input: unknown): input is PackagerName =>
342-
typeof input === "string" && ["npm", "yarn", "pnpm"].includes(input)
343+
typeof input === "string" && ["npm", "yarn", "pnpm", "bun"].includes(input)
343344

344345
if (packagerName !== undefined && validatePackagerName(packagerName) === false) {
345346
p()
346-
p(yellow(`Error: Invalid packager: "${packagerName}". Valid packagers are npm, yarn, pnpm.`))
347+
p(
348+
yellow(
349+
`Error: Invalid packager: "${packagerName}". Valid packagers are npm, yarn, pnpm, bun.`,
350+
),
351+
)
347352
process.exit(1)
348353
}
349354

@@ -471,7 +476,7 @@ export default {
471476
await copyBoilerplate(toolbox, {
472477
boilerplatePath,
473478
targetPath,
474-
excluded: [".vscode", "node_modules", "yarn.lock"],
479+
excluded: [".vscode", "node_modules", "yarn.lock", "bun.lockb", "package-lock.json"],
475480
overwrite,
476481
})
477482
stopSpinner(" 3D-printing a new React Native app", "🖨")

src/tools/cache.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const lockFile = {
66
yarn: "yarn.lock",
77
pnpm: "pnpm-lock.yaml",
88
npm: "package-lock.json",
9+
bun: "bun.lockb",
910
} as const
1011

1112
const MAC: NodeJS.Platform = "darwin"

src/tools/packager.ts

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { spawnProgress } from "./spawn"
55
// in the meantime, we'll use this hacked together version
66

77
// Expo doesn't support pnpm, so we'll use yarn or npm
8-
export type PackagerName = "npm" | "yarn" | "pnpm"
8+
export type PackagerName = "npm" | "yarn" | "pnpm" | "bun"
99
type PackageOptions = {
1010
packagerName?: PackagerName
1111
dev?: boolean
@@ -39,11 +39,20 @@ function pnpmAvailable() {
3939
return isPnpm
4040
}
4141

42+
let isBun
43+
function bunAvailable() {
44+
if (isBun !== undefined) return isBun
45+
isBun = Boolean(system.which("bun"))
46+
return isBun
47+
}
48+
4249
function detectPackager(): PackagerName {
4350
if (yarnAvailable()) {
4451
return "yarn"
4552
} else if (pnpmAvailable()) {
4653
return "pnpm"
54+
} else if (bunAvailable()) {
55+
return "bun"
4756
} else {
4857
return "npm"
4958
}
@@ -59,6 +68,10 @@ function availablePackagers(): PackagerName[] {
5968
packagers.push("pnpm")
6069
}
6170

71+
if (bunAvailable()) {
72+
packagers.push("bun")
73+
}
74+
6275
return packagers
6376
}
6477

@@ -80,6 +93,8 @@ function addCmd(pkg: string, options: PackageRunOptions = packageInstallOptions)
8093
cmd = `yarn add`
8194
} else if (options.packagerName === "npm") {
8295
cmd = `npm install`
96+
} else if (options.packagerName === "bun") {
97+
cmd = `bun add`
8398
} else {
8499
// neither expo nor a packagerName was provided, so let's detect one
85100
return addCmd(pkg, { ...options, packagerName: detectPackager() })
@@ -106,6 +121,8 @@ function removeCmd(pkg: string, options: PackageOptions = packageInstallOptions)
106121
cmd = `yarn remove`
107122
} else if (options.packagerName === "npm") {
108123
cmd = `npm uninstall`
124+
} else if (options.packagerName === "bun") {
125+
cmd = `bun remove`
109126
} else {
110127
// neither expo nor a packagerName was provided, so let's detect one
111128
return removeCmd(pkg, { ...options, packagerName: detectPackager() })
@@ -130,6 +147,8 @@ function installCmd(options: PackageRunOptions) {
130147
return `yarn install${silent}`
131148
} else if (options.packagerName === "npm") {
132149
return `npm install${silent}`
150+
} else if (options.packagerName === "bun") {
151+
return `bun install`
133152
} else {
134153
return installCmd({ ...options, packagerName: detectPackager() })
135154
}
@@ -140,6 +159,20 @@ export function list(options: PackageOptions = packageListOptions): PackageListO
140159
if (options.packagerName === "pnpm") {
141160
// TODO: pnpm list?
142161
throw new Error("pnpm list is not supported yet")
162+
} else if (options.packagerName === "bun") {
163+
return [
164+
// TODO do we need to add --global here?
165+
`bun pm ls`,
166+
(output: string): [string, string][] => {
167+
// Parse yarn's human-readable output
168+
return output
169+
.split("\n")
170+
.reduce((acc: [string, string][], line: string): [string, string][] => {
171+
const match = line.match(/info "([^@]+)@([^"]+)" has binaries/)
172+
return match ? [...acc, [match[1], match[2]]] : acc
173+
}, [])
174+
},
175+
]
143176
} else if (
144177
options.packagerName === "yarn" ||
145178
(options.packagerName === undefined && yarnAvailable())
@@ -181,6 +214,8 @@ function runCmd(command: string, options: PackageOptions) {
181214
return `pnpm run ${command}${silent}`
182215
} else if (options.packagerName === "yarn") {
183216
return `yarn ${command}${silent}`
217+
} else if (options.packagerName === "bun") {
218+
return `bun run ${command}`
184219
} else {
185220
// defaults to npm run
186221
return `npm run ${command}${silent}`
@@ -209,9 +244,10 @@ export const packager = {
209244
const [cmd, parseFn] = list(options)
210245
return parseFn(await spawnProgress(cmd, {}))
211246
},
212-
has: (packageManager: "yarn" | "npm" | "pnpm"): boolean => {
247+
has: (packageManager: "yarn" | "npm" | "pnpm" | "bun"): boolean => {
213248
if (packageManager === "yarn") return yarnAvailable()
214249
if (packageManager === "pnpm") return pnpmAvailable()
250+
if (packageManager === "bun") return bunAvailable()
215251
return true
216252
},
217253
detectPackager,

src/tools/pretty.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ export const pkgColor = (packagerName: PackagerName) => {
130130
npm: "red",
131131
yarn: "blue",
132132
pnpm: "yellow",
133+
bun: "cyan",
133134
}
134135
return print.colors[packagerColors[packagerName]] as (text: string) => string
135136
}

0 commit comments

Comments
 (0)