@yahoo/uds 0.1.13 → 0.1.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli/README.md +57 -5
- package/cli/commands/expo/_setup.ts +100 -73
- package/cli/commands/expo/build.ts +84 -3
- package/cli/commands/expo/dev.ts +51 -41
- package/cli/commands/expo/install/cocoapods.rb +35 -0
- package/cli/commands/purge.ts +15 -0
- package/cli/commands/{config/sync.ts → sync.ts} +2 -2
- package/cli/utils/configWorker.ts +21 -1
- package/cli/utils/purgeCSS.ts +139 -0
- package/cli/utils/setupConfigWorker.ts +12 -13
- package/dist/{chunk-P7GR6E3K.js → chunk-AHFH5E5L.js} +1 -1
- package/dist/{chunk-MBOOJIH7.js → chunk-FLBMVDKG.js} +1 -1
- package/dist/{chunk-AWTLI4D3.js → chunk-U3UPAQ7V.js} +1 -1
- package/dist/fixtures/index.cjs +1 -1
- package/dist/fixtures/index.d.cts +2 -2
- package/dist/fixtures/index.d.ts +2 -2
- package/dist/fixtures/index.js +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +40 -31
- package/dist/index.d.ts +40 -31
- package/dist/index.js +1 -1
- package/dist/{index.native-9kYJrUPa.d.ts → index.native-TvtXtTXg.d.ts} +2 -2
- package/dist/{index.native-3ww4C4UV.d.cts → index.native-dgGFONLf.d.cts} +2 -2
- package/dist/index.native.cjs +1 -1
- package/dist/index.native.d.cts +10 -24
- package/dist/index.native.d.ts +10 -24
- package/dist/index.native.js +1 -1
- package/dist/tailwindPlugin.cjs +1 -1
- package/dist/tailwindPlugin.d.cts +1 -1
- package/dist/tailwindPlugin.d.ts +1 -1
- package/dist/tailwindPlugin.js +1 -1
- package/dist/tailwindPurge.cjs +4 -0
- package/dist/tailwindPurge.d.cts +16 -0
- package/dist/tailwindPurge.d.ts +16 -0
- package/dist/tailwindPurge.js +4 -0
- package/dist/tokens/index.cjs +1 -1
- package/dist/tokens/index.d.cts +3 -3
- package/dist/tokens/index.d.ts +3 -3
- package/dist/tokens/index.js +1 -1
- package/dist/tokens/index.native.cjs +1 -1
- package/dist/tokens/index.native.d.cts +2 -2
- package/dist/tokens/index.native.d.ts +2 -2
- package/dist/tokens/index.native.js +1 -1
- package/dist/tokens/parseTokens.cjs +1 -1
- package/dist/tokens/parseTokens.d.cts +12 -12
- package/dist/tokens/parseTokens.d.ts +12 -12
- package/dist/tokens/parseTokens.js +1 -1
- package/dist/tokens/parseTokens.native.d.cts +2 -2
- package/dist/tokens/parseTokens.native.d.ts +2 -2
- package/dist/{types-J4DLS6Xj.d.cts → types-3GXulqnG.d.cts} +1 -1
- package/dist/{types-J4DLS6Xj.d.ts → types-3GXulqnG.d.ts} +1 -1
- package/dist/{types-hirL9Qk5.d.cts → types-8OHfDki5.d.cts} +47 -54
- package/dist/{types-hirL9Qk5.d.ts → types-8OHfDki5.d.ts} +47 -54
- package/package.json +21 -18
- package/cli/commands/config/config.ts +0 -10
- package/cli/commands/nextjs/dev.ts +0 -17
- package/cli/commands/nextjs/nextjs.ts +0 -10
package/cli/README.md
CHANGED
@@ -1,16 +1,68 @@
|
|
1
|
-
# UDS
|
1
|
+
# UDS Cli
|
2
2
|
|
3
3
|
We leverage Bluebun, which is a CLI framework inspired by [Gluegun](https://github.com/infinitered/gluegun), but specifically designed to be used with [Bun](https://bun.sh), the new JS runtime.
|
4
4
|
|
5
5
|
Bluebun relies on Bun APIs and is designed to be extremely fast, with no-dependencies.
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
We use Bun to build our standalone executable. See [Bun build docs](https://bun.sh/docs/bundler/executables) for more details. The uds package.json's `build:cli` script handles building the CLI. The bin is output to the `dist/uds` binary file and this path is defined in the package.json's bin field.
|
7
|
+
> Trying to add a new command? Please see the "Adding a Command" section below
|
10
8
|
|
11
9
|
# Commands
|
12
10
|
|
13
|
-
|
11
|
+
In any consumer of `@yahoo/uds` the following commands are available:
|
12
|
+
|
13
|
+
> Please note: If you are _not_ running the CLI from a package.json script you will need to add `bun` before the binary in order to run it directly. i.e. `bun uds purge`
|
14
|
+
|
15
|
+
## Config
|
16
|
+
|
17
|
+
### Using args
|
18
|
+
|
19
|
+
| Arg | Required | Default |
|
20
|
+
| ------- | -------- | --------------- |
|
21
|
+
| id | true | |
|
22
|
+
| outFile | false | ./uds.config.ts |
|
23
|
+
|
24
|
+
```shell
|
25
|
+
uds sync --id [id] --outFile [path]
|
26
|
+
```
|
27
|
+
|
28
|
+
```shell
|
29
|
+
uds sync --id [id]
|
30
|
+
```
|
31
|
+
|
32
|
+
### Using ENV vars
|
33
|
+
|
34
|
+
| Env Var | Required | Default |
|
35
|
+
| ------------ | -------- | --------------- |
|
36
|
+
| UDS_ID | true | |
|
37
|
+
| UDS_OUT_FILE | false | ./uds.config.ts |
|
38
|
+
|
39
|
+
```shell
|
40
|
+
UDS_ID=[id] uds sync --outFile [path]
|
41
|
+
```
|
42
|
+
|
43
|
+
```shell
|
44
|
+
UDS_ID=[id] UDS_OUT_FILE=[path] uds sync
|
45
|
+
```
|
46
|
+
|
47
|
+
## Expo
|
48
|
+
|
49
|
+
```shell
|
50
|
+
uds expo build --profile [profile] --platform [ios|android]
|
51
|
+
uds expo dev --profile [profile] --platform [ios|android]
|
52
|
+
uds expo launch --profile [profile] --platform [ios|android]
|
53
|
+
uds expo update --profile [profile] --platform [ios|android]
|
54
|
+
uds expo --help
|
55
|
+
```
|
56
|
+
|
57
|
+
## Purge CSS
|
58
|
+
|
59
|
+
```shell
|
60
|
+
uds purge
|
61
|
+
```
|
62
|
+
|
63
|
+
## Adding a command
|
64
|
+
|
65
|
+
> Please note: Adding nested commands, i.e. uds expo dev, appears to not work correctly when UDS is consumed from npm. As a workaround, please see code for expo/expo.ts for re-routing sub-commands from the root command file. To verify your CLI command works correctly you should run `npm pack` within the packages/uds directory. Once you have your generated tarball you should copy that tarball to a test application such as https://github.com/yahoo-design/uds-nextjs-demo, then add `"@yahoo/uds": "file:./tarball-generated-from-npm-pack.tgz` to it's dependencies and run an install. Now you should be able to run `bun uds [your command name]` to test your functionality.
|
14
66
|
|
15
67
|
Commands are organized in a tree structure. The root command is the name of the CLI (uds), and then we can have subcommands under that, and subcommands under those, and so on.
|
16
68
|
|
@@ -1,22 +1,23 @@
|
|
1
1
|
import { EasJsonAccessor, EasJsonUtils, Platform } from '@expo/eas-json';
|
2
2
|
import { type Props, print } from 'bluebun';
|
3
|
-
import {
|
3
|
+
import { $, semver, which } from 'bun';
|
4
|
+
import fs from 'node:fs';
|
5
|
+
import os from 'node:os';
|
4
6
|
|
5
7
|
export interface MobileProps extends Props {
|
6
8
|
options: {
|
7
9
|
profile: string;
|
8
|
-
platform: Platform
|
10
|
+
platform: Platform;
|
9
11
|
jsEngine?: 'hermes' | 'jsc';
|
10
12
|
debug?: boolean;
|
11
13
|
};
|
12
14
|
}
|
13
15
|
|
14
|
-
async function needsBinary(lib: string) {
|
15
|
-
|
16
|
-
return whichLib.includes('not found');
|
16
|
+
export async function needsBinary(lib: string) {
|
17
|
+
return which(lib) === null;
|
17
18
|
}
|
18
19
|
|
19
|
-
async function needsBrewFormula(formula: string) {
|
20
|
+
export async function needsBrewFormula(formula: string) {
|
20
21
|
return (await $`brew list --formula | grep ${formula} | wc -l`.text()).trim() === '0';
|
21
22
|
}
|
22
23
|
|
@@ -28,87 +29,108 @@ export async function setup({
|
|
28
29
|
env?: Partial<typeof Bun.env>;
|
29
30
|
}) {
|
30
31
|
const { profile, platform, jsEngine = 'hermes', debug = false } = props.options;
|
32
|
+
const isIOS = platform === Platform.IOS;
|
33
|
+
const isAndroid = platform === Platform.ANDROID;
|
34
|
+
const pathAsString = await $`echo $PATH`.text();
|
35
|
+
const needsBunInPath = !pathAsString.includes('.bun');
|
31
36
|
|
32
37
|
/* -------------------------------------------------------------------------- */
|
33
|
-
/*
|
38
|
+
/* VERIFY BUN IS IN PATH */
|
34
39
|
/* -------------------------------------------------------------------------- */
|
35
|
-
|
36
|
-
if (needsBrew) {
|
37
|
-
console.log('Installing brew...');
|
38
|
-
await $`/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"`;
|
39
|
-
console.log('Installing brew...Complete');
|
40
|
-
|
40
|
+
if (needsBunInPath) {
|
41
41
|
/**
|
42
|
-
*
|
43
|
-
* https://
|
44
|
-
* However, their script just alerts users to the fact that they need to add
|
45
|
-
* brew to their path, but doesn't do it for them. This logic attempts to do that
|
46
|
-
* so we can automatically proceed to the next steps of auto-installing
|
47
|
-
* the necessary dependencies for local development.
|
42
|
+
* If BUN_INSTALL is not in the path, we need to add it.
|
43
|
+
* https://bun.sh/docs/installation#checking-installation:~:text=shell%27s%20configuration%20file.
|
48
44
|
*/
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
const
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
shellRcFile
|
57
|
-
|
58
|
-
|
59
|
-
}
|
60
|
-
|
61
|
-
const shellRcPath = `${Bun.env.HOME}/${shellRcFile}`;
|
62
|
-
let shellRcContents = '';
|
63
|
-
try {
|
64
|
-
shellRcContents = await Bun.file(shellRcPath).text();
|
65
|
-
} catch (err) {
|
66
|
-
// Ignore if it doesn't exist. We create it below.
|
67
|
-
}
|
68
|
-
|
69
|
-
if (!shellRcContents.includes('homebrew')) {
|
70
|
-
console.log('Adding brew to $PATH...');
|
71
|
-
const newShellRcContents = `${shellRcContents}\neval "$(${homebrewPrefix}/bin/brew shellenv)"`;
|
72
|
-
await Bun.write(shellRcPath, newShellRcContents);
|
73
|
-
}
|
45
|
+
console.write(
|
46
|
+
'BUN is not installed globally or is not available in your $PATH. Adding to your $PATH...',
|
47
|
+
);
|
48
|
+
const whichShell = await $`echo $SHELL`.text();
|
49
|
+
const homeDirectory = os.homedir();
|
50
|
+
const shellRcFile = whichShell.includes('zsh') ? '.zshrc' : '.bashrc';
|
51
|
+
fs.appendFileSync(
|
52
|
+
`${homeDirectory}/${shellRcFile}`,
|
53
|
+
'\n# bun\nexport BUN_INSTALL="$HOME/.bun"\nexport PATH="$BUN_INSTALL/bin:$PATH"',
|
54
|
+
);
|
55
|
+
await $`source $HOME/${shellRcFile}`;
|
74
56
|
}
|
75
57
|
|
76
58
|
/* -------------------------------------------------------------------------- */
|
77
|
-
/*
|
59
|
+
/* XCODE SETUP */
|
78
60
|
/* -------------------------------------------------------------------------- */
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
61
|
+
if (isIOS) {
|
62
|
+
const xcodePath = await $`xcode-select -p`.text();
|
63
|
+
|
64
|
+
if (xcodePath) {
|
65
|
+
const isInvalidXcodePath = !xcodePath.startsWith('/Applications');
|
66
|
+
|
67
|
+
if (isInvalidXcodePath) {
|
68
|
+
console.write(`
|
69
|
+
/* -------------------------------------------------------------------------- */
|
70
|
+
/* XCODDE PATH IS INVALID */
|
71
|
+
/* -------------------------------------------------------------------------- */
|
72
|
+
|
73
|
+
Run the following command to set the correct path to XCode:
|
74
|
+
|
75
|
+
sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
|
76
|
+
`);
|
77
|
+
}
|
78
|
+
} else {
|
79
|
+
console.write(`
|
80
|
+
/* -------------------------------------------------------------------------- */
|
81
|
+
/* XCODE NOT INSTALLED */
|
82
|
+
/* -------------------------------------------------------------------------- */
|
83
|
+
|
84
|
+
You must have XCode installed before continuing...
|
85
|
+
|
86
|
+
Visit https://apps.apple.com/us/app/xcode/id497799835?mt=12 to download.
|
87
|
+
`);
|
88
|
+
throw new Error('XCode not installed');
|
89
|
+
}
|
84
90
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
91
|
+
/**
|
92
|
+
* Installing the XCode command line tools & simulators normally
|
93
|
+
* requires opening up XCode to install.
|
94
|
+
* This conditional is to avoid having to do that.
|
95
|
+
*
|
96
|
+
* If xcode command line tools and simulators have already been installed, that's
|
97
|
+
* fine. This command is really fast and will continue running if already available.
|
98
|
+
*
|
99
|
+
* https://developer.apple.com/documentation/xcode/installing-additional-simulator-runtimes#Install-and-manage-Simulator-runtimes-from-the-command-line
|
100
|
+
*/
|
101
|
+
await $`xcodebuild -runFirstLaunch`;
|
102
|
+
await $`xcodebuild -downloadPlatform iOS`;
|
92
103
|
}
|
93
104
|
|
94
105
|
/* -------------------------------------------------------------------------- */
|
95
106
|
/* JAVA DEVELOPMENT KIT */
|
96
107
|
/* -------------------------------------------------------------------------- */
|
97
|
-
if (
|
108
|
+
if (isAndroid) {
|
98
109
|
const jdkPath = await $`brew info --cask zulu17`.text();
|
99
110
|
const needsJdk = jdkPath.includes('unavailable');
|
100
111
|
if (needsJdk) {
|
101
|
-
console.
|
112
|
+
console.write('Installing Java Development Kit for Android...');
|
102
113
|
await $`brew install --cask zulu17`;
|
103
114
|
}
|
104
115
|
}
|
105
116
|
|
106
117
|
/* -------------------------------------------------------------------------- */
|
107
|
-
/*
|
118
|
+
/* EAS CONFIG SETUP */
|
108
119
|
/* -------------------------------------------------------------------------- */
|
120
|
+
/**
|
121
|
+
* eas.json is used to define build profiles for different environments.
|
122
|
+
* For example, you may have a profile for development, staging, and production.
|
123
|
+
*
|
124
|
+
* The EAS CLI is used to build and run an app locally based on the eas.json,
|
125
|
+
* but it isn't opinionated about how you define your profiles.
|
126
|
+
*
|
127
|
+
* We however want to enforce some conventions to make it easier to get started.
|
128
|
+
* We also want to store our builds outside of EAS ecosystem since they auto
|
129
|
+
* delete after 30 days & our builds infrequently.
|
130
|
+
*
|
131
|
+
*/
|
109
132
|
const appDirectory = Bun.env.PWD;
|
110
133
|
const easJsonAccessor = EasJsonAccessor.fromProjectPath(appDirectory);
|
111
|
-
|
112
134
|
const easProfiles = await EasJsonUtils.getBuildProfileNamesAsync(easJsonAccessor);
|
113
135
|
|
114
136
|
if (!easProfiles.includes(profile)) {
|
@@ -126,20 +148,22 @@ export async function setup({
|
|
126
148
|
}
|
127
149
|
|
128
150
|
const easJsonConfig = await EasJsonUtils.getBuildProfileAsync(easJsonAccessor, platform, profile);
|
129
|
-
|
130
151
|
const easCliConfig = await EasJsonUtils.getCliConfigAsync(easJsonAccessor);
|
131
152
|
const easCliVersion = easCliConfig?.version ?? 'latest';
|
132
153
|
|
133
154
|
/* -------------------------------------------------------------------------- */
|
134
155
|
/* EAS CLI SETUP */
|
135
156
|
/* -------------------------------------------------------------------------- */
|
157
|
+
/**
|
158
|
+
* EAS CLI is used to build and run an app locally.
|
159
|
+
*/
|
136
160
|
const needsEasCli = await needsBinary('eas');
|
137
161
|
if (needsEasCli) {
|
138
|
-
await $`bun install eas-cli@${easCliVersion} -g
|
162
|
+
await $`bun install eas-cli@${easCliVersion} -g`.quiet();
|
139
163
|
} else {
|
140
164
|
const currentEasCliVersion = await $`eas --version`.text();
|
141
|
-
if (currentEasCliVersion
|
142
|
-
await $`bun install eas-cli@${easCliVersion} -g
|
165
|
+
if (!semver.satisfies(currentEasCliVersion, easCliVersion)) {
|
166
|
+
await $`bun install eas-cli@${easCliVersion} -g`.quiet();
|
143
167
|
}
|
144
168
|
}
|
145
169
|
|
@@ -150,7 +174,7 @@ export async function setup({
|
|
150
174
|
} = easJsonConfig.env ?? {};
|
151
175
|
|
152
176
|
// TODO: Add additional checks for ensuring this value adheres to Android formatting specs
|
153
|
-
if (
|
177
|
+
if (isAndroid && !androidId) {
|
154
178
|
throw new Error(`
|
155
179
|
APP_ANDROID_BUNDLE_IDENTIFIER must be defined in eas.json within the ${profile} > env config.
|
156
180
|
See https://docs.expo.dev/build-reference/variables/#setting-plaintext-environment-variables-in-easjson for information about env variables in eas.json
|
@@ -174,7 +198,7 @@ export async function setup({
|
|
174
198
|
}
|
175
199
|
|
176
200
|
// TODO: Add additional checks for ensuring this value adheres to Uniform Type Identifier
|
177
|
-
if (
|
201
|
+
if (isIOS && !appleId) {
|
178
202
|
throw new Error(`
|
179
203
|
APP_APPLE_BUNDLE_IDENTIFIER must be defined in eas.json within the ${profile} > env config.
|
180
204
|
See https://docs.expo.dev/build-reference/variables/#setting-plaintext-environment-variables-in-easjson for information about env variables in eas.json
|
@@ -197,11 +221,13 @@ export async function setup({
|
|
197
221
|
}
|
198
222
|
|
199
223
|
const outputName = `${platform}-${profile}-${jsEngine}`;
|
200
|
-
// TODO: make this configurable
|
201
|
-
const prebuildsDir = `${appDirectory}/prebuilds`;
|
224
|
+
const prebuildsDir = `${appDirectory}/prebuilds`; // TODO: make this configurable
|
202
225
|
const outputDir = `${prebuildsDir}/${outputName}`;
|
203
226
|
const outputFileBase = `${outputDir}/${outputName}`;
|
204
227
|
|
228
|
+
/* -------------------------------------------------------------------------- */
|
229
|
+
/* ENVIRONMENT VARIABLES */
|
230
|
+
/* -------------------------------------------------------------------------- */
|
205
231
|
let envVars = Bun.env;
|
206
232
|
|
207
233
|
envVars = {
|
@@ -226,6 +252,7 @@ export async function setup({
|
|
226
252
|
envVars = { ...envVars, ...envOpts };
|
227
253
|
}
|
228
254
|
|
255
|
+
/** Change the default environment variables for shells created by this instance. */
|
229
256
|
$.env(envVars);
|
230
257
|
|
231
258
|
const output = {
|
@@ -233,10 +260,10 @@ export async function setup({
|
|
233
260
|
dir: outputDir,
|
234
261
|
prebuildsDir: prebuildsDir,
|
235
262
|
fileBase: outputFileBase,
|
236
|
-
artifact:
|
237
|
-
app:
|
263
|
+
artifact: isIOS ? `${outputFileBase}.tar.gz` : `${outputFileBase}.zip`,
|
264
|
+
app: isIOS ? `${outputFileBase}.app` : 'todo fix android',
|
238
265
|
get launchFile() {
|
239
|
-
return
|
266
|
+
return isIOS ? this.artifact : this.apk.signed;
|
240
267
|
},
|
241
268
|
apk: {
|
242
269
|
contents: `${outputFileBase}/build`,
|
@@ -248,7 +275,7 @@ export async function setup({
|
|
248
275
|
};
|
249
276
|
|
250
277
|
return {
|
251
|
-
scheme:
|
278
|
+
scheme: isIOS ? appleId : androidId,
|
252
279
|
channel: easJsonConfig.channel,
|
253
280
|
debug,
|
254
281
|
profile,
|
@@ -1,6 +1,5 @@
|
|
1
|
-
import {
|
2
|
-
import type
|
3
|
-
import { setup } from './_setup';
|
1
|
+
import { $, semver } from 'bun';
|
2
|
+
import { setup, needsBinary, needsBrewFormula, type MobileProps } from './_setup';
|
4
3
|
|
5
4
|
export default {
|
6
5
|
name: 'build',
|
@@ -10,6 +9,88 @@ export default {
|
|
10
9
|
props,
|
11
10
|
});
|
12
11
|
|
12
|
+
/* ----- Homebrew, Fastlane, and Cocoapods are only required for builds. ---- */
|
13
|
+
/* -------------------------------------------------------------------------- */
|
14
|
+
/* HOMEBREW SETUP */
|
15
|
+
/* -------------------------------------------------------------------------- */
|
16
|
+
const needsBrew = await needsBinary('brew');
|
17
|
+
if (needsBrew) {
|
18
|
+
console.write('Installing brew...');
|
19
|
+
await $`/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"`;
|
20
|
+
console.write('Installing brew...Complete');
|
21
|
+
|
22
|
+
/**
|
23
|
+
* This logic was ported from the homebrew installer script
|
24
|
+
* https://github.com/Homebrew/install/blob/master/install.sh#L153C5-L153C63.
|
25
|
+
* However, their script just alerts users to the fact that they need to add
|
26
|
+
* brew to their path, but doesn't do it for them. This logic attempts to do that
|
27
|
+
* so we can automatically proceed to the next steps of auto-installing
|
28
|
+
* the necessary dependencies for local development.
|
29
|
+
*/
|
30
|
+
const machineArch = await $`uname -m`.text();
|
31
|
+
const isLinux = (await $`uname`.text()) === 'Linux';
|
32
|
+
const shellType = await $`echo $SHELL`.text();
|
33
|
+
const homebrewPrefix = machineArch.includes('arm64') ? '/opt/homebrew' : '/usr/local';
|
34
|
+
let shellRcFile;
|
35
|
+
|
36
|
+
if (isLinux) {
|
37
|
+
shellRcFile = shellType.includes('zsh') ? '.zshrc' : '.bashrc';
|
38
|
+
} else {
|
39
|
+
shellRcFile = shellType.includes('zsh') ? '.zprofile' : '.bash_profile';
|
40
|
+
}
|
41
|
+
|
42
|
+
const shellRcPath = `${Bun.env.HOME}/${shellRcFile}`;
|
43
|
+
let shellRcContents = '';
|
44
|
+
try {
|
45
|
+
shellRcContents = await Bun.file(shellRcPath).text();
|
46
|
+
} catch (err) {
|
47
|
+
// Ignore if it doesn't exist. We create it below.
|
48
|
+
}
|
49
|
+
|
50
|
+
if (!shellRcContents.includes('homebrew')) {
|
51
|
+
console.write('Adding brew to $PATH...');
|
52
|
+
const newShellRcContents = `${shellRcContents}\neval "$(${homebrewPrefix}/bin/brew shellenv)"`;
|
53
|
+
await Bun.write(shellRcPath, newShellRcContents);
|
54
|
+
}
|
55
|
+
}
|
56
|
+
|
57
|
+
/* -------------------------------------------------------------------------- */
|
58
|
+
/* FASTLANE SETUP */
|
59
|
+
/* -------------------------------------------------------------------------- */
|
60
|
+
const needsFastlane = await needsBrewFormula('fastlane');
|
61
|
+
if (needsFastlane) {
|
62
|
+
console.write('Installing fastlane...');
|
63
|
+
await $`brew install fastlane`;
|
64
|
+
}
|
65
|
+
|
66
|
+
/* -------------------------------------------------------------------------- */
|
67
|
+
/* COCOAPODS SETUP */
|
68
|
+
/* -------------------------------------------------------------------------- */
|
69
|
+
const needsCocoapods = await needsBrewFormula('cocoapods');
|
70
|
+
/** https://github.com/facebook/react-native/issues/42698#issuecomment-1915670708 */
|
71
|
+
const validCocoapodsVersion = '1.14.3';
|
72
|
+
|
73
|
+
const installCocoapods = async () =>
|
74
|
+
await $`brew install ${import.meta.dirname}/install/cocoapods.rb`;
|
75
|
+
|
76
|
+
if (needsCocoapods) {
|
77
|
+
console.write('Installing cocoapods...');
|
78
|
+
await installCocoapods();
|
79
|
+
} else {
|
80
|
+
const cocoapodsVersion = await $`pod --version`.text();
|
81
|
+
const needsDowngrade = semver.satisfies(cocoapodsVersion, `>${validCocoapodsVersion}`);
|
82
|
+
if (needsDowngrade) {
|
83
|
+
await $`brew unlink cocoapods`;
|
84
|
+
await $`brew uninstall cocoapods`;
|
85
|
+
console.write(
|
86
|
+
`Downgrading cocoapods from ${cocoapodsVersion} to ${validCocoapodsVersion}...`,
|
87
|
+
);
|
88
|
+
await installCocoapods();
|
89
|
+
await $`brew link cocoapods`;
|
90
|
+
}
|
91
|
+
}
|
92
|
+
|
13
93
|
await $`eas build --local --non-interactive --json --clear-cache --platform ${platform} --profile ${profile} --output ${output.artifact}`;
|
94
|
+
console.write('You can now run your dev command to start the app!');
|
14
95
|
},
|
15
96
|
};
|
package/cli/commands/expo/dev.ts
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
import { Props } from 'bluebun';
|
2
|
-
import {
|
2
|
+
import { $, sleep } from 'bun';
|
3
3
|
import { setup, type MobileProps } from './_setup';
|
4
4
|
|
5
5
|
interface MobileStartProps extends Props {
|
@@ -12,7 +12,7 @@ interface MobileStartProps extends Props {
|
|
12
12
|
type SimDevice = { udid: string; name: string; state: 'Booted' | 'Shutdown' };
|
13
13
|
type SimList = {
|
14
14
|
devices: {
|
15
|
-
[
|
15
|
+
[key: string]: SimDevice[];
|
16
16
|
};
|
17
17
|
};
|
18
18
|
|
@@ -20,7 +20,6 @@ export default {
|
|
20
20
|
name: 'dev',
|
21
21
|
description: '🚧 Dev',
|
22
22
|
run: async (props: MobileStartProps) => {
|
23
|
-
console.log('running dev');
|
24
23
|
const { platform, scheme, output } = await setup({
|
25
24
|
props,
|
26
25
|
env: {
|
@@ -28,52 +27,63 @@ export default {
|
|
28
27
|
},
|
29
28
|
});
|
30
29
|
|
31
|
-
|
32
|
-
const xcodePath = await $`xcode-select -p`.text();
|
33
|
-
const xcodeExists = xcodePath.startsWith('/Applications');
|
30
|
+
const extraArgs = [];
|
34
31
|
|
35
|
-
|
36
|
-
|
37
|
-
|
32
|
+
if (props.options.clear) {
|
33
|
+
extraArgs.push('--clear');
|
34
|
+
}
|
35
|
+
const extrArgsString = extraArgs.join(' ');
|
38
36
|
|
37
|
+
try {
|
38
|
+
/**
|
39
|
+
* Get list of devices.
|
40
|
+
* If there is a booted device, open the simulator on that device.
|
41
|
+
* If no booted device is found, open the simulator on iPhone 15 Pro Max.
|
42
|
+
* * https://github.com/expo/orbit/blob/main/packages/eas-shared/src/run/ios/simulator.ts#L98
|
43
|
+
*
|
44
|
+
* TODO:
|
45
|
+
* Should we open app on all booted devices if there are multiple open?
|
46
|
+
* Should we prompt user to pick from one of the booted devices?
|
47
|
+
* Should we prompt user to pick a device if there are no booted devices?
|
48
|
+
*/
|
49
|
+
if (platform === 'ios') {
|
50
|
+
const deviceList =
|
51
|
+
(await $`xcrun simctl list devices available --json -e`.json()) as SimList;
|
39
52
|
const devices = Object.values(deviceList?.devices).flatMap((item) => item);
|
53
|
+
const bootedDevice = devices.find((device: SimDevice) => device.state === 'Booted');
|
54
|
+
if (!bootedDevice) {
|
55
|
+
const iphone15ProMax = devices.find((device) => device.name === 'iPhone 15 Pro Max');
|
56
|
+
const iphone15Udid = iphone15ProMax?.udid;
|
57
|
+
await $`open -a Simulator --args -CurrentDeviceUDID ${iphone15Udid}`;
|
58
|
+
}
|
59
|
+
const appContainerPath =
|
60
|
+
await $`xcrun simctl get_app_container booted ${scheme} data`.text();
|
40
61
|
|
41
|
-
if (
|
42
|
-
|
43
|
-
|
44
|
-
const isBooted = devices.find((device: SimDevice) => device.state === 'Booted');
|
45
|
-
if (!isBooted) {
|
46
|
-
const iphone15Max = devices.find(
|
47
|
-
(device: SimDevice) => device.name === 'iPhone 15 Pro Max',
|
48
|
-
);
|
49
|
-
if (!iphone15Max) {
|
50
|
-
throw new Error('iPhone 15 Pro Max not found');
|
51
|
-
} else {
|
52
|
-
const udid = iphone15Max.udid;
|
53
|
-
await $`xcrun simctl boot ${udid}`;
|
54
|
-
}
|
55
|
-
}
|
62
|
+
if (!appContainerPath) {
|
63
|
+
console.write('App not installed on booted device. Installing...');
|
64
|
+
await $`eas build:run --platform ${platform} --path ${output.launchFile}`;
|
56
65
|
}
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
66
|
+
/**
|
67
|
+
* In dev mode we use a debug build, which requires a metro server to serve
|
68
|
+
* the Javascript bundle.
|
69
|
+
*
|
70
|
+
* To avoid the, "Could not find metro server" error screen on launch,
|
71
|
+
* we delay the launch of the app until after the metro server has started.
|
72
|
+
*/
|
62
73
|
}
|
63
|
-
}
|
64
74
|
|
65
|
-
|
75
|
+
sleep(3000).then(async () => {
|
76
|
+
/**
|
77
|
+
* Launch the app on the booted device
|
78
|
+
* https://github.com/expo/eas-cli?tab=readme-ov-file#eas-buildrun
|
79
|
+
*/
|
80
|
+
await $`eas build:run --platform ${platform} --path ${output.launchFile}`;
|
81
|
+
});
|
66
82
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
83
|
+
console.write('Starting Metro server...');
|
84
|
+
await $`expo start --${platform} --dev-client --localhost --scheme ${scheme} ${extrArgsString}`;
|
85
|
+
} catch (err) {
|
86
|
+
throw err;
|
71
87
|
}
|
72
|
-
|
73
|
-
const extrArgsString = extraArgs.join(' ');
|
74
|
-
|
75
|
-
console.log(`Starting metro server...`);
|
76
|
-
|
77
|
-
await $`expo start --${platform} --dev-client --localhost --scheme ${scheme} ${extrArgsString}`;
|
78
88
|
},
|
79
89
|
};
|
@@ -0,0 +1,35 @@
|
|
1
|
+
class Cocoapods < Formula
|
2
|
+
desc "Dependency manager for Cocoa projects"
|
3
|
+
homepage "https://cocoapods.org/"
|
4
|
+
url "https://github.com/CocoaPods/CocoaPods/archive/refs/tags/1.14.3.tar.gz"
|
5
|
+
sha256 "de05766e5771e0cef7af89f73b0e42a1f1c52a76ce1288592cd9511bcd688a9e"
|
6
|
+
license "MIT"
|
7
|
+
revision 1
|
8
|
+
|
9
|
+
bottle do
|
10
|
+
sha256 cellar: :any, arm64_sonoma: "0fb8e638fb4901b6c578c44ae1af0098a0b3530e7a339bf43f2fb67f2819d412"
|
11
|
+
sha256 cellar: :any, arm64_ventura: "e3d0c8624df429cb30c5cf818f3a358d4f678b374410e9fbc8fde090889f9b61"
|
12
|
+
sha256 cellar: :any, arm64_monterey: "a6df519bae3f51b1609cfcd017b4d47cb688200780ffb9b27d57a5dc05ea93de"
|
13
|
+
sha256 cellar: :any, sonoma: "5c2ee41824fcb154b46f9fa967f203fbf9009d2051f8c898375d69d333052988"
|
14
|
+
sha256 cellar: :any, ventura: "91459cb108161201a81fdd0e96a126e9843be8213112c208051e8e72ce9736f9"
|
15
|
+
sha256 cellar: :any, monterey: "316b0954e21f76c013d8c581c589e4f884231687eb2253a9f9a38a77a87728a6"
|
16
|
+
sha256 cellar: :any_skip_relocation, x86_64_linux: "2d5be1290e8161d9a49b3fd191fc8423aac29f61fbc84148c8ba08cdc03d8d84"
|
17
|
+
end
|
18
|
+
|
19
|
+
depends_on "pkg-config" => :build
|
20
|
+
depends_on "ruby"
|
21
|
+
uses_from_macos "libffi", since: :catalina
|
22
|
+
|
23
|
+
def install
|
24
|
+
ENV["GEM_HOME"] = libexec
|
25
|
+
system "gem", "build", "cocoapods.gemspec"
|
26
|
+
system "gem", "install", "cocoapods-#{version}.gem"
|
27
|
+
# Other executables don't work currently.
|
28
|
+
bin.install libexec/"bin/pod", libexec/"bin/xcodeproj"
|
29
|
+
bin.env_script_all_files(libexec/"bin", GEM_HOME: ENV["GEM_HOME"])
|
30
|
+
end
|
31
|
+
|
32
|
+
test do
|
33
|
+
system "#{bin}/pod", "list"
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
import { Props, spinStart, spinStop } from 'bluebun';
|
2
|
+
|
3
|
+
import { purge } from '../utils/purgeCSS';
|
4
|
+
|
5
|
+
export default {
|
6
|
+
name: 'purge',
|
7
|
+
description: `Purge unused CSS`,
|
8
|
+
run: async (props: Props) => {
|
9
|
+
spinStart('Purging css...');
|
10
|
+
|
11
|
+
await purge();
|
12
|
+
|
13
|
+
spinStop('✅ Purging css done!');
|
14
|
+
},
|
15
|
+
};
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import { Props } from 'bluebun';
|
2
|
-
import { setupConfigWorker } from '
|
3
|
-
import { SyncOptions } from '
|
2
|
+
import { setupConfigWorker } from '../utils/setupConfigWorker';
|
3
|
+
import { SyncOptions } from '../utils/types';
|
4
4
|
|
5
5
|
interface SyncProps extends Props {
|
6
6
|
options: SyncOptions;
|