@nx/expo 22.2.0-beta.2 → 22.2.0-beta.4
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/migrations.json +109 -0
- package/package.json +8 -7
- package/plugins/with-nx-metro.d.ts +1 -1
- package/plugins/with-nx-metro.d.ts.map +1 -1
- package/plugins/with-nx-metro.js +1 -1
- package/src/generators/application/application.js +1 -1
- package/src/generators/application/files/nx-welcome/claimed/src/app/App.tsx.template +7 -10
- package/src/generators/application/files/nx-welcome/not-configured/src/app/App.tsx.template +7 -10
- package/src/generators/application/files/nx-welcome/unclaimed/src/app/App.tsx.template +7 -10
- package/src/generators/init/init.d.ts +1 -1
- package/src/generators/init/init.d.ts.map +1 -1
- package/src/generators/init/init.js +11 -9
- package/src/generators/library/library.d.ts.map +1 -1
- package/src/generators/library/library.js +7 -6
- package/src/migrations/update-22-2-0/add-expo-system-ui.d.ts +8 -0
- package/src/migrations/update-22-2-0/add-expo-system-ui.d.ts.map +1 -0
- package/src/migrations/update-22-2-0/add-expo-system-ui.js +48 -0
- package/src/migrations/update-22-2-0/create-ai-instructions-for-expo-54.d.ts +3 -0
- package/src/migrations/update-22-2-0/create-ai-instructions-for-expo-54.d.ts.map +1 -0
- package/src/migrations/update-22-2-0/create-ai-instructions-for-expo-54.js +16 -0
- package/src/migrations/update-22-2-0/files/ai-instructions-for-expo-54.md +519 -0
- package/src/migrations/update-22-2-0/update-jest-for-expo-54.d.ts +12 -0
- package/src/migrations/update-22-2-0/update-jest-for-expo-54.d.ts.map +1 -0
- package/src/migrations/update-22-2-0/update-jest-for-expo-54.js +150 -0
- package/src/utils/ensure-dependencies.d.ts +1 -1
- package/src/utils/ensure-dependencies.d.ts.map +1 -1
- package/src/utils/ensure-dependencies.js +16 -15
- package/src/utils/jest/add-jest.d.ts.map +1 -1
- package/src/utils/jest/add-jest.js +35 -10
- package/src/utils/version-utils.d.ts +48 -0
- package/src/utils/version-utils.d.ts.map +1 -0
- package/src/utils/version-utils.js +130 -0
- package/src/utils/versions.d.ts +46 -16
- package/src/utils/versions.d.ts.map +1 -1
- package/src/utils/versions.js +51 -17
|
@@ -0,0 +1,519 @@
|
|
|
1
|
+
# Expo SDK 54 Migration Instructions for LLM
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
These instructions guide you through migrating an Nx workspace containing Expo projects from Expo SDK 53 to Expo SDK 54. Work systematically through each breaking change category.
|
|
6
|
+
|
|
7
|
+
## Pre-Migration Checklist
|
|
8
|
+
|
|
9
|
+
1. **Identify all Expo projects**:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
nx show projects --with-target start
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
2. **Locate all Expo configuration files**:
|
|
16
|
+
|
|
17
|
+
- Search for `app.json` or `app.config.{js,ts}`
|
|
18
|
+
- Search for `metro.config.{js,ts}`
|
|
19
|
+
- Check `project.json` files for Expo-related configuration
|
|
20
|
+
|
|
21
|
+
3. **Identify affected code**:
|
|
22
|
+
|
|
23
|
+
- Files importing from `expo-av`
|
|
24
|
+
- Files importing from `expo-file-system`
|
|
25
|
+
- Files using `StatusBar` configuration
|
|
26
|
+
- Android-specific layout code
|
|
27
|
+
- Files importing from `@expo/vector-icons`
|
|
28
|
+
|
|
29
|
+
4. **Check for Detox E2E testing projects**:
|
|
30
|
+
- Search for `detox` in package.json dependencies
|
|
31
|
+
- Look for `detox.config.js` or `.detoxrc.js` files
|
|
32
|
+
|
|
33
|
+
## Important Warnings
|
|
34
|
+
|
|
35
|
+
### Detox E2E Testing Not Supported
|
|
36
|
+
|
|
37
|
+
**Expo SDK 54 does not currently support Detox for end-to-end testing.** If your workspace includes Detox projects, be aware of the following:
|
|
38
|
+
|
|
39
|
+
1. **Impact**: E2E tests using Detox will not work after migrating to Expo SDK 54
|
|
40
|
+
2. **Detection**: Check for `detox` in package.json dependencies or projects with `detox.config.js`
|
|
41
|
+
|
|
42
|
+
**Action Required**: If Detox projects are detected, you MUST ask the user before proceeding:
|
|
43
|
+
|
|
44
|
+
> "Your workspace contains Detox E2E tests. Detox is not currently supported in Expo SDK 54. Do you want to proceed with the migration knowing that Detox tests will not work until Detox adds SDK 54 support?"
|
|
45
|
+
|
|
46
|
+
**Alternatives to consider**:
|
|
47
|
+
|
|
48
|
+
- Stay on Expo SDK 53 if Detox E2E testing is critical for your workflow
|
|
49
|
+
- Wait for Detox to add Expo SDK 54 support
|
|
50
|
+
- Consider migrating to [Maestro](https://maestro.mobile.dev/) for E2E testing (has Expo SDK 54 support)
|
|
51
|
+
|
|
52
|
+
## Migration Steps by Category
|
|
53
|
+
|
|
54
|
+
### 1. expo-av to expo-audio and expo-video Migration
|
|
55
|
+
|
|
56
|
+
The `expo-av` package has been deprecated and split into two separate packages: `expo-audio` and `expo-video`.
|
|
57
|
+
|
|
58
|
+
#### 1.1 Audio Migration
|
|
59
|
+
|
|
60
|
+
**Search Pattern**: `import.*from ['"]expo-av['"]` with `Audio` usage
|
|
61
|
+
|
|
62
|
+
**Changes Required**:
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
// BEFORE (Expo SDK 53)
|
|
66
|
+
import { Audio } from 'expo-av';
|
|
67
|
+
|
|
68
|
+
const sound = new Audio.Sound();
|
|
69
|
+
await sound.loadAsync(require('./audio.mp3'));
|
|
70
|
+
await sound.playAsync();
|
|
71
|
+
|
|
72
|
+
// AFTER (Expo SDK 54)
|
|
73
|
+
import { useAudioPlayer } from 'expo-audio';
|
|
74
|
+
|
|
75
|
+
function AudioComponent() {
|
|
76
|
+
const player = useAudioPlayer(require('./audio.mp3'));
|
|
77
|
+
|
|
78
|
+
const play = () => player.play();
|
|
79
|
+
const pause = () => player.pause();
|
|
80
|
+
|
|
81
|
+
return <Button onPress={play} title="Play" />;
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**Action Items**:
|
|
86
|
+
|
|
87
|
+
- [ ] Install `expo-audio`: `npx expo install expo-audio`
|
|
88
|
+
- [ ] Remove `expo-av` if only used for audio
|
|
89
|
+
- [ ] Replace `Audio.Sound` with `useAudioPlayer` hook
|
|
90
|
+
- [ ] Replace `Audio.Recording` with `useAudioRecorder` hook
|
|
91
|
+
- [ ] Update audio playback control methods (`playAsync` -> `play`, etc.)
|
|
92
|
+
- [ ] Convert class-based audio handling to hook-based approach
|
|
93
|
+
|
|
94
|
+
#### 1.2 Video Migration
|
|
95
|
+
|
|
96
|
+
**Search Pattern**: `import.*from ['"]expo-av['"]` with `Video` usage
|
|
97
|
+
|
|
98
|
+
**Changes Required**:
|
|
99
|
+
|
|
100
|
+
```tsx
|
|
101
|
+
// BEFORE (Expo SDK 53)
|
|
102
|
+
import { Video } from 'expo-av';
|
|
103
|
+
|
|
104
|
+
function VideoPlayer() {
|
|
105
|
+
return (
|
|
106
|
+
<Video
|
|
107
|
+
source={{ uri: 'https://example.com/video.mp4' }}
|
|
108
|
+
style={{ width: 300, height: 200 }}
|
|
109
|
+
useNativeControls
|
|
110
|
+
resizeMode="contain"
|
|
111
|
+
/>
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// AFTER (Expo SDK 54)
|
|
116
|
+
import { VideoView, useVideoPlayer } from 'expo-video';
|
|
117
|
+
|
|
118
|
+
function VideoPlayer() {
|
|
119
|
+
const player = useVideoPlayer('https://example.com/video.mp4', (player) => {
|
|
120
|
+
player.loop = true;
|
|
121
|
+
player.play();
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
return (
|
|
125
|
+
<VideoView
|
|
126
|
+
player={player}
|
|
127
|
+
style={{ width: 300, height: 200 }}
|
|
128
|
+
nativeControls
|
|
129
|
+
contentFit="contain"
|
|
130
|
+
/>
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
**Action Items**:
|
|
136
|
+
|
|
137
|
+
- [ ] Install `expo-video`: `npx expo install expo-video`
|
|
138
|
+
- [ ] Remove `expo-av` if only used for video
|
|
139
|
+
- [ ] Replace `Video` component with `VideoView` and `useVideoPlayer`
|
|
140
|
+
- [ ] Replace `resizeMode` prop with `contentFit`
|
|
141
|
+
- [ ] Replace `useNativeControls` prop with `nativeControls`
|
|
142
|
+
- [ ] Update video control methods to use the player instance
|
|
143
|
+
|
|
144
|
+
### 2. expo-file-system Import Path Changes
|
|
145
|
+
|
|
146
|
+
**Search Pattern**: `import.*from ['"]expo-file-system/next['"]`
|
|
147
|
+
|
|
148
|
+
**Changes Required**:
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
// BEFORE (Expo SDK 53)
|
|
152
|
+
import { File, Directory } from 'expo-file-system/next';
|
|
153
|
+
|
|
154
|
+
// AFTER (Expo SDK 54)
|
|
155
|
+
import { File, Directory } from 'expo-file-system';
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
**Action Items**:
|
|
159
|
+
|
|
160
|
+
- [ ] Replace all `expo-file-system/next` imports with `expo-file-system`
|
|
161
|
+
- [ ] Verify API compatibility (the API is now stable)
|
|
162
|
+
|
|
163
|
+
### 3. StatusBar Configuration Removal
|
|
164
|
+
|
|
165
|
+
In Expo SDK 54, the `expo-status-bar` configuration is now handled differently. The old `userInterfaceStyle` in `app.json` affects status bar theming.
|
|
166
|
+
|
|
167
|
+
**Search Pattern**: `userInterfaceStyle` in `app.json` or `app.config.*`
|
|
168
|
+
|
|
169
|
+
**Changes Required**:
|
|
170
|
+
|
|
171
|
+
```json
|
|
172
|
+
// BEFORE (Expo SDK 53)
|
|
173
|
+
{
|
|
174
|
+
"expo": {
|
|
175
|
+
"userInterfaceStyle": "automatic",
|
|
176
|
+
"ios": {
|
|
177
|
+
"userInterfaceStyle": "light"
|
|
178
|
+
},
|
|
179
|
+
"android": {
|
|
180
|
+
"userInterfaceStyle": "dark"
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// AFTER (Expo SDK 54)
|
|
186
|
+
// The userInterfaceStyle is now handled via expo-system-ui
|
|
187
|
+
// For programmatic control, use:
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
```typescript
|
|
191
|
+
// AFTER (Expo SDK 54) - Programmatic control
|
|
192
|
+
import * as SystemUI from 'expo-system-ui';
|
|
193
|
+
|
|
194
|
+
// Set root view background color
|
|
195
|
+
SystemUI.setBackgroundColorAsync('#ffffff');
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
**Action Items**:
|
|
199
|
+
|
|
200
|
+
- [ ] Install `expo-system-ui`: `npx expo install expo-system-ui`
|
|
201
|
+
- [ ] Review `userInterfaceStyle` settings in app.json
|
|
202
|
+
- [ ] Move UI style handling to `expo-system-ui` if programmatic control is needed
|
|
203
|
+
|
|
204
|
+
### 4. Android Edge-to-Edge UI
|
|
205
|
+
|
|
206
|
+
Expo SDK 54 enables edge-to-edge display by default on Android. This means content can extend behind system bars (status bar and navigation bar).
|
|
207
|
+
|
|
208
|
+
**Search Pattern**: Android-specific styles, safe area handling, padding/margin adjustments
|
|
209
|
+
|
|
210
|
+
**Changes Required**:
|
|
211
|
+
|
|
212
|
+
```tsx
|
|
213
|
+
// BEFORE (Expo SDK 53) - Implicit safe area
|
|
214
|
+
function App() {
|
|
215
|
+
return (
|
|
216
|
+
<View style={{ flex: 1 }}>
|
|
217
|
+
<Text>Content</Text>
|
|
218
|
+
</View>
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// AFTER (Expo SDK 54) - Explicit safe area handling
|
|
223
|
+
import { SafeAreaView } from 'react-native-safe-area-context';
|
|
224
|
+
// or
|
|
225
|
+
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
226
|
+
|
|
227
|
+
function App() {
|
|
228
|
+
return (
|
|
229
|
+
<SafeAreaView style={{ flex: 1 }}>
|
|
230
|
+
<Text>Content</Text>
|
|
231
|
+
</SafeAreaView>
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Or with hooks for more control
|
|
236
|
+
function App() {
|
|
237
|
+
const insets = useSafeAreaInsets();
|
|
238
|
+
|
|
239
|
+
return (
|
|
240
|
+
<View
|
|
241
|
+
style={{ flex: 1, paddingTop: insets.top, paddingBottom: insets.bottom }}
|
|
242
|
+
>
|
|
243
|
+
<Text>Content</Text>
|
|
244
|
+
</View>
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
**Action Items**:
|
|
250
|
+
|
|
251
|
+
- [ ] Audit all screen components for safe area handling
|
|
252
|
+
- [ ] Install `react-native-safe-area-context` if not present
|
|
253
|
+
- [ ] Wrap root components with `SafeAreaProvider`
|
|
254
|
+
- [ ] Add `SafeAreaView` or use `useSafeAreaInsets` where content touches screen edges
|
|
255
|
+
- [ ] Test on Android devices/emulators to verify UI doesn't overlap system bars
|
|
256
|
+
- [ ] Pay special attention to:
|
|
257
|
+
- Header components
|
|
258
|
+
- Bottom navigation/tab bars
|
|
259
|
+
- Modal components
|
|
260
|
+
- Full-screen media players
|
|
261
|
+
|
|
262
|
+
### 5. React Native Reanimated Version Decision
|
|
263
|
+
|
|
264
|
+
Expo SDK 54 supports both Reanimated v3 and v4. If you're using New Architecture, you should upgrade to v4.
|
|
265
|
+
|
|
266
|
+
**Search Pattern**: `react-native-reanimated` in package.json, worklet functions
|
|
267
|
+
|
|
268
|
+
**Reanimated v3 (stable)**:
|
|
269
|
+
|
|
270
|
+
```bash
|
|
271
|
+
npx expo install react-native-reanimated@3
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
**Reanimated v4 (recommended for New Architecture)**:
|
|
275
|
+
|
|
276
|
+
```bash
|
|
277
|
+
npx expo install react-native-reanimated@4
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
**Action Items**:
|
|
281
|
+
|
|
282
|
+
- [ ] Check if New Architecture is enabled in your project
|
|
283
|
+
- [ ] If using New Architecture, upgrade to Reanimated v4
|
|
284
|
+
- [ ] If staying on old architecture, Reanimated v3 is fine
|
|
285
|
+
- [ ] Test all animations after the upgrade
|
|
286
|
+
|
|
287
|
+
### 6. @expo/vector-icons Validation
|
|
288
|
+
|
|
289
|
+
Some icons in `@expo/vector-icons` may have been renamed or removed in SDK 54.
|
|
290
|
+
|
|
291
|
+
**Search Pattern**: `import.*from ['"]@expo/vector-icons['"]`
|
|
292
|
+
|
|
293
|
+
**Action Items**:
|
|
294
|
+
|
|
295
|
+
- [ ] Run the app and check console for warnings about missing icons
|
|
296
|
+
- [ ] Search for icon names that may have changed
|
|
297
|
+
- [ ] Update icon names as needed
|
|
298
|
+
- [ ] Consider using the Expo Vector Icons directory to find replacements: https://icons.expo.fyi/
|
|
299
|
+
|
|
300
|
+
### 7. React 19.1 Compatibility
|
|
301
|
+
|
|
302
|
+
Expo SDK 54 uses React 19.1 and React Native 0.81.
|
|
303
|
+
|
|
304
|
+
**Search Pattern**: `React.FC`, deprecated lifecycle methods, legacy context API
|
|
305
|
+
|
|
306
|
+
**Changes Required**:
|
|
307
|
+
|
|
308
|
+
```typescript
|
|
309
|
+
// BEFORE - React.FC (discouraged in React 19)
|
|
310
|
+
const MyComponent: React.FC<Props> = ({ title }) => {
|
|
311
|
+
return <Text>{title}</Text>;
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
// AFTER - Direct function typing
|
|
315
|
+
function MyComponent({ title }: Props) {
|
|
316
|
+
return <Text>{title}</Text>;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// Or with explicit return type
|
|
320
|
+
const MyComponent = ({ title }: Props): React.ReactElement => {
|
|
321
|
+
return <Text>{title}</Text>;
|
|
322
|
+
};
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
**Action Items**:
|
|
326
|
+
|
|
327
|
+
- [ ] Update TypeScript types for React 19.1 (`@types/react@~19.1.0`)
|
|
328
|
+
- [ ] Remove usage of `React.FC` pattern (optional but recommended)
|
|
329
|
+
- [ ] Check for deprecated lifecycle methods and update to hooks
|
|
330
|
+
- [ ] Verify third-party libraries are compatible with React 19.1
|
|
331
|
+
|
|
332
|
+
### 8. Metro Configuration Updates
|
|
333
|
+
|
|
334
|
+
Expo SDK 54 uses Metro 0.83 with updated configuration.
|
|
335
|
+
|
|
336
|
+
**Search Pattern**: `metro.config.{js,ts}`
|
|
337
|
+
|
|
338
|
+
**Changes Required**:
|
|
339
|
+
|
|
340
|
+
```javascript
|
|
341
|
+
// BEFORE (Expo SDK 53)
|
|
342
|
+
const { getDefaultConfig } = require('@expo/metro-config');
|
|
343
|
+
|
|
344
|
+
const config = getDefaultConfig(__dirname);
|
|
345
|
+
|
|
346
|
+
// AFTER (Expo SDK 54) - Same API, but verify compatibility
|
|
347
|
+
const { getDefaultConfig } = require('@expo/metro-config');
|
|
348
|
+
|
|
349
|
+
const config = getDefaultConfig(__dirname);
|
|
350
|
+
|
|
351
|
+
// Ensure any custom transformers are compatible with Metro 0.83
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
**Action Items**:
|
|
355
|
+
|
|
356
|
+
- [ ] Update `@expo/metro-config` to `~0.22.0`
|
|
357
|
+
- [ ] Update `metro-config` to `~0.83.0`
|
|
358
|
+
- [ ] Update `metro-resolver` to `~0.83.0`
|
|
359
|
+
- [ ] Test custom Metro plugins/transformers for compatibility
|
|
360
|
+
|
|
361
|
+
### 9. Babel Configuration Cleanup
|
|
362
|
+
|
|
363
|
+
Expo SDK 54 updates to `babel-preset-expo@~14.0.0`.
|
|
364
|
+
|
|
365
|
+
**Search Pattern**: `babel.config.js`, `.babelrc`
|
|
366
|
+
|
|
367
|
+
**Action Items**:
|
|
368
|
+
|
|
369
|
+
- [ ] Update `babel-preset-expo` to `~14.0.0`
|
|
370
|
+
- [ ] Remove any deprecated Babel plugins
|
|
371
|
+
- [ ] Clear Metro cache after Babel changes: `npx expo start --clear`
|
|
372
|
+
|
|
373
|
+
## Post-Migration Validation
|
|
374
|
+
|
|
375
|
+
### 1. Clear All Caches
|
|
376
|
+
|
|
377
|
+
```bash
|
|
378
|
+
# Clear Expo cache
|
|
379
|
+
npx expo start --clear
|
|
380
|
+
|
|
381
|
+
# Clear Metro bundler cache
|
|
382
|
+
rm -rf node_modules/.cache/metro-*
|
|
383
|
+
|
|
384
|
+
# Clear Nx cache if needed
|
|
385
|
+
nx reset
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
### 2. Run Tests Per Project
|
|
389
|
+
|
|
390
|
+
```bash
|
|
391
|
+
# Test each project individually
|
|
392
|
+
nx run-many -t test -p PROJECT_NAME
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
### 3. Run All Tests
|
|
396
|
+
|
|
397
|
+
```bash
|
|
398
|
+
# Run tests across all affected projects
|
|
399
|
+
nx affected -t test
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
### 4. Test on Device/Simulator
|
|
403
|
+
|
|
404
|
+
```bash
|
|
405
|
+
# iOS
|
|
406
|
+
nx run PROJECT_NAME:run-ios
|
|
407
|
+
|
|
408
|
+
# Android
|
|
409
|
+
nx run PROJECT_NAME:run-android
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
### 5. Review Migration Checklist
|
|
413
|
+
|
|
414
|
+
- [ ] All `expo-av` usages migrated to `expo-audio` or `expo-video`
|
|
415
|
+
- [ ] All `expo-file-system/next` imports updated
|
|
416
|
+
- [ ] Safe area handling verified on Android
|
|
417
|
+
- [ ] All icon references validated
|
|
418
|
+
- [ ] React 19.1 compatibility verified
|
|
419
|
+
- [ ] Metro and Babel configurations updated
|
|
420
|
+
- [ ] All tests pass
|
|
421
|
+
- [ ] App runs on iOS simulator/device
|
|
422
|
+
- [ ] App runs on Android emulator/device
|
|
423
|
+
|
|
424
|
+
## Common Issues and Solutions
|
|
425
|
+
|
|
426
|
+
### Issue: Audio playback stops when component unmounts
|
|
427
|
+
|
|
428
|
+
**Solution**: The new `useAudioPlayer` hook manages cleanup automatically. If you need persistent audio, consider using a context or state management solution.
|
|
429
|
+
|
|
430
|
+
### Issue: Video player shows black screen
|
|
431
|
+
|
|
432
|
+
**Solution**: Ensure you're using `useVideoPlayer` with `VideoView`. Check that the video source URL is correct and accessible.
|
|
433
|
+
|
|
434
|
+
### Issue: Content hidden behind Android navigation bar
|
|
435
|
+
|
|
436
|
+
**Solution**: Wrap your screen content with `SafeAreaView` from `react-native-safe-area-context` or use `useSafeAreaInsets` for custom padding.
|
|
437
|
+
|
|
438
|
+
### Issue: Missing icons after upgrade
|
|
439
|
+
|
|
440
|
+
**Solution**: Check the Expo Vector Icons directory for renamed icons: https://icons.expo.fyi/
|
|
441
|
+
|
|
442
|
+
### Issue: TypeScript errors with React 19.1
|
|
443
|
+
|
|
444
|
+
**Solution**: Update `@types/react` to `~19.1.0` and check for deprecated patterns.
|
|
445
|
+
|
|
446
|
+
### Issue: Metro bundler fails to start
|
|
447
|
+
|
|
448
|
+
**Solution**: Clear all caches with `npx expo start --clear` and ensure Metro packages are at compatible versions.
|
|
449
|
+
|
|
450
|
+
## Files to Review
|
|
451
|
+
|
|
452
|
+
Create a checklist of all files that need review:
|
|
453
|
+
|
|
454
|
+
```bash
|
|
455
|
+
# Configuration files
|
|
456
|
+
find . -name "app.json" -o -name "app.config.*"
|
|
457
|
+
find . -name "metro.config.*"
|
|
458
|
+
find . -name "babel.config.*"
|
|
459
|
+
|
|
460
|
+
# Files with expo-av imports
|
|
461
|
+
rg "from ['\"]expo-av['\"]" --type ts --type tsx --type js
|
|
462
|
+
|
|
463
|
+
# Files with expo-file-system/next imports
|
|
464
|
+
rg "from ['\"]expo-file-system/next['\"]" --type ts --type tsx --type js
|
|
465
|
+
|
|
466
|
+
# Files with vector-icons imports
|
|
467
|
+
rg "from ['\"]@expo/vector-icons['\"]" --type ts --type tsx --type js
|
|
468
|
+
|
|
469
|
+
# Safe area related files
|
|
470
|
+
rg "SafeAreaView|useSafeAreaInsets" --type ts --type tsx --type js
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
## Migration Strategy for Large Workspaces
|
|
474
|
+
|
|
475
|
+
1. **Migrate in phases**: Start with a small project, validate, then expand
|
|
476
|
+
2. **Use feature branches**: Create separate branches for different migration aspects
|
|
477
|
+
3. **Run tests frequently**: After each configuration change, run affected tests
|
|
478
|
+
4. **Document issues**: Keep track of project-specific issues and solutions
|
|
479
|
+
5. **Test on real devices**: Android edge-to-edge changes require device testing
|
|
480
|
+
|
|
481
|
+
## Useful Commands During Migration
|
|
482
|
+
|
|
483
|
+
```bash
|
|
484
|
+
# Find all Expo projects
|
|
485
|
+
nx show projects --with-target start
|
|
486
|
+
|
|
487
|
+
# Run specific project
|
|
488
|
+
nx start PROJECT_NAME
|
|
489
|
+
|
|
490
|
+
# Test specific project after changes
|
|
491
|
+
nx test PROJECT_NAME
|
|
492
|
+
|
|
493
|
+
# Test all affected
|
|
494
|
+
nx affected -t test
|
|
495
|
+
|
|
496
|
+
# View project details
|
|
497
|
+
nx show project PROJECT_NAME --web
|
|
498
|
+
|
|
499
|
+
# Clear Nx cache if needed
|
|
500
|
+
nx reset
|
|
501
|
+
|
|
502
|
+
# Clear Expo cache
|
|
503
|
+
npx expo start --clear
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
---
|
|
507
|
+
|
|
508
|
+
## Notes for LLM Execution
|
|
509
|
+
|
|
510
|
+
When executing this migration:
|
|
511
|
+
|
|
512
|
+
1. **Work systematically**: Complete one category before moving to the next
|
|
513
|
+
2. **Test after each change**: Don't batch all changes without validation
|
|
514
|
+
3. **Keep user informed**: Report progress through each section
|
|
515
|
+
4. **Handle errors promptly**: If tests fail, fix immediately before proceeding
|
|
516
|
+
5. **Update documentation**: Note any workspace-specific patterns or issues
|
|
517
|
+
6. **Create meaningful commits**: Group related changes together with clear messages
|
|
518
|
+
7. **Use TodoWrite tool**: Track migration progress for visibility
|
|
519
|
+
8. **Test on both platforms**: Expo changes often affect iOS and Android differently
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Tree } from '@nx/devkit';
|
|
2
|
+
/**
|
|
3
|
+
* Update Jest configuration for Expo SDK 54.
|
|
4
|
+
*
|
|
5
|
+
* Expo 54 requires a different approach for Jest configuration:
|
|
6
|
+
* - Remove the custom resolver from jest.config
|
|
7
|
+
* - Delete the jest.resolver.js file
|
|
8
|
+
* - Add ImportMetaRegistry mock and structuredClone polyfill to test-setup.ts
|
|
9
|
+
* - Update tsconfig files to remove jest.resolver.js references
|
|
10
|
+
*/
|
|
11
|
+
export default function update(tree: Tree): Promise<void>;
|
|
12
|
+
//# sourceMappingURL=update-jest-for-expo-54.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update-jest-for-expo-54.d.ts","sourceRoot":"","sources":["../../../../../../packages/expo/src/migrations/update-22-2-0/update-jest-for-expo-54.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,IAAI,EAOL,MAAM,YAAY,CAAC;AAIpB;;;;;;;;GAQG;AACH,wBAA8B,MAAM,CAAC,IAAI,EAAE,IAAI,iBA6C9C"}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.default = update;
|
|
4
|
+
const devkit_1 = require("@nx/devkit");
|
|
5
|
+
const jest_1 = require("@nx/jest");
|
|
6
|
+
const path_1 = require("path");
|
|
7
|
+
/**
|
|
8
|
+
* Update Jest configuration for Expo SDK 54.
|
|
9
|
+
*
|
|
10
|
+
* Expo 54 requires a different approach for Jest configuration:
|
|
11
|
+
* - Remove the custom resolver from jest.config
|
|
12
|
+
* - Delete the jest.resolver.js file
|
|
13
|
+
* - Add ImportMetaRegistry mock and structuredClone polyfill to test-setup.ts
|
|
14
|
+
* - Update tsconfig files to remove jest.resolver.js references
|
|
15
|
+
*/
|
|
16
|
+
async function update(tree) {
|
|
17
|
+
const projects = (0, devkit_1.getProjects)(tree);
|
|
18
|
+
for (const [projectName, config] of projects.entries()) {
|
|
19
|
+
if (!isExpoProject(tree, config.root)) {
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
// Check if this project has Jest configured
|
|
23
|
+
const jestConfigPath = findJestConfigPath(tree, config.root);
|
|
24
|
+
if (!jestConfigPath) {
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
const jestConfigContent = tree.read(jestConfigPath, 'utf-8');
|
|
28
|
+
// Only process if this is an Expo project with jest-expo preset and custom resolver
|
|
29
|
+
if (!jestConfigContent.includes('jest-expo') ||
|
|
30
|
+
!jestConfigContent.includes('jest.resolver.js')) {
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
// Remove resolver property from jest.config using AST
|
|
34
|
+
(0, jest_1.removePropertyFromJestConfig)(tree, jestConfigPath, 'resolver');
|
|
35
|
+
// Delete jest.resolver.js file
|
|
36
|
+
const resolverPath = (0, path_1.join)(config.root, 'jest.resolver.js');
|
|
37
|
+
if (tree.exists(resolverPath)) {
|
|
38
|
+
tree.delete(resolverPath);
|
|
39
|
+
}
|
|
40
|
+
// Update test-setup.ts with new mocks
|
|
41
|
+
updateTestSetup(tree, config.root);
|
|
42
|
+
// Update tsconfig files to remove jest.resolver.js references
|
|
43
|
+
updateTsConfigFilesForV54(tree, config.root);
|
|
44
|
+
devkit_1.logger.info(`Updated Jest configuration for ${projectName} to support Expo SDK 54`);
|
|
45
|
+
}
|
|
46
|
+
await (0, devkit_1.formatFiles)(tree);
|
|
47
|
+
}
|
|
48
|
+
function findJestConfigPath(tree, projectRoot) {
|
|
49
|
+
const possiblePaths = [
|
|
50
|
+
(0, path_1.join)(projectRoot, 'jest.config.ts'),
|
|
51
|
+
(0, path_1.join)(projectRoot, 'jest.config.cts'),
|
|
52
|
+
(0, path_1.join)(projectRoot, 'jest.config.js'),
|
|
53
|
+
];
|
|
54
|
+
for (const configPath of possiblePaths) {
|
|
55
|
+
if (tree.exists(configPath)) {
|
|
56
|
+
return configPath;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
function updateTestSetup(tree, projectRoot) {
|
|
62
|
+
const testSetupTsPath = (0, path_1.join)(projectRoot, 'src/test-setup.ts');
|
|
63
|
+
const testSetupJsPath = (0, path_1.join)(projectRoot, 'src/test-setup.js');
|
|
64
|
+
let testSetupPath = testSetupTsPath;
|
|
65
|
+
if (!tree.exists(testSetupTsPath)) {
|
|
66
|
+
if (tree.exists(testSetupJsPath)) {
|
|
67
|
+
testSetupPath = testSetupJsPath;
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
// Create test-setup.ts if it doesn't exist
|
|
71
|
+
tree.write(testSetupPath, '');
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
let existingContent = tree.read(testSetupPath, 'utf-8') || '';
|
|
75
|
+
// Add ImportMetaRegistry mock if not already present
|
|
76
|
+
if (!existingContent.includes('ImportMetaRegistry')) {
|
|
77
|
+
const importMetaRegistryMock = `jest.mock('expo/src/winter/ImportMetaRegistry', () => ({
|
|
78
|
+
ImportMetaRegistry: {
|
|
79
|
+
get url() {
|
|
80
|
+
return null;
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
}));
|
|
84
|
+
|
|
85
|
+
`;
|
|
86
|
+
existingContent = importMetaRegistryMock + existingContent;
|
|
87
|
+
}
|
|
88
|
+
// Add structuredClone polyfill if not already present
|
|
89
|
+
if (!existingContent.includes('structuredClone')) {
|
|
90
|
+
const structuredClonePolyfill = `if (typeof global.structuredClone === 'undefined') {
|
|
91
|
+
global.structuredClone = (object) => JSON.parse(JSON.stringify(object));
|
|
92
|
+
}
|
|
93
|
+
`;
|
|
94
|
+
existingContent = existingContent + '\n' + structuredClonePolyfill;
|
|
95
|
+
}
|
|
96
|
+
tree.write(testSetupPath, existingContent);
|
|
97
|
+
}
|
|
98
|
+
function updateTsConfigFilesForV54(tree, projectRoot) {
|
|
99
|
+
// Update main tsconfig (app or lib) to remove jest.resolver.js from excludes
|
|
100
|
+
const mainTsConfigFiles = [
|
|
101
|
+
'tsconfig.app.json',
|
|
102
|
+
'tsconfig.lib.json',
|
|
103
|
+
'tsconfig.json',
|
|
104
|
+
];
|
|
105
|
+
for (const configFile of mainTsConfigFiles) {
|
|
106
|
+
const configPath = (0, path_1.join)(projectRoot, configFile);
|
|
107
|
+
if (tree.exists(configPath)) {
|
|
108
|
+
try {
|
|
109
|
+
(0, devkit_1.updateJson)(tree, configPath, (json) => {
|
|
110
|
+
if (json.exclude && Array.isArray(json.exclude)) {
|
|
111
|
+
json.exclude = json.exclude.filter((item) => item !== 'jest.resolver.js');
|
|
112
|
+
}
|
|
113
|
+
return json;
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
// Skip if JSON is invalid
|
|
118
|
+
}
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
// Update tsconfig.spec.json to remove jest.resolver.js from includes
|
|
123
|
+
const specTsConfigPath = (0, path_1.join)(projectRoot, 'tsconfig.spec.json');
|
|
124
|
+
if (tree.exists(specTsConfigPath)) {
|
|
125
|
+
try {
|
|
126
|
+
(0, devkit_1.updateJson)(tree, specTsConfigPath, (json) => {
|
|
127
|
+
if (json.include && Array.isArray(json.include)) {
|
|
128
|
+
json.include = json.include.filter((item) => item !== 'jest.resolver.js');
|
|
129
|
+
}
|
|
130
|
+
return json;
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
// Skip if JSON is invalid
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
function isExpoProject(tree, projectRoot) {
|
|
139
|
+
const packageJsonPath = (0, devkit_1.joinPathFragments)(projectRoot, 'package.json');
|
|
140
|
+
if (!tree.exists(packageJsonPath)) {
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
try {
|
|
144
|
+
const packageJson = (0, devkit_1.readJson)(tree, packageJsonPath);
|
|
145
|
+
return Boolean(packageJson.dependencies?.expo || packageJson.devDependencies?.expo);
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { type GeneratorCallback, type Tree } from '@nx/devkit';
|
|
2
|
-
export declare function ensureDependencies(host: Tree, unitTestRunner: 'jest' | 'none'): GeneratorCallback
|
|
2
|
+
export declare function ensureDependencies(host: Tree, unitTestRunner: 'jest' | 'none'): Promise<GeneratorCallback>;
|
|
3
3
|
//# sourceMappingURL=ensure-dependencies.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ensure-dependencies.d.ts","sourceRoot":"","sources":["../../../../../packages/expo/src/utils/ensure-dependencies.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,iBAAiB,EACtB,KAAK,IAAI,EACV,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"ensure-dependencies.d.ts","sourceRoot":"","sources":["../../../../../packages/expo/src/utils/ensure-dependencies.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,iBAAiB,EACtB,KAAK,IAAI,EACV,MAAM,YAAY,CAAC;AAGpB,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,IAAI,EACV,cAAc,EAAE,MAAM,GAAG,MAAM,GAC9B,OAAO,CAAC,iBAAiB,CAAC,CAiC5B"}
|