@expo/cli 1.0.0-canary-20250404-3c3b5fd → 1.0.0-canary-20250701-6a945c5

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.
Files changed (182) hide show
  1. package/README.md +33 -24
  2. package/build/bin/cli +1 -1
  3. package/build/metro-require/require.js +6 -4
  4. package/build/src/api/user/actions.js +25 -11
  5. package/build/src/api/user/actions.js.map +1 -1
  6. package/build/src/customize/templates.js +15 -1
  7. package/build/src/customize/templates.js.map +1 -1
  8. package/build/src/export/exportApp.js +26 -14
  9. package/build/src/export/exportApp.js.map +1 -1
  10. package/build/src/export/exportAsync.js +6 -0
  11. package/build/src/export/exportAsync.js.map +1 -1
  12. package/build/src/export/exportHermes.js +2 -2
  13. package/build/src/export/exportHermes.js.map +1 -1
  14. package/build/src/export/persistMetroAssets.js.map +1 -1
  15. package/build/src/install/checkPackages.js +22 -4
  16. package/build/src/install/checkPackages.js.map +1 -1
  17. package/build/src/install/index.js +3 -1
  18. package/build/src/install/index.js.map +1 -1
  19. package/build/src/install/resolveOptions.js +7 -2
  20. package/build/src/install/resolveOptions.js.map +1 -1
  21. package/build/src/install/utils/checkPackagesCompatibility.js +1 -1
  22. package/build/src/install/utils/checkPackagesCompatibility.js.map +1 -1
  23. package/build/src/lint/ESlintPrerequisite.js +32 -48
  24. package/build/src/lint/ESlintPrerequisite.js.map +1 -1
  25. package/build/src/lint/index.js +45 -47
  26. package/build/src/lint/index.js.map +1 -1
  27. package/build/src/lint/lintAsync.js +150 -4
  28. package/build/src/lint/lintAsync.js.map +1 -1
  29. package/build/src/lint/resolveOptions.js +115 -0
  30. package/build/src/lint/resolveOptions.js.map +1 -0
  31. package/build/src/prebuild/renameTemplateAppName.js +4 -1
  32. package/build/src/prebuild/renameTemplateAppName.js.map +1 -1
  33. package/build/src/prebuild/resolveTemplate.js +4 -4
  34. package/build/src/prebuild/resolveTemplate.js.map +1 -1
  35. package/build/src/prebuild/updatePackageJson.js +19 -9
  36. package/build/src/prebuild/updatePackageJson.js.map +1 -1
  37. package/build/src/run/android/resolveOptions.js +13 -1
  38. package/build/src/run/android/resolveOptions.js.map +1 -1
  39. package/build/src/run/android/runAndroidAsync.js +39 -17
  40. package/build/src/run/android/runAndroidAsync.js.map +1 -1
  41. package/build/src/run/ios/XcodeBuild.js +3 -3
  42. package/build/src/run/ios/XcodeBuild.js.map +1 -1
  43. package/build/src/run/ios/options/resolveOptions.js +13 -1
  44. package/build/src/run/ios/options/resolveOptions.js.map +1 -1
  45. package/build/src/run/ios/runIosAsync.js +38 -7
  46. package/build/src/run/ios/runIosAsync.js.map +1 -1
  47. package/build/src/start/doctor/SecurityBinPrerequisite.js +1 -1
  48. package/build/src/start/doctor/SecurityBinPrerequisite.js.map +1 -1
  49. package/build/src/start/doctor/apple/XcodePrerequisite.js +1 -1
  50. package/build/src/start/doctor/apple/XcodePrerequisite.js.map +1 -1
  51. package/build/src/start/doctor/dependencies/ensureDependenciesAsync.js +1 -1
  52. package/build/src/start/doctor/dependencies/ensureDependenciesAsync.js.map +1 -1
  53. package/build/src/start/doctor/dependencies/resolvePackages.js +1 -1
  54. package/build/src/start/doctor/dependencies/resolvePackages.js.map +1 -1
  55. package/build/src/start/doctor/ngrok/ExternalModule.js +1 -1
  56. package/build/src/start/doctor/ngrok/ExternalModule.js.map +1 -1
  57. package/build/src/start/index.js +1 -1
  58. package/build/src/start/index.js.map +1 -1
  59. package/build/src/start/platforms/PlatformManager.js +1 -1
  60. package/build/src/start/platforms/PlatformManager.js.map +1 -1
  61. package/build/src/start/platforms/android/AndroidPlatformManager.js +1 -1
  62. package/build/src/start/platforms/android/AndroidPlatformManager.js.map +1 -1
  63. package/build/src/start/platforms/android/getDevices.js +1 -1
  64. package/build/src/start/platforms/android/getDevices.js.map +1 -1
  65. package/build/src/start/platforms/ios/AppleDeviceManager.js +1 -1
  66. package/build/src/start/platforms/ios/AppleDeviceManager.js.map +1 -1
  67. package/build/src/start/platforms/ios/xcrun.js +1 -1
  68. package/build/src/start/platforms/ios/xcrun.js.map +1 -1
  69. package/build/src/start/project/dotExpo.js +5 -0
  70. package/build/src/start/project/dotExpo.js.map +1 -1
  71. package/build/src/start/resolveOptions.js +3 -0
  72. package/build/src/start/resolveOptions.js.map +1 -1
  73. package/build/src/start/server/metro/MetroBundlerDevServer.js +38 -26
  74. package/build/src/start/server/metro/MetroBundlerDevServer.js.map +1 -1
  75. package/build/src/start/server/metro/MetroTerminalReporter.js +29 -2
  76. package/build/src/start/server/metro/MetroTerminalReporter.js.map +1 -1
  77. package/build/src/start/server/metro/createExpoFallbackResolver.js +6 -4
  78. package/build/src/start/server/metro/createExpoFallbackResolver.js.map +1 -1
  79. package/build/src/start/server/metro/createJResolver.js +2 -2
  80. package/build/src/start/server/metro/createJResolver.js.map +1 -1
  81. package/build/src/start/server/metro/createServerComponentsMiddleware.js +16 -5
  82. package/build/src/start/server/metro/createServerComponentsMiddleware.js.map +1 -1
  83. package/build/src/start/server/metro/debugging/createDebugMiddleware.js +19 -19
  84. package/build/src/start/server/metro/debugging/createDebugMiddleware.js.map +1 -1
  85. package/build/src/start/server/metro/externals.js +1 -1
  86. package/build/src/start/server/metro/externals.js.map +1 -1
  87. package/build/src/start/server/metro/instantiateMetro.js +13 -8
  88. package/build/src/start/server/metro/instantiateMetro.js.map +1 -1
  89. package/build/src/start/server/metro/log-box/LogBoxSymbolication.js +21 -2
  90. package/build/src/start/server/metro/log-box/LogBoxSymbolication.js.map +1 -1
  91. package/build/src/start/server/metro/log-box/formatProjectFilePath.js +15 -12
  92. package/build/src/start/server/metro/log-box/formatProjectFilePath.js.map +1 -1
  93. package/build/src/start/server/metro/metroErrorInterface.js +19 -8
  94. package/build/src/start/server/metro/metroErrorInterface.js.map +1 -1
  95. package/build/src/start/server/metro/runServer-fork.js +1 -1
  96. package/build/src/start/server/metro/runServer-fork.js.map +1 -1
  97. package/build/src/start/server/metro/withMetroMultiPlatform.js +7 -12
  98. package/build/src/start/server/metro/withMetroMultiPlatform.js.map +1 -1
  99. package/build/src/start/server/middleware/CorsMiddleware.js +1 -1
  100. package/build/src/start/server/middleware/CorsMiddleware.js.map +1 -1
  101. package/build/src/start/server/middleware/ManifestMiddleware.js +4 -8
  102. package/build/src/start/server/middleware/ManifestMiddleware.js.map +1 -1
  103. package/build/src/start/server/middleware/inspector/JsInspector.js +2 -25
  104. package/build/src/start/server/middleware/inspector/JsInspector.js.map +1 -1
  105. package/build/src/start/server/middleware/metroOptions.js +2 -26
  106. package/build/src/start/server/middleware/metroOptions.js.map +1 -1
  107. package/build/src/utils/build-cache-providers/helpers.js +61 -0
  108. package/build/src/utils/build-cache-providers/helpers.js.map +1 -0
  109. package/build/src/utils/build-cache-providers/index.js +283 -0
  110. package/build/src/utils/build-cache-providers/index.js.map +1 -0
  111. package/build/src/utils/codesigning.js +14 -2
  112. package/build/src/utils/codesigning.js.map +1 -1
  113. package/build/src/utils/exit.js +0 -1
  114. package/build/src/utils/exit.js.map +1 -1
  115. package/build/src/utils/ip.js +7 -104
  116. package/build/src/utils/ip.js.map +1 -1
  117. package/build/src/utils/modifyConfigAsync.js +1 -1
  118. package/build/src/utils/modifyConfigAsync.js.map +1 -1
  119. package/build/src/utils/resolveArgs.js +8 -0
  120. package/build/src/utils/resolveArgs.js.map +1 -1
  121. package/build/src/utils/scheme.js +1 -1
  122. package/build/src/utils/scheme.js.map +1 -1
  123. package/build/src/utils/telemetry/clients/FetchClient.js +2 -2
  124. package/build/src/utils/telemetry/clients/FetchClient.js.map +1 -1
  125. package/build/src/utils/telemetry/utils/context.js +1 -1
  126. package/build/src/utils/tsconfig/evaluateTsConfig.js +7 -2
  127. package/build/src/utils/tsconfig/evaluateTsConfig.js.map +1 -1
  128. package/build/src/utils/variadic.js +63 -6
  129. package/build/src/utils/variadic.js.map +1 -1
  130. package/package.json +20 -20
  131. package/static/canary/react-is/cjs/react-is.development.js +118 -185
  132. package/static/canary/react-is/cjs/react-is.production.js +2 -2
  133. package/static/canary/react-native/Libraries/Renderer/implementations/ReactFabric-dev.js +16582 -26565
  134. package/static/canary/react-native/Libraries/Renderer/implementations/ReactFabric-prod.js +3495 -3357
  135. package/static/canary/react-native/Libraries/Renderer/implementations/ReactFabric-profiling.js +3929 -3801
  136. package/static/canary/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-dev.js +16869 -27032
  137. package/static/canary/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js +3535 -3428
  138. package/static/canary/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.js +4198 -4095
  139. package/static/canary/scheduler/cjs/scheduler-unstable_mock.development.js +387 -684
  140. package/static/canary/scheduler/cjs/scheduler-unstable_mock.production.js +0 -9
  141. package/static/canary/scheduler/cjs/scheduler-unstable_post_task.development.js +137 -195
  142. package/static/canary/scheduler/cjs/scheduler-unstable_post_task.production.js +0 -5
  143. package/static/canary/scheduler/cjs/scheduler.development.js +339 -600
  144. package/static/canary/scheduler/cjs/scheduler.native.development.js +324 -512
  145. package/static/canary/scheduler/cjs/scheduler.native.production.js +6 -5
  146. package/static/canary/scheduler/cjs/scheduler.production.js +16 -17
  147. package/static/canary-full/react/cjs/react-compiler-runtime.development.js +13 -68
  148. package/static/canary-full/react/cjs/react-jsx-dev-runtime.development.js +317 -1251
  149. package/static/canary-full/react/cjs/react-jsx-dev-runtime.react-server.development.js +353 -1286
  150. package/static/canary-full/react/cjs/react-jsx-runtime.development.js +326 -1279
  151. package/static/canary-full/react/cjs/react-jsx-runtime.react-server.development.js +353 -1286
  152. package/static/canary-full/react/cjs/react.development.js +1204 -2771
  153. package/static/canary-full/react/cjs/react.production.js +25 -20
  154. package/static/canary-full/react/cjs/react.react-server.development.js +783 -2162
  155. package/static/canary-full/react/cjs/react.react-server.production.js +13 -63
  156. package/static/canary-full/react/package.json +1 -1
  157. package/static/canary-full/react-dom/cjs/react-dom-client.development.js +24847 -37099
  158. package/static/canary-full/react-dom/cjs/react-dom-client.production.js +8261 -7475
  159. package/static/canary-full/react-dom/cjs/react-dom-profiling.development.js +25252 -37571
  160. package/static/canary-full/react-dom/cjs/react-dom-profiling.profiling.js +9442 -8662
  161. package/static/canary-full/react-dom/cjs/react-dom-server-legacy.browser.development.js +8944 -11568
  162. package/static/canary-full/react-dom/cjs/react-dom-server-legacy.browser.production.js +1378 -944
  163. package/static/canary-full/react-dom/cjs/react-dom-server-legacy.node.development.js +8944 -11568
  164. package/static/canary-full/react-dom/cjs/react-dom-server-legacy.node.production.js +1386 -954
  165. package/static/canary-full/react-dom/cjs/react-dom-server.browser.development.js +9344 -11600
  166. package/static/canary-full/react-dom/cjs/react-dom-server.browser.production.js +1545 -954
  167. package/static/canary-full/react-dom/cjs/react-dom-server.bun.development.js +8286 -11064
  168. package/static/canary-full/react-dom/cjs/react-dom-server.bun.production.js +1437 -976
  169. package/static/canary-full/react-dom/cjs/react-dom-server.edge.development.js +9356 -11609
  170. package/static/canary-full/react-dom/cjs/react-dom-server.edge.production.js +1542 -970
  171. package/static/canary-full/react-dom/cjs/react-dom-server.node.development.js +9227 -11571
  172. package/static/canary-full/react-dom/cjs/react-dom-server.node.production.js +1787 -1183
  173. package/static/canary-full/react-dom/cjs/react-dom-test-utils.development.js +13 -59
  174. package/static/canary-full/react-dom/cjs/react-dom.development.js +402 -604
  175. package/static/canary-full/react-dom/cjs/react-dom.production.js +4 -3
  176. package/static/canary-full/react-dom/cjs/react-dom.react-server.development.js +322 -382
  177. package/static/canary-full/react-dom/cjs/react-dom.react-server.production.js +6 -7
  178. package/static/canary-full/react-dom/package.json +5 -5
  179. package/static/canary-full/react-dom/static.browser.js +1 -0
  180. package/static/canary-full/react-dom/static.edge.js +1 -0
  181. package/static/canary-full/react-dom/static.node.js +1 -0
  182. package/static/template/eslint.config.js +10 -0
package/README.md CHANGED
@@ -9,29 +9,37 @@
9
9
  <p align="center">The fastest way to build and run universal React Native apps for Android, iOS, and the web</p>
10
10
 
11
11
  <p align="center">
12
+ <a aria-label="expo documentation" href="https://docs.expo.dev/more/expo-cli/">📚 Read the Documentation</a>
13
+ &ensp;•&ensp;
14
+ <a aria-label="expo documentation" href="https://expo.dev/blog">Learn more on our blog</a>
15
+ &ensp;•&ensp;
16
+ <a aria-label="Contribute to Expo CLI" href="#contributing">Contribute to Expo CLI</a>
17
+ </p>
12
18
 
19
+ <p align="center">
13
20
  <a aria-label="Join the Expo Discord" href="https://discord.gg/4gtbPAdpaE" target="_blank">
14
- <img alt="Discord" src="https://img.shields.io/discord/695411232856997968.svg?style=flat-square&labelColor=000000&color=000000&logo=discord&logoColor=FFFFFF&label=" />
21
+ <img alt="Discord" src="https://img.shields.io/discord/695411232856997968.svg?style=for-the-badge&color=5865F2&logo=discord&logoColor=FFFFFF" />
15
22
  </a>
16
- <a aria-label="Browse the Expo forums" href="https://forums.expo.dev" target="_blank">
17
- <img alt="" src="https://img.shields.io/badge/Ask%20Questions%20-000.svg?style=flat-square&logo=discourse&logoWidth=15&labelColor=000000&color=000000">
18
- </a>
19
-
20
23
  </p>
21
24
 
22
25
  <p align="center">
23
- <a aria-label="expo documentation" href="https://docs.expo.dev/more/expo-cli/">📚 Read the Documentation</a>
24
- |
25
- <a aria-label="Contribute to Expo CLI" href="#contributing"><b>Contribute to Expo CLI</b></a>
26
- </p>
27
-
28
- <p>
29
- <a aria-label="Follow @expo on Twitter" href="https://twitter.com/intent/follow?screen_name=expo" target="_blank">
30
- <img alt="Twitter: expo" src="https://img.shields.io/twitter/follow/expo.svg?style=flat-square&label=Follow%20%40expo&logo=TWITTER&logoColor=FFFFFF&labelColor=00aced&logoWidth=15&color=lightgray" target="_blank" />
31
- </a>
32
- <a aria-label="Follow Expo on Medium" href="https://blog.expo.dev">
33
- <img align="right" alt="Medium: exposition" src="https://img.shields.io/badge/Learn%20more%20on%20our%20blog-lightgray.svg?style=flat-square" target="_blank" />
26
+ <a aria-label="Follow @expo on X" href="https://x.com/intent/follow?screen_name=expo" target="_blank">
27
+ <img alt="Expo on X" src="https://img.shields.io/badge/X-000000?style=for-the-badge&logo=x&logoColor=white" target="_blank" />
28
+ </a>&nbsp;
29
+ <a aria-label="Follow @expo on GitHub" href="https://github.com/expo" target="_blank">
30
+ <img alt="Expo on GitHub" src="https://img.shields.io/badge/GitHub-222222?style=for-the-badge&logo=github&logoColor=white" target="_blank" />
31
+ </a>&nbsp;
32
+ <a aria-label="Follow @expo on Reddit" href="https://www.reddit.com/r/expo/" target="_blank">
33
+ <img alt="Expo on Reddit" src="https://img.shields.io/badge/Reddit-FF4500?style=for-the-badge&logo=reddit&logoColor=white" target="_blank" />
34
+ </a>&nbsp;
35
+ <a aria-label="Follow @expo on Bluesky" href="https://bsky.app/profile/expo.dev" target="_blank">
36
+ <img alt="Expo on LinkedIn" src="https://img.shields.io/badge/Bluesky-1DA1F2?style=for-the-badge&logo=bluesky&logoColor=white" target="_blank" />
37
+ </a>&nbsp;
38
+ <a aria-label="Follow @expo on LinkedIn" href="https://www.linkedin.com/company/expo-dev" target="_blank">
39
+ <img alt="Expo on LinkedIn" src="https://img.shields.io/badge/LinkedIn-0077B5?style=for-the-badge&logo=LinkedIn&logoColor=white" target="_blank" />
34
40
  </a>
41
+
42
+ <p align="center">⭐️ Be sure to star the Expo GitHub repo if you enjoy using the project! ⭐️</p>
35
43
  </p>
36
44
 
37
45
  ---
@@ -49,9 +57,9 @@ npx expo
49
57
  This CLI has the following purposes:
50
58
 
51
59
  - Be a minimal interface for starting a local development server that emulates a production EAS Updates server. The development server is the proxy between a native runtime (Expo Go, Dev Client) and a JS Bundler (Metro, Webpack).
52
- - To accomplish secure manifest signing (think https/TSL/SSL for web (required for sandboxing AsyncStorage, Permissions, etc.)) we need an authenticated Expo user account. This is the only reason we include the authentication commands `login`, `logout`, `whoami`, `register`. Standard web CLIs don't have authentication commands because they either don't set up https or they use emulation via packages like `devcert`.
60
+ - To accomplish secure manifest signing for the web, like AsyncStorage or Permissions where both require https/SSL, we need an authenticated Expo account. This is the only reason we include the authentication commands `login`, `logout`, `whoami`, `register`. Standard web CLIs don't have authentication commands because they either don't set up https or they use emulation via packages like `devcert`.
53
61
  - Orchestrating various native tools like Xcode, `Simulator.app`, Android Studio, ADB, etc. to make native builds as painless as possible. `run:ios`, `run:android` commands.
54
- - Implementing a versioned `prebuild` command that can reliably work with a project for long periods of time. Prebuild is like a bundler for native code, it generates the `ios`, `android` folders based on the project Expo config (`app.json`).
62
+ - Implementing a versioned `prebuild` command that can reliably work with a project for long periods of time. Prebuild is like a bundler for native code, it generates the **android** and **ios** folders based on the project Expo config (**app.json**).
55
63
  - `npx expo config` is auxiliary to `npx expo prebuild` and used for debugging/introspection.
56
64
  - Installing versioned libraries with `npx expo install` this is a minimal utility born out of pure necessity since versioning in React Native is hard to get right.
57
65
 
@@ -63,7 +71,7 @@ To develop the CLI run (defaults to watch mode):
63
71
  yarn build
64
72
  ```
65
73
 
66
- We highly recommend setting up an alias for the Expo CLI so you can try it in projects all around your computer. Open your `.zshrc` or other config file and add:
74
+ We highly recommend setting up an alias for the Expo CLI so you can try it in projects all around your computer. Open your **.zshrc** or other config file and add:
67
75
 
68
76
  ```
69
77
  alias nexpo="/path/to/expo/packages/@expo/cli/build/bin/cli"
@@ -75,7 +83,7 @@ Then use it with `nexpo` like `nexpo config`. You can also set up a debug versio
75
83
  alias expo-inspect="node --inspect /path/to/expo/packages/@expo/cli/build/bin/cli"
76
84
  ```
77
85
 
78
- Then you can run it and visit `chrome://inspect/#devices` in Chrome, and press "Open dedicated DevTools for Node" to get a debugger attached to your process. When debugging the CLI, you'll want to disable workers whenever possible, this will make all code run on the same thread, this is mostly applicable to the `start` command, i.e. `expo-inspect start --max-workers 0`.
86
+ Then you can run it and visit `chrome://inspect/#devices` in Chrome, and press **"Open dedicated DevTools for Node"** to get a debugger attached to your process. When debugging the CLI, you'll want to disable workers whenever possible, this will make all code run on the same thread, this is mostly applicable to the `start` command, i.e. `expo-inspect start --max-workers 0`.
79
87
 
80
88
  ## Format
81
89
 
@@ -97,7 +105,7 @@ Then you can run it and visit `chrome://inspect/#devices` in Chrome, and press "
97
105
  - Unlike the legacy global Expo CLI, this CLI is shipped with `expo` meaning the SDK Version is always present.
98
106
  - Reduce SDK specific tasks since only one SDK should be accounted for in a single version of `@expo/cli`.
99
107
  - The `@expo/config` method `getConfig` does not need the `skipSDKVersionRequirement` in any case since `expo` should always be installed. Ex: `getConfig('...', { skipSDKVersionRequirement: true });` shouldn't be used.
100
- - Also unlike the global Expo CLI we can assume that node modules are always installed since this CLI should be used via a project's local `node_modules` folder.
108
+ - Also unlike the global Expo CLI we can assume that node modules are always installed since this CLI should be used via a project's local **node_modules** folder.
101
109
  - This means we can't perform operations that upgrade the `expo` package as these may kill the running process. Features that need this pattern (like `expo upgrade`) should live in standalone global tools.
102
110
 
103
111
  ## Testing
@@ -105,7 +113,7 @@ Then you can run it and visit `chrome://inspect/#devices` in Chrome, and press "
105
113
  There are two testing scripts:
106
114
 
107
115
  - `yarn test`: Controlled unit and integration tests.
108
- - `yarn test:e2e`: End to end testing for CLI commands. This requires the files to be built with `yarn build`
116
+ - `yarn test:e2e`: End to end testing for CLI commands. This requires the files to be built with `yarn build`.
109
117
 
110
118
  ---
111
119
 
@@ -126,7 +134,8 @@ There are two testing scripts:
126
134
  ### E2E Testing Guidelines
127
135
 
128
136
  - E2E tests should be resilient and reliable, be sure to give them plenty of time for network requests.
129
- - When testing locally you should attempt to reuse node modules for faster results. In the `npx expo prebuild` and `npx expo start` commands for instance, we utilize a helper method that will default to reusing a project + node_modules when run locally. This can be [toggled off](https://github.com/expo/expo/blob/11a5a4d27b7e1c8e4d6ddf0401397d789d89f52a/packages/%40expo/cli/e2e/__tests__/utils.ts#L174) to bootstrap a fresh project every time.
137
+ - When testing locally you had to have [Bun installed](https://bun.sh/docs/installation).
138
+ - When testing locally you should attempt to reuse node modules for faster results. In the `npx expo prebuild` and `npx expo start` commands for instance, we utilize a helper method that will default to reusing a project + **node_modules** when run locally. This can be [toggled off](https://github.com/expo/expo/blob/11a5a4d27b7e1c8e4d6ddf0401397d789d89f52a/packages/%40expo/cli/e2e/__tests__/utils.ts#L174) to bootstrap a fresh project every time.
130
139
  - When bootstrapping test projects, utilize the temporary folder `os.tmpdir()` as this folder is automatically cleaned up when the computer restarts.
131
140
 
132
141
  ## Coming from Expo CLI
@@ -139,6 +148,6 @@ The legacy global `expo-cli` package was deprecated in favor of this versioned `
139
148
  - `expo-cli` worked for almost all versions of the `expo` package, meaning it was getting more complex with every release.
140
149
  - `expo-cli` combined service commands (like the legacy `build`, `submit`, `publish`) with project-level commands like `expo start`. We've since divided services into `eas-cli` and project commands into `npx expo` (`@expo/cli`). This structure is more optimal/faster for developers since they can install/update commands when they need them.
141
150
  - This CLI utilizes more Node.js standard features like `$EDITOR` instead of the custom `$EXPO_EDITOR` environment variable. Also transitioning away from `$EXPO_DEBUG` and more towards `$DEBUG=expo:*`. These types of changes make Expo CLI play nicer with existing tooling.
142
- - The DevTools UI has been deprecated to reduce the net install size, minimize complexity, and make room for future debugging UIs (Hermes/v8 Chrome debugger).
151
+ - The DevTools UI has been deprecated to reduce the net installation size, minimize complexity, and make room for future debugging UIs (Hermes/v8 Chrome debugger).
143
152
  - The `expo start:web` and `expo web` commands have been rolled into `npx expo start` as we now lazily load platforms until the device requests them.
144
153
  - Other missing or beta features from `expo-cli` may still be getting migrated over to this new CLI. For a more comprehensive breakdown see the [start command PR](https://github.com/expo/expo/pull/16160).
package/build/bin/cli CHANGED
@@ -123,7 +123,7 @@ const args = (0, _arg().default)({
123
123
  });
124
124
  if (args['--version']) {
125
125
  // Version is added in the build script.
126
- console.log("1.0.0-canary-20250404-3c3b5fd");
126
+ console.log("1.0.0-canary-20250701-6a945c5");
127
127
  process.exit(0);
128
128
  }
129
129
  if (args['--non-interactive']) {
@@ -1,8 +1,10 @@
1
1
  'use strict';
2
- global.__r = metroRequire;
3
- global[`${__METRO_GLOBAL_PREFIX__}__d`] = define;
4
- global.__c = clear;
5
- global.__registerSegment = registerSegment;
2
+ if (__DEV__ || !global[`${__METRO_GLOBAL_PREFIX__}__d`]) {
3
+ global.__r = metroRequire;
4
+ global[`${__METRO_GLOBAL_PREFIX__}__d`] = define;
5
+ global.__c = clear;
6
+ global.__registerSegment = registerSegment;
7
+ }
6
8
  var modules = clear();
7
9
  const EMPTY = {};
8
10
  const CYCLE_DETECTED = {};
@@ -9,11 +9,11 @@ function _export(target, all) {
9
9
  });
10
10
  }
11
11
  _export(exports, {
12
- ensureLoggedInAsync: function() {
13
- return ensureLoggedInAsync;
14
- },
15
12
  showLoginPromptAsync: function() {
16
13
  return showLoginPromptAsync;
14
+ },
15
+ tryGetUserAsync: function() {
16
+ return tryGetUserAsync;
17
17
  }
18
18
  });
19
19
  function _assert() {
@@ -36,7 +36,7 @@ const _log = /*#__PURE__*/ _interop_require_wildcard(require("../../log"));
36
36
  const _env = require("../../utils/env");
37
37
  const _errors = require("../../utils/errors");
38
38
  const _link = require("../../utils/link");
39
- const _prompts = /*#__PURE__*/ _interop_require_default(require("../../utils/prompts"));
39
+ const _prompts = /*#__PURE__*/ _interop_require_wildcard(require("../../utils/prompts"));
40
40
  const _client = require("../rest/client");
41
41
  function _interop_require_default(obj) {
42
42
  return obj && obj.__esModule ? obj : {
@@ -134,17 +134,31 @@ async function showLoginPromptAsync({ printNewLine = false, otp, ...options } =
134
134
  }
135
135
  }
136
136
  }
137
- async function ensureLoggedInAsync() {
138
- let user = await (0, _user.getUserAsync)().catch(()=>null);
139
- if (!user) {
140
- _log.warn(_chalk().default.yellow`An Expo user account is required to proceed.`);
137
+ async function tryGetUserAsync() {
138
+ const user = await (0, _user.getUserAsync)().catch(()=>null);
139
+ if (user) {
140
+ return user;
141
+ }
142
+ const choices = [
143
+ {
144
+ title: 'Log in',
145
+ value: true
146
+ },
147
+ {
148
+ title: 'Proceed anonymously',
149
+ value: false
150
+ }
151
+ ];
152
+ const value = await (0, _prompts.selectAsync)((0, _chalk().default)`\n\nIt is recommended to log in with your Expo account before proceeding. \n{dim ${(0, _link.learnMore)('https://expo.fyi/unverified-app-expo-go')}}\n`, choices, {
153
+ nonInteractiveHelp: `Use the EXPO_TOKEN environment variable to authenticate in CI (${(0, _link.learnMore)('https://docs.expo.dev/accounts/programmatic-access/')})`
154
+ });
155
+ if (value) {
141
156
  await showLoginPromptAsync({
142
157
  printNewLine: true
143
158
  });
144
- user = await (0, _user.getUserAsync)();
159
+ return await (0, _user.getUserAsync)() ?? null;
145
160
  }
146
- (0, _assert().default)(user, 'User should be logged in');
147
- return user;
161
+ return null;
148
162
  }
149
163
 
150
164
  //# sourceMappingURL=actions.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/api/user/actions.ts"],"sourcesContent":["import assert from 'assert';\nimport chalk from 'chalk';\n\nimport { retryUsernamePasswordAuthWithOTPAsync } from './otp';\nimport { Actor, getUserAsync, loginAsync, ssoLoginAsync } from './user';\nimport * as Log from '../../log';\nimport { env } from '../../utils/env';\nimport { CommandError } from '../../utils/errors';\nimport { learnMore } from '../../utils/link';\nimport promptAsync, { Question } from '../../utils/prompts';\nimport { ApiV2Error } from '../rest/client';\n\n/** Show login prompt while prompting for missing credentials. */\nexport async function showLoginPromptAsync({\n printNewLine = false,\n otp,\n ...options\n}: {\n printNewLine?: boolean;\n username?: string;\n password?: string;\n otp?: string;\n sso?: boolean | undefined;\n} = {}): Promise<void> {\n if (env.EXPO_OFFLINE) {\n throw new CommandError('OFFLINE', 'Cannot authenticate in offline-mode');\n }\n const hasCredentials = options.username && options.password;\n const sso = options.sso;\n\n if (printNewLine) {\n Log.log();\n }\n\n if (sso) {\n await ssoLoginAsync();\n return;\n }\n\n Log.log(\n hasCredentials\n ? `Logging in to EAS with email or username (exit and run 'npx expo login --help' for other login options)`\n : `Log in to EAS with email or username (exit and run 'npx expo login --help' for other login options)`\n );\n\n let username = options.username;\n let password = options.password;\n\n if (!hasCredentials) {\n const resolved = await promptAsync(\n [\n !options.username && {\n type: 'text',\n name: 'username',\n message: 'Email or username',\n },\n !options.password && {\n type: 'password',\n name: 'password',\n message: 'Password',\n },\n ].filter(Boolean) as Question<string>[],\n {\n nonInteractiveHelp: `Use the EXPO_TOKEN environment variable to authenticate in CI (${learnMore(\n 'https://docs.expo.dev/accounts/programmatic-access/'\n )})`,\n }\n );\n username ??= resolved.username;\n password ??= resolved.password;\n }\n // This is just for the types.\n assert(username && password);\n\n try {\n await loginAsync({\n username,\n password,\n otp,\n });\n } catch (e) {\n if (e instanceof ApiV2Error && e.expoApiV2ErrorCode === 'ONE_TIME_PASSWORD_REQUIRED') {\n await retryUsernamePasswordAuthWithOTPAsync(\n username,\n password,\n e.expoApiV2ErrorMetadata as any\n );\n } else {\n throw e;\n }\n }\n}\n\n/** Ensure the user is logged in, if not, prompt to login. */\nexport async function ensureLoggedInAsync(): Promise<Actor> {\n let user = await getUserAsync().catch(() => null);\n\n if (!user) {\n Log.warn(chalk.yellow`An Expo user account is required to proceed.`);\n await showLoginPromptAsync({ printNewLine: true });\n user = await getUserAsync();\n }\n\n assert(user, 'User should be logged in');\n return user;\n}\n"],"names":["ensureLoggedInAsync","showLoginPromptAsync","printNewLine","otp","options","env","EXPO_OFFLINE","CommandError","hasCredentials","username","password","sso","Log","log","ssoLoginAsync","resolved","promptAsync","type","name","message","filter","Boolean","nonInteractiveHelp","learnMore","assert","loginAsync","e","ApiV2Error","expoApiV2ErrorCode","retryUsernamePasswordAuthWithOTPAsync","expoApiV2ErrorMetadata","user","getUserAsync","catch","warn","chalk","yellow"],"mappings":";;;;;;;;;;;IA8FsBA,mBAAmB;eAAnBA;;IAjFAC,oBAAoB;eAApBA;;;;gEAbH;;;;;;;gEACD;;;;;;qBAEoC;sBACS;6DAC1C;qBACD;wBACS;sBACH;gEACY;wBACX;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAGpB,eAAeA,qBAAqB,EACzCC,eAAe,KAAK,EACpBC,GAAG,EACH,GAAGC,SAOJ,GAAG,CAAC,CAAC;IACJ,IAAIC,QAAG,CAACC,YAAY,EAAE;QACpB,MAAM,IAAIC,oBAAY,CAAC,WAAW;IACpC;IACA,MAAMC,iBAAiBJ,QAAQK,QAAQ,IAAIL,QAAQM,QAAQ;IAC3D,MAAMC,MAAMP,QAAQO,GAAG;IAEvB,IAAIT,cAAc;QAChBU,KAAIC,GAAG;IACT;IAEA,IAAIF,KAAK;QACP,MAAMG,IAAAA,mBAAa;QACnB;IACF;IAEAF,KAAIC,GAAG,CACLL,iBACI,CAAC,uGAAuG,CAAC,GACzG,CAAC,mGAAmG,CAAC;IAG3G,IAAIC,WAAWL,QAAQK,QAAQ;IAC/B,IAAIC,WAAWN,QAAQM,QAAQ;IAE/B,IAAI,CAACF,gBAAgB;QACnB,MAAMO,WAAW,MAAMC,IAAAA,gBAAW,EAChC;YACE,CAACZ,QAAQK,QAAQ,IAAI;gBACnBQ,MAAM;gBACNC,MAAM;gBACNC,SAAS;YACX;YACA,CAACf,QAAQM,QAAQ,IAAI;gBACnBO,MAAM;gBACNC,MAAM;gBACNC,SAAS;YACX;SACD,CAACC,MAAM,CAACC,UACT;YACEC,oBAAoB,CAAC,+DAA+D,EAAEC,IAAAA,eAAS,EAC7F,uDACA,CAAC,CAAC;QACN;QAEFd,aAAaM,SAASN,QAAQ;QAC9BC,aAAaK,SAASL,QAAQ;IAChC;IACA,8BAA8B;IAC9Bc,IAAAA,iBAAM,EAACf,YAAYC;IAEnB,IAAI;QACF,MAAMe,IAAAA,gBAAU,EAAC;YACfhB;YACAC;YACAP;QACF;IACF,EAAE,OAAOuB,GAAG;QACV,IAAIA,aAAaC,kBAAU,IAAID,EAAEE,kBAAkB,KAAK,8BAA8B;YACpF,MAAMC,IAAAA,0CAAqC,EACzCpB,UACAC,UACAgB,EAAEI,sBAAsB;QAE5B,OAAO;YACL,MAAMJ;QACR;IACF;AACF;AAGO,eAAe1B;IACpB,IAAI+B,OAAO,MAAMC,IAAAA,kBAAY,IAAGC,KAAK,CAAC,IAAM;IAE5C,IAAI,CAACF,MAAM;QACTnB,KAAIsB,IAAI,CAACC,gBAAK,CAACC,MAAM,CAAC,4CAA4C,CAAC;QACnE,MAAMnC,qBAAqB;YAAEC,cAAc;QAAK;QAChD6B,OAAO,MAAMC,IAAAA,kBAAY;IAC3B;IAEAR,IAAAA,iBAAM,EAACO,MAAM;IACb,OAAOA;AACT"}
1
+ {"version":3,"sources":["../../../../src/api/user/actions.ts"],"sourcesContent":["import assert from 'assert';\nimport chalk from 'chalk';\n\nimport { retryUsernamePasswordAuthWithOTPAsync } from './otp';\nimport { Actor, getUserAsync, loginAsync, ssoLoginAsync } from './user';\nimport * as Log from '../../log';\nimport { env } from '../../utils/env';\nimport { CommandError } from '../../utils/errors';\nimport { learnMore } from '../../utils/link';\nimport promptAsync, { confirmAsync, Question, selectAsync } from '../../utils/prompts';\nimport { ApiV2Error } from '../rest/client';\n\n/** Show login prompt while prompting for missing credentials. */\nexport async function showLoginPromptAsync({\n printNewLine = false,\n otp,\n ...options\n}: {\n printNewLine?: boolean;\n username?: string;\n password?: string;\n otp?: string;\n sso?: boolean | undefined;\n} = {}): Promise<void> {\n if (env.EXPO_OFFLINE) {\n throw new CommandError('OFFLINE', 'Cannot authenticate in offline-mode');\n }\n const hasCredentials = options.username && options.password;\n const sso = options.sso;\n\n if (printNewLine) {\n Log.log();\n }\n\n if (sso) {\n await ssoLoginAsync();\n return;\n }\n\n Log.log(\n hasCredentials\n ? `Logging in to EAS with email or username (exit and run 'npx expo login --help' for other login options)`\n : `Log in to EAS with email or username (exit and run 'npx expo login --help' for other login options)`\n );\n\n let username = options.username;\n let password = options.password;\n\n if (!hasCredentials) {\n const resolved = await promptAsync(\n [\n !options.username && {\n type: 'text',\n name: 'username',\n message: 'Email or username',\n },\n !options.password && {\n type: 'password',\n name: 'password',\n message: 'Password',\n },\n ].filter(Boolean) as Question<string>[],\n {\n nonInteractiveHelp: `Use the EXPO_TOKEN environment variable to authenticate in CI (${learnMore(\n 'https://docs.expo.dev/accounts/programmatic-access/'\n )})`,\n }\n );\n username ??= resolved.username;\n password ??= resolved.password;\n }\n // This is just for the types.\n assert(username && password);\n\n try {\n await loginAsync({\n username,\n password,\n otp,\n });\n } catch (e) {\n if (e instanceof ApiV2Error && e.expoApiV2ErrorCode === 'ONE_TIME_PASSWORD_REQUIRED') {\n await retryUsernamePasswordAuthWithOTPAsync(\n username,\n password,\n e.expoApiV2ErrorMetadata as any\n );\n } else {\n throw e;\n }\n }\n}\n\nexport async function tryGetUserAsync(): Promise<Actor | null> {\n const user = await getUserAsync().catch(() => null);\n\n if (user) {\n return user;\n }\n\n const choices = [\n {\n title: 'Log in',\n value: true,\n },\n {\n title: 'Proceed anonymously',\n value: false,\n },\n ];\n\n const value = await selectAsync(\n chalk`\\n\\nIt is recommended to log in with your Expo account before proceeding. \\n{dim ${learnMore(\n 'https://expo.fyi/unverified-app-expo-go'\n )}}\\n`,\n choices,\n {\n nonInteractiveHelp: `Use the EXPO_TOKEN environment variable to authenticate in CI (${learnMore(\n 'https://docs.expo.dev/accounts/programmatic-access/'\n )})`,\n }\n );\n\n if (value) {\n await showLoginPromptAsync({ printNewLine: true });\n return (await getUserAsync()) ?? null;\n }\n\n return null;\n}\n"],"names":["showLoginPromptAsync","tryGetUserAsync","printNewLine","otp","options","env","EXPO_OFFLINE","CommandError","hasCredentials","username","password","sso","Log","log","ssoLoginAsync","resolved","promptAsync","type","name","message","filter","Boolean","nonInteractiveHelp","learnMore","assert","loginAsync","e","ApiV2Error","expoApiV2ErrorCode","retryUsernamePasswordAuthWithOTPAsync","expoApiV2ErrorMetadata","user","getUserAsync","catch","choices","title","value","selectAsync","chalk"],"mappings":";;;;;;;;;;;IAasBA,oBAAoB;eAApBA;;IAgFAC,eAAe;eAAfA;;;;gEA7FH;;;;;;;gEACD;;;;;;qBAEoC;sBACS;6DAC1C;qBACD;wBACS;sBACH;iEACuC;wBACtC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAGpB,eAAeD,qBAAqB,EACzCE,eAAe,KAAK,EACpBC,GAAG,EACH,GAAGC,SAOJ,GAAG,CAAC,CAAC;IACJ,IAAIC,QAAG,CAACC,YAAY,EAAE;QACpB,MAAM,IAAIC,oBAAY,CAAC,WAAW;IACpC;IACA,MAAMC,iBAAiBJ,QAAQK,QAAQ,IAAIL,QAAQM,QAAQ;IAC3D,MAAMC,MAAMP,QAAQO,GAAG;IAEvB,IAAIT,cAAc;QAChBU,KAAIC,GAAG;IACT;IAEA,IAAIF,KAAK;QACP,MAAMG,IAAAA,mBAAa;QACnB;IACF;IAEAF,KAAIC,GAAG,CACLL,iBACI,CAAC,uGAAuG,CAAC,GACzG,CAAC,mGAAmG,CAAC;IAG3G,IAAIC,WAAWL,QAAQK,QAAQ;IAC/B,IAAIC,WAAWN,QAAQM,QAAQ;IAE/B,IAAI,CAACF,gBAAgB;QACnB,MAAMO,WAAW,MAAMC,IAAAA,gBAAW,EAChC;YACE,CAACZ,QAAQK,QAAQ,IAAI;gBACnBQ,MAAM;gBACNC,MAAM;gBACNC,SAAS;YACX;YACA,CAACf,QAAQM,QAAQ,IAAI;gBACnBO,MAAM;gBACNC,MAAM;gBACNC,SAAS;YACX;SACD,CAACC,MAAM,CAACC,UACT;YACEC,oBAAoB,CAAC,+DAA+D,EAAEC,IAAAA,eAAS,EAC7F,uDACA,CAAC,CAAC;QACN;QAEFd,aAAaM,SAASN,QAAQ;QAC9BC,aAAaK,SAASL,QAAQ;IAChC;IACA,8BAA8B;IAC9Bc,IAAAA,iBAAM,EAACf,YAAYC;IAEnB,IAAI;QACF,MAAMe,IAAAA,gBAAU,EAAC;YACfhB;YACAC;YACAP;QACF;IACF,EAAE,OAAOuB,GAAG;QACV,IAAIA,aAAaC,kBAAU,IAAID,EAAEE,kBAAkB,KAAK,8BAA8B;YACpF,MAAMC,IAAAA,0CAAqC,EACzCpB,UACAC,UACAgB,EAAEI,sBAAsB;QAE5B,OAAO;YACL,MAAMJ;QACR;IACF;AACF;AAEO,eAAezB;IACpB,MAAM8B,OAAO,MAAMC,IAAAA,kBAAY,IAAGC,KAAK,CAAC,IAAM;IAE9C,IAAIF,MAAM;QACR,OAAOA;IACT;IAEA,MAAMG,UAAU;QACd;YACEC,OAAO;YACPC,OAAO;QACT;QACA;YACED,OAAO;YACPC,OAAO;QACT;KACD;IAED,MAAMA,QAAQ,MAAMC,IAAAA,oBAAW,EAC7BC,IAAAA,gBAAK,CAAA,CAAC,iFAAiF,EAAEf,IAAAA,eAAS,EAChG,2CACA,GAAG,CAAC,EACNW,SACA;QACEZ,oBAAoB,CAAC,+DAA+D,EAAEC,IAAAA,eAAS,EAC7F,uDACA,CAAC,CAAC;IACN;IAGF,IAAIa,OAAO;QACT,MAAMpC,qBAAqB;YAAEE,cAAc;QAAK;QAChD,OAAO,AAAC,MAAM8B,IAAAA,kBAAY,OAAO;IACnC;IAEA,OAAO;AACT"}
@@ -106,7 +106,7 @@ const TEMPLATES = [
106
106
  {
107
107
  id: '.eslintrc.js',
108
108
  dependencies: [],
109
- destination: ()=>'.eslintrc.js',
109
+ destination: ()=>'.eslintrc.js (deprecated)',
110
110
  file: (projectRoot)=>importFromVendor(projectRoot, '.eslintrc.js'),
111
111
  configureAsync: async (projectRoot)=>{
112
112
  const { ESLintProjectPrerequisite } = require('../lint/ESlintPrerequisite');
@@ -117,6 +117,20 @@ const TEMPLATES = [
117
117
  return false;
118
118
  }
119
119
  },
120
+ {
121
+ id: 'eslint.config.js',
122
+ dependencies: [],
123
+ destination: ()=>'eslint.config.js',
124
+ file: (projectRoot)=>importFromVendor(projectRoot, 'eslint.config.js'),
125
+ configureAsync: async (projectRoot)=>{
126
+ const { ESLintProjectPrerequisite } = require('../lint/ESlintPrerequisite');
127
+ const prerequisite = new ESLintProjectPrerequisite(projectRoot);
128
+ if (!await prerequisite.assertAsync()) {
129
+ await prerequisite.bootstrapAsync();
130
+ }
131
+ return false;
132
+ }
133
+ },
120
134
  {
121
135
  id: 'index.html',
122
136
  file: (projectRoot)=>importFromExpoWebpackConfig(projectRoot, 'web-default', 'index.html'),
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/customize/templates.ts"],"sourcesContent":["import chalk from 'chalk';\nimport fs from 'fs';\nimport path from 'path';\nimport resolveFrom from 'resolve-from';\n\nimport prompt, { ExpoChoice } from '../utils/prompts';\n\nconst debug = require('debug')('expo:customize:templates');\n\nexport type DestinationResolutionProps = {\n /** Web 'public' folder path (defaults to `/web`). This technically can be changed but shouldn't be. */\n webStaticPath: string;\n /** The Expo Router app directory. */\n appDirPath: string;\n};\n\nfunction importFromExpoWebpackConfig(projectRoot: string, folder: string, moduleId: string) {\n try {\n const filePath = resolveFrom(projectRoot, `@expo/webpack-config/${folder}/${moduleId}`);\n debug(`Using @expo/webpack-config template for \"${moduleId}\": ${filePath}`);\n return filePath;\n } catch {\n debug(`@expo/webpack-config template for \"${moduleId}\" not found, falling back on @expo/cli`);\n }\n return importFromVendor(projectRoot, moduleId);\n}\n\nfunction importFromVendor(projectRoot: string, moduleId: string) {\n try {\n const filePath = resolveFrom(projectRoot, '@expo/cli/static/template/' + moduleId);\n debug(`Using @expo/cli template for \"${moduleId}\": ${filePath}`);\n return filePath;\n } catch {\n // For dev mode, testing and other cases where @expo/cli is not installed\n const filePath = require.resolve(`@expo/cli/static/template/${moduleId}`);\n debug(\n `Local @expo/cli template for \"${moduleId}\" not found, falling back on template relative to @expo/cli: ${filePath}`\n );\n\n return filePath;\n }\n}\n\nexport const TEMPLATES: {\n /** Unique ID for easily indexing. */\n id: string;\n /** Template file path to copy into the project. */\n file: (projectRoot: string) => string;\n /** Output location for the file in the user project. */\n destination: (props: DestinationResolutionProps) => string;\n /** List of dependencies to install in the project. These are used inside of the template file. */\n dependencies: string[];\n\n /** Custom step for configuring the file. Return true to exit early. */\n configureAsync?: (projectRoot: string) => Promise<boolean>;\n}[] = [\n {\n id: 'babel.config.js',\n file: (projectRoot) => importFromVendor(projectRoot, 'babel.config.js'),\n destination: () => 'babel.config.js',\n dependencies: [\n // Even though this is installed in `expo`, we should add it for now.\n 'babel-preset-expo',\n ],\n },\n {\n id: 'metro.config.js',\n dependencies: ['@expo/metro-config'],\n destination: () => 'metro.config.js',\n file: (projectRoot) => importFromVendor(projectRoot, 'metro.config.js'),\n },\n {\n // `tsconfig.json` is special-cased and doesn't follow the template.\n id: 'tsconfig.json',\n dependencies: [],\n destination: () => 'tsconfig.json',\n file: () => '',\n configureAsync: async (projectRoot) => {\n const { typescript } = require('./typescript') as typeof import('./typescript');\n await typescript(projectRoot);\n return true;\n },\n },\n {\n id: '.eslintrc.js',\n dependencies: [],\n destination: () => '.eslintrc.js',\n file: (projectRoot) => importFromVendor(projectRoot, '.eslintrc.js'),\n configureAsync: async (projectRoot) => {\n const { ESLintProjectPrerequisite } =\n require('../lint/ESlintPrerequisite') as typeof import('../lint/ESlintPrerequisite.js');\n const prerequisite = new ESLintProjectPrerequisite(projectRoot);\n if (!(await prerequisite.assertAsync())) {\n await prerequisite.bootstrapAsync();\n }\n return false;\n },\n },\n {\n id: 'index.html',\n file: (projectRoot) => importFromExpoWebpackConfig(projectRoot, 'web-default', 'index.html'),\n // web/index.html\n destination: ({ webStaticPath }) => webStaticPath + '/index.html',\n dependencies: [],\n },\n {\n id: 'webpack.config.js',\n file: (projectRoot) =>\n importFromExpoWebpackConfig(projectRoot, 'template', 'webpack.config.js'),\n destination: () => 'webpack.config.js',\n dependencies: ['@expo/webpack-config'],\n },\n {\n id: '+html.tsx',\n file: (projectRoot) => importFromVendor(projectRoot, '+html.tsx'),\n destination: ({ appDirPath }) => path.join(appDirPath, '+html.tsx'),\n dependencies: [],\n },\n {\n id: '+native-intent.ts',\n file: (projectRoot) => importFromVendor(projectRoot, '+native-intent.ts'),\n destination: ({ appDirPath }) => path.join(appDirPath, '+native-intent.ts'),\n dependencies: [],\n },\n];\n\n/** Generate the prompt choices. */\nfunction createChoices(\n projectRoot: string,\n props: DestinationResolutionProps\n): ExpoChoice<number>[] {\n return TEMPLATES.map((template, index) => {\n const destination = template.destination(props);\n const localProjectFile = path.resolve(projectRoot, destination);\n const exists = fs.existsSync(localProjectFile);\n\n return {\n title: destination,\n value: index,\n description: exists ? chalk.red('This will overwrite the existing file') : undefined,\n };\n });\n}\n\n/** Prompt to select templates to add. */\nexport async function selectTemplatesAsync(projectRoot: string, props: DestinationResolutionProps) {\n const options = createChoices(projectRoot, props);\n\n const { answer } = await prompt({\n type: 'multiselect',\n name: 'answer',\n message: 'Which files would you like to generate?',\n hint: '- Space to select. Return to submit',\n warn: 'File already exists.',\n limit: options.length,\n instructions: '',\n choices: options,\n });\n return answer;\n}\n"],"names":["TEMPLATES","selectTemplatesAsync","debug","require","importFromExpoWebpackConfig","projectRoot","folder","moduleId","filePath","resolveFrom","importFromVendor","resolve","id","file","destination","dependencies","configureAsync","typescript","ESLintProjectPrerequisite","prerequisite","assertAsync","bootstrapAsync","webStaticPath","appDirPath","path","join","createChoices","props","map","template","index","localProjectFile","exists","fs","existsSync","title","value","description","chalk","red","undefined","options","answer","prompt","type","name","message","hint","warn","limit","length","instructions","choices"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/customize/templates.ts"],"sourcesContent":["import chalk from 'chalk';\nimport fs from 'fs';\nimport path from 'path';\nimport resolveFrom from 'resolve-from';\n\nimport prompt, { ExpoChoice } from '../utils/prompts';\n\nconst debug = require('debug')('expo:customize:templates');\n\nexport type DestinationResolutionProps = {\n /** Web 'public' folder path (defaults to `/web`). This technically can be changed but shouldn't be. */\n webStaticPath: string;\n /** The Expo Router app directory. */\n appDirPath: string;\n};\n\nfunction importFromExpoWebpackConfig(projectRoot: string, folder: string, moduleId: string) {\n try {\n const filePath = resolveFrom(projectRoot, `@expo/webpack-config/${folder}/${moduleId}`);\n debug(`Using @expo/webpack-config template for \"${moduleId}\": ${filePath}`);\n return filePath;\n } catch {\n debug(`@expo/webpack-config template for \"${moduleId}\" not found, falling back on @expo/cli`);\n }\n return importFromVendor(projectRoot, moduleId);\n}\n\nfunction importFromVendor(projectRoot: string, moduleId: string) {\n try {\n const filePath = resolveFrom(projectRoot, '@expo/cli/static/template/' + moduleId);\n debug(`Using @expo/cli template for \"${moduleId}\": ${filePath}`);\n return filePath;\n } catch {\n // For dev mode, testing and other cases where @expo/cli is not installed\n const filePath = require.resolve(`@expo/cli/static/template/${moduleId}`);\n debug(\n `Local @expo/cli template for \"${moduleId}\" not found, falling back on template relative to @expo/cli: ${filePath}`\n );\n\n return filePath;\n }\n}\n\nexport const TEMPLATES: {\n /** Unique ID for easily indexing. */\n id: string;\n /** Template file path to copy into the project. */\n file: (projectRoot: string) => string;\n /** Output location for the file in the user project. */\n destination: (props: DestinationResolutionProps) => string;\n /** List of dependencies to install in the project. These are used inside of the template file. */\n dependencies: string[];\n\n /** Custom step for configuring the file. Return true to exit early. */\n configureAsync?: (projectRoot: string) => Promise<boolean>;\n}[] = [\n {\n id: 'babel.config.js',\n file: (projectRoot) => importFromVendor(projectRoot, 'babel.config.js'),\n destination: () => 'babel.config.js',\n dependencies: [\n // Even though this is installed in `expo`, we should add it for now.\n 'babel-preset-expo',\n ],\n },\n {\n id: 'metro.config.js',\n dependencies: ['@expo/metro-config'],\n destination: () => 'metro.config.js',\n file: (projectRoot) => importFromVendor(projectRoot, 'metro.config.js'),\n },\n {\n // `tsconfig.json` is special-cased and doesn't follow the template.\n id: 'tsconfig.json',\n dependencies: [],\n destination: () => 'tsconfig.json',\n file: () => '',\n configureAsync: async (projectRoot) => {\n const { typescript } = require('./typescript') as typeof import('./typescript');\n await typescript(projectRoot);\n return true;\n },\n },\n {\n id: '.eslintrc.js',\n dependencies: [],\n destination: () => '.eslintrc.js (deprecated)',\n file: (projectRoot) => importFromVendor(projectRoot, '.eslintrc.js'),\n configureAsync: async (projectRoot) => {\n const { ESLintProjectPrerequisite } =\n require('../lint/ESlintPrerequisite') as typeof import('../lint/ESlintPrerequisite.js');\n const prerequisite = new ESLintProjectPrerequisite(projectRoot);\n if (!(await prerequisite.assertAsync())) {\n await prerequisite.bootstrapAsync();\n }\n return false;\n },\n },\n {\n id: 'eslint.config.js',\n dependencies: [],\n destination: () => 'eslint.config.js',\n file: (projectRoot) => importFromVendor(projectRoot, 'eslint.config.js'),\n configureAsync: async (projectRoot) => {\n const { ESLintProjectPrerequisite } =\n require('../lint/ESlintPrerequisite') as typeof import('../lint/ESlintPrerequisite.js');\n const prerequisite = new ESLintProjectPrerequisite(projectRoot);\n if (!(await prerequisite.assertAsync())) {\n await prerequisite.bootstrapAsync();\n }\n return false;\n },\n },\n {\n id: 'index.html',\n file: (projectRoot) => importFromExpoWebpackConfig(projectRoot, 'web-default', 'index.html'),\n // web/index.html\n destination: ({ webStaticPath }) => webStaticPath + '/index.html',\n dependencies: [],\n },\n {\n id: 'webpack.config.js',\n file: (projectRoot) =>\n importFromExpoWebpackConfig(projectRoot, 'template', 'webpack.config.js'),\n destination: () => 'webpack.config.js',\n dependencies: ['@expo/webpack-config'],\n },\n {\n id: '+html.tsx',\n file: (projectRoot) => importFromVendor(projectRoot, '+html.tsx'),\n destination: ({ appDirPath }) => path.join(appDirPath, '+html.tsx'),\n dependencies: [],\n },\n {\n id: '+native-intent.ts',\n file: (projectRoot) => importFromVendor(projectRoot, '+native-intent.ts'),\n destination: ({ appDirPath }) => path.join(appDirPath, '+native-intent.ts'),\n dependencies: [],\n },\n];\n\n/** Generate the prompt choices. */\nfunction createChoices(\n projectRoot: string,\n props: DestinationResolutionProps\n): ExpoChoice<number>[] {\n return TEMPLATES.map((template, index) => {\n const destination = template.destination(props);\n const localProjectFile = path.resolve(projectRoot, destination);\n const exists = fs.existsSync(localProjectFile);\n\n return {\n title: destination,\n value: index,\n description: exists ? chalk.red('This will overwrite the existing file') : undefined,\n };\n });\n}\n\n/** Prompt to select templates to add. */\nexport async function selectTemplatesAsync(projectRoot: string, props: DestinationResolutionProps) {\n const options = createChoices(projectRoot, props);\n\n const { answer } = await prompt({\n type: 'multiselect',\n name: 'answer',\n message: 'Which files would you like to generate?',\n hint: '- Space to select. Return to submit',\n warn: 'File already exists.',\n limit: options.length,\n instructions: '',\n choices: options,\n });\n return answer;\n}\n"],"names":["TEMPLATES","selectTemplatesAsync","debug","require","importFromExpoWebpackConfig","projectRoot","folder","moduleId","filePath","resolveFrom","importFromVendor","resolve","id","file","destination","dependencies","configureAsync","typescript","ESLintProjectPrerequisite","prerequisite","assertAsync","bootstrapAsync","webStaticPath","appDirPath","path","join","createChoices","props","map","template","index","localProjectFile","exists","fs","existsSync","title","value","description","chalk","red","undefined","options","answer","prompt","type","name","message","hint","warn","limit","length","instructions","choices"],"mappings":"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"}
@@ -185,27 +185,39 @@ async function exportAppAsync(projectRoot, { platforms, outputDir, clear, dev, d
185
185
  // Can be empty during web-only SSG.
186
186
  if (spaPlatforms.length) {
187
187
  await Promise.all(spaPlatforms.map(async (platform)=>{
188
- var _exp_experiments;
189
188
  // Assert early so the user doesn't have to wait until bundling is complete to find out that
190
189
  // Hermes won't be available.
191
190
  const isHermes = (0, _exportHermes.isEnableHermesManaged)(exp, platform);
192
191
  if (isHermes) {
193
192
  await (0, _exportHermes.assertEngineMismatchAsync)(projectRoot, exp, platform);
194
193
  }
195
- // Run metro bundler and create the JS bundles/source maps.
196
- const bundle = await devServer.nativeExportBundleAsync(exp, {
197
- platform,
198
- splitChunks: !_env.env.EXPO_NO_BUNDLE_SPLITTING && (devServer.isReactServerComponentsEnabled && !bytecode || platform === 'web'),
199
- mainModuleName: (0, _ManifestMiddleware.getEntryWithServerRoot)(projectRoot, {
194
+ let bundle;
195
+ try {
196
+ var _exp_experiments;
197
+ // Run metro bundler and create the JS bundles/source maps.
198
+ bundle = await devServer.nativeExportBundleAsync(exp, {
200
199
  platform,
201
- pkg: projectConfig.pkg
202
- }),
203
- mode: dev ? 'development' : 'production',
204
- engine: isHermes ? 'hermes' : undefined,
205
- serializerIncludeMaps: sourceMaps,
206
- bytecode: bytecode && isHermes,
207
- reactCompiler: !!((_exp_experiments = exp.experiments) == null ? void 0 : _exp_experiments.reactCompiler)
208
- }, files);
200
+ splitChunks: !_env.env.EXPO_NO_BUNDLE_SPLITTING && (devServer.isReactServerComponentsEnabled && !bytecode || platform === 'web'),
201
+ mainModuleName: (0, _ManifestMiddleware.getEntryWithServerRoot)(projectRoot, {
202
+ platform,
203
+ pkg: projectConfig.pkg
204
+ }),
205
+ mode: dev ? 'development' : 'production',
206
+ engine: isHermes ? 'hermes' : undefined,
207
+ serializerIncludeMaps: sourceMaps,
208
+ bytecode: bytecode && isHermes,
209
+ reactCompiler: !!((_exp_experiments = exp.experiments) == null ? void 0 : _exp_experiments.reactCompiler)
210
+ }, files);
211
+ } catch (error) {
212
+ _log.log('');
213
+ if (error instanceof Error) {
214
+ _log.exception(error);
215
+ } else {
216
+ _log.error('Failed to bundle the app');
217
+ _log.log(error);
218
+ }
219
+ process.exit(1);
220
+ }
209
221
  bundles[platform] = bundle;
210
222
  (0, _saveAssets.getFilesFromSerialAssets)(bundle.artifacts, {
211
223
  includeSourceMaps: sourceMaps,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/export/exportApp.ts"],"sourcesContent":["import { getConfig } from '@expo/config';\nimport type { Platform } from '@expo/config';\nimport assert from 'assert';\nimport chalk from 'chalk';\nimport fs from 'fs';\nimport path from 'path';\n\nimport { type PlatformMetadata, createMetadataJson } from './createMetadataJson';\nimport { exportAssetsAsync } from './exportAssets';\nimport {\n addDomBundleToMetadataAsync,\n exportDomComponentAsync,\n transformNativeBundleForMd5Filename,\n transformDomEntryForMd5Filename,\n} from './exportDomComponents';\nimport { assertEngineMismatchAsync, isEnableHermesManaged } from './exportHermes';\nimport { exportApiRoutesStandaloneAsync, exportFromServerAsync } from './exportStaticAsync';\nimport { getVirtualFaviconAssetsAsync } from './favicon';\nimport { getPublicExpoManifestAsync } from './getPublicExpoManifest';\nimport { copyPublicFolderAsync } from './publicFolder';\nimport { Options } from './resolveOptions';\nimport {\n ExportAssetMap,\n BundleOutput,\n getFilesFromSerialAssets,\n persistMetroFilesAsync,\n} from './saveAssets';\nimport { createAssetMap } from './writeContents';\nimport * as Log from '../log';\nimport { WebSupportProjectPrerequisite } from '../start/doctor/web/WebSupportProjectPrerequisite';\nimport { DevServerManager } from '../start/server/DevServerManager';\nimport { MetroBundlerDevServer } from '../start/server/metro/MetroBundlerDevServer';\nimport { getRouterDirectoryModuleIdWithManifest } from '../start/server/metro/router';\nimport { serializeHtmlWithAssets } from '../start/server/metro/serializeHtml';\nimport { getEntryWithServerRoot } from '../start/server/middleware/ManifestMiddleware';\nimport { getBaseUrlFromExpoConfig } from '../start/server/middleware/metroOptions';\nimport { createTemplateHtmlFromExpoConfigAsync } from '../start/server/webTemplate';\nimport { env } from '../utils/env';\nimport { CommandError } from '../utils/errors';\nimport { setNodeEnv } from '../utils/nodeEnv';\n\nexport async function exportAppAsync(\n projectRoot: string,\n {\n platforms,\n outputDir,\n clear,\n dev,\n dumpAssetmap,\n sourceMaps,\n minify,\n bytecode,\n maxWorkers,\n skipSSG,\n }: Pick<\n Options,\n | 'dumpAssetmap'\n | 'sourceMaps'\n | 'dev'\n | 'clear'\n | 'outputDir'\n | 'platforms'\n | 'minify'\n | 'bytecode'\n | 'maxWorkers'\n | 'skipSSG'\n >\n): Promise<void> {\n // Force the environment during export and do not allow overriding it.\n const environment = dev ? 'development' : 'production';\n process.env.NODE_ENV = environment;\n setNodeEnv(environment);\n\n require('@expo/env').load(projectRoot);\n\n const projectConfig = getConfig(projectRoot);\n const exp = await getPublicExpoManifestAsync(projectRoot, {\n // Web doesn't require validation.\n skipValidation: platforms.length === 1 && platforms[0] === 'web',\n });\n\n if (platforms.includes('web')) {\n await new WebSupportProjectPrerequisite(projectRoot).assertAsync();\n }\n\n const useServerRendering = ['static', 'server'].includes(exp.web?.output ?? '');\n\n if (skipSSG && exp.web?.output !== 'server') {\n throw new CommandError('--no-ssg can only be used with `web.output: server`');\n }\n\n const baseUrl = getBaseUrlFromExpoConfig(exp);\n\n if (!bytecode && (platforms.includes('ios') || platforms.includes('android'))) {\n Log.warn(\n `Bytecode makes the app startup faster, disabling bytecode is highly discouraged and should only be used for debugging purposes.`\n );\n }\n\n // Print out logs\n if (baseUrl) {\n Log.log();\n Log.log(chalk.gray`Using (experimental) base path: ${baseUrl}`);\n // Warn if not using an absolute path.\n if (!baseUrl.startsWith('/')) {\n Log.log(\n chalk.yellow` Base path does not start with a slash. Requests will not be absolute.`\n );\n }\n }\n\n const mode = dev ? 'development' : 'production';\n const publicPath = path.resolve(projectRoot, env.EXPO_PUBLIC_FOLDER);\n const outputPath = path.resolve(projectRoot, outputDir);\n\n // Write the JS bundles to disk, and get the bundle file names (this could change with async chunk loading support).\n\n const files: ExportAssetMap = new Map();\n\n const devServerManager = await DevServerManager.startMetroAsync(projectRoot, {\n minify,\n mode,\n port: 8081,\n isExporting: true,\n location: {},\n resetDevServer: clear,\n maxWorkers,\n });\n\n const devServer = devServerManager.getDefaultDevServer();\n assert(devServer instanceof MetroBundlerDevServer);\n\n const bundles: Partial<Record<Platform, BundleOutput>> = {};\n const domComponentAssetsMetadata: Partial<Record<Platform, PlatformMetadata['assets']>> = {};\n\n const spaPlatforms =\n // TODO: Support server and static rendering for server component exports.\n useServerRendering && !devServer.isReactServerComponentsEnabled\n ? platforms.filter((platform) => platform !== 'web')\n : platforms;\n\n try {\n if (devServer.isReactServerComponentsEnabled) {\n // In RSC mode, we only need these to be in the client dir.\n // TODO: Merge back with other copy after we add SSR.\n try {\n await copyPublicFolderAsync(publicPath, path.join(outputPath, 'client'));\n } catch (error) {\n Log.error('Failed to copy public directory to dist directory');\n throw error;\n }\n } else {\n // NOTE(kitten): The public folder is currently always copied, regardless of targetDomain\n // split. Hence, there's another separate `copyPublicFolderAsync` call below for `web`\n await copyPublicFolderAsync(publicPath, outputPath);\n }\n\n let templateHtml: string | undefined;\n // Can be empty during web-only SSG.\n if (spaPlatforms.length) {\n await Promise.all(\n spaPlatforms.map(async (platform) => {\n // Assert early so the user doesn't have to wait until bundling is complete to find out that\n // Hermes won't be available.\n const isHermes = isEnableHermesManaged(exp, platform);\n if (isHermes) {\n await assertEngineMismatchAsync(projectRoot, exp, platform);\n }\n\n // Run metro bundler and create the JS bundles/source maps.\n const bundle = await devServer.nativeExportBundleAsync(\n exp,\n {\n platform,\n splitChunks:\n !env.EXPO_NO_BUNDLE_SPLITTING &&\n ((devServer.isReactServerComponentsEnabled && !bytecode) || platform === 'web'),\n mainModuleName: getEntryWithServerRoot(projectRoot, {\n platform,\n pkg: projectConfig.pkg,\n }),\n mode: dev ? 'development' : 'production',\n engine: isHermes ? 'hermes' : undefined,\n serializerIncludeMaps: sourceMaps,\n bytecode: bytecode && isHermes,\n reactCompiler: !!exp.experiments?.reactCompiler,\n },\n files\n );\n\n bundles[platform] = bundle;\n\n getFilesFromSerialAssets(bundle.artifacts, {\n includeSourceMaps: sourceMaps,\n files,\n isServerHosted: devServer.isReactServerComponentsEnabled,\n });\n\n // TODO: Remove duplicates...\n const expoDomComponentReferences = bundle.artifacts\n .map((artifact) =>\n Array.isArray(artifact.metadata.expoDomComponentReferences)\n ? artifact.metadata.expoDomComponentReferences\n : []\n )\n .flat();\n await Promise.all(\n // TODO: Make a version of this which uses `this.metro.getBundler().buildGraphForEntries([])` to bundle all the DOM components at once.\n expoDomComponentReferences.map(async (filePath) => {\n const { bundle: platformDomComponentsBundle, htmlOutputName } =\n await exportDomComponentAsync({\n filePath,\n projectRoot,\n dev,\n devServer,\n isHermes,\n includeSourceMaps: sourceMaps,\n exp,\n files,\n useMd5Filename: true,\n });\n\n // Merge the assets from the DOM component into the output assets.\n // @ts-expect-error: mutate assets\n bundle.assets.push(...platformDomComponentsBundle.assets);\n\n transformNativeBundleForMd5Filename({\n domComponentReference: filePath,\n nativeBundle: bundle,\n files,\n htmlOutputName,\n });\n domComponentAssetsMetadata[platform] = [\n ...(await addDomBundleToMetadataAsync(platformDomComponentsBundle)),\n ...transformDomEntryForMd5Filename({\n files,\n htmlOutputName,\n }),\n ];\n })\n );\n\n if (platform === 'web') {\n // TODO: Unify with exportStaticAsync\n // TODO: Maybe move to the serializer.\n let html = await serializeHtmlWithAssets({\n isExporting: true,\n resources: bundle.artifacts,\n template: await createTemplateHtmlFromExpoConfigAsync(projectRoot, {\n scripts: [],\n cssLinks: [],\n exp: projectConfig.exp,\n }),\n baseUrl,\n });\n\n // Add the favicon assets to the HTML.\n const modifyHtml = await getVirtualFaviconAssetsAsync(projectRoot, {\n outputDir,\n baseUrl,\n files,\n exp: projectConfig.exp,\n });\n if (modifyHtml) {\n html = modifyHtml(html);\n }\n\n // HACK: This is used for adding SSR shims in React Server Components.\n templateHtml = html;\n\n // Generate SPA-styled HTML file.\n // If web exists, then write the template HTML file.\n files.set('index.html', {\n contents: html,\n targetDomain: devServer.isReactServerComponentsEnabled ? 'server' : 'client',\n });\n }\n })\n );\n\n if (devServer.isReactServerComponentsEnabled) {\n const isWeb = platforms.includes('web');\n\n await exportApiRoutesStandaloneAsync(devServer, {\n files,\n platform: 'web',\n apiRoutesOnly: !isWeb,\n templateHtml,\n });\n }\n\n // TODO: Use same asset system across platforms again.\n const { assets, embeddedHashSet } = await exportAssetsAsync(projectRoot, {\n files,\n exp,\n outputDir: outputPath,\n bundles,\n baseUrl,\n });\n\n if (dumpAssetmap) {\n Log.log('Creating asset map');\n files.set('assetmap.json', { contents: JSON.stringify(createAssetMap({ assets })) });\n }\n\n const targetDomain = devServer.isReactServerComponentsEnabled ? 'client/' : '';\n const fileNames = Object.fromEntries(\n Object.entries(bundles).map(([platform, bundle]) => [\n platform,\n bundle.artifacts\n .filter((asset) => asset.type === 'js')\n .map((asset) => targetDomain + asset.filename),\n ])\n );\n\n // Generate a `metadata.json` for EAS Update.\n const contents = createMetadataJson({\n bundles,\n fileNames,\n embeddedHashSet,\n domComponentAssetsMetadata,\n });\n files.set('metadata.json', { contents: JSON.stringify(contents) });\n }\n\n // Additional web-only steps...\n\n if (platforms.includes('web') && useServerRendering) {\n const exportServer = exp.web?.output === 'server';\n\n if (exportServer) {\n // TODO: Remove when this is abstracted into the files map\n await copyPublicFolderAsync(publicPath, path.resolve(outputPath, 'client'));\n }\n\n if (skipSSG) {\n Log.log('Skipping static site generation');\n await exportApiRoutesStandaloneAsync(devServer, {\n files,\n platform: 'web',\n apiRoutesOnly: true,\n });\n\n // Output a placeholder index.html if one doesn't exist in the public directory.\n // This ensures native + API routes have some content at the root URL.\n const placeholderIndex = path.resolve(outputPath, 'client/index.html');\n if (!fs.existsSync(placeholderIndex)) {\n files.set('index.html', {\n contents: `<html><body></body></html>`,\n targetDomain: 'client',\n });\n }\n } else if (\n // TODO: Support static export with RSC.\n !devServer.isReactServerComponentsEnabled\n ) {\n await exportFromServerAsync(projectRoot, devServer, {\n mode,\n files,\n clear: !!clear,\n outputDir: outputPath,\n minify,\n baseUrl,\n includeSourceMaps: sourceMaps,\n routerRoot: getRouterDirectoryModuleIdWithManifest(projectRoot, exp),\n reactCompiler: !!exp.experiments?.reactCompiler,\n exportServer,\n maxWorkers,\n isExporting: true,\n exp: projectConfig.exp,\n });\n }\n }\n } finally {\n await devServerManager.stopAsync();\n }\n\n // Write all files at the end for unified logging.\n await persistMetroFilesAsync(files, outputPath);\n}\n"],"names":["exportAppAsync","projectRoot","platforms","outputDir","clear","dev","dumpAssetmap","sourceMaps","minify","bytecode","maxWorkers","skipSSG","exp","environment","process","env","NODE_ENV","setNodeEnv","require","load","projectConfig","getConfig","getPublicExpoManifestAsync","skipValidation","length","includes","WebSupportProjectPrerequisite","assertAsync","useServerRendering","web","output","CommandError","baseUrl","getBaseUrlFromExpoConfig","Log","warn","log","chalk","gray","startsWith","yellow","mode","publicPath","path","resolve","EXPO_PUBLIC_FOLDER","outputPath","files","Map","devServerManager","DevServerManager","startMetroAsync","port","isExporting","location","resetDevServer","devServer","getDefaultDevServer","assert","MetroBundlerDevServer","bundles","domComponentAssetsMetadata","spaPlatforms","isReactServerComponentsEnabled","filter","platform","copyPublicFolderAsync","join","error","templateHtml","Promise","all","map","isHermes","isEnableHermesManaged","assertEngineMismatchAsync","bundle","nativeExportBundleAsync","splitChunks","EXPO_NO_BUNDLE_SPLITTING","mainModuleName","getEntryWithServerRoot","pkg","engine","undefined","serializerIncludeMaps","reactCompiler","experiments","getFilesFromSerialAssets","artifacts","includeSourceMaps","isServerHosted","expoDomComponentReferences","artifact","Array","isArray","metadata","flat","filePath","platformDomComponentsBundle","htmlOutputName","exportDomComponentAsync","useMd5Filename","assets","push","transformNativeBundleForMd5Filename","domComponentReference","nativeBundle","addDomBundleToMetadataAsync","transformDomEntryForMd5Filename","html","serializeHtmlWithAssets","resources","template","createTemplateHtmlFromExpoConfigAsync","scripts","cssLinks","modifyHtml","getVirtualFaviconAssetsAsync","set","contents","targetDomain","isWeb","exportApiRoutesStandaloneAsync","apiRoutesOnly","embeddedHashSet","exportAssetsAsync","JSON","stringify","createAssetMap","fileNames","Object","fromEntries","entries","asset","type","filename","createMetadataJson","exportServer","placeholderIndex","fs","existsSync","exportFromServerAsync","routerRoot","getRouterDirectoryModuleIdWithManifest","stopAsync","persistMetroFilesAsync"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/export/exportApp.ts"],"sourcesContent":["import { getConfig } from '@expo/config';\nimport type { Platform } from '@expo/config';\nimport { SerialAsset } from '@expo/metro-config/build/serializer/serializerAssets';\nimport assert from 'assert';\nimport chalk from 'chalk';\nimport fs from 'fs';\nimport path from 'path';\n\nimport { type PlatformMetadata, createMetadataJson } from './createMetadataJson';\nimport { exportAssetsAsync } from './exportAssets';\nimport {\n addDomBundleToMetadataAsync,\n exportDomComponentAsync,\n transformNativeBundleForMd5Filename,\n transformDomEntryForMd5Filename,\n} from './exportDomComponents';\nimport { assertEngineMismatchAsync, isEnableHermesManaged } from './exportHermes';\nimport { exportApiRoutesStandaloneAsync, exportFromServerAsync } from './exportStaticAsync';\nimport { getVirtualFaviconAssetsAsync } from './favicon';\nimport { getPublicExpoManifestAsync } from './getPublicExpoManifest';\nimport { copyPublicFolderAsync } from './publicFolder';\nimport { Options } from './resolveOptions';\nimport {\n ExportAssetMap,\n BundleOutput,\n getFilesFromSerialAssets,\n persistMetroFilesAsync,\n BundleAssetWithFileHashes,\n} from './saveAssets';\nimport { createAssetMap } from './writeContents';\nimport * as Log from '../log';\nimport { WebSupportProjectPrerequisite } from '../start/doctor/web/WebSupportProjectPrerequisite';\nimport { DevServerManager } from '../start/server/DevServerManager';\nimport { MetroBundlerDevServer } from '../start/server/metro/MetroBundlerDevServer';\nimport { getRouterDirectoryModuleIdWithManifest } from '../start/server/metro/router';\nimport { serializeHtmlWithAssets } from '../start/server/metro/serializeHtml';\nimport { getEntryWithServerRoot } from '../start/server/middleware/ManifestMiddleware';\nimport { getBaseUrlFromExpoConfig } from '../start/server/middleware/metroOptions';\nimport { createTemplateHtmlFromExpoConfigAsync } from '../start/server/webTemplate';\nimport { env } from '../utils/env';\nimport { CommandError } from '../utils/errors';\nimport { setNodeEnv } from '../utils/nodeEnv';\n\nexport async function exportAppAsync(\n projectRoot: string,\n {\n platforms,\n outputDir,\n clear,\n dev,\n dumpAssetmap,\n sourceMaps,\n minify,\n bytecode,\n maxWorkers,\n skipSSG,\n }: Pick<\n Options,\n | 'dumpAssetmap'\n | 'sourceMaps'\n | 'dev'\n | 'clear'\n | 'outputDir'\n | 'platforms'\n | 'minify'\n | 'bytecode'\n | 'maxWorkers'\n | 'skipSSG'\n >\n): Promise<void> {\n // Force the environment during export and do not allow overriding it.\n const environment = dev ? 'development' : 'production';\n process.env.NODE_ENV = environment;\n setNodeEnv(environment);\n\n require('@expo/env').load(projectRoot);\n\n const projectConfig = getConfig(projectRoot);\n const exp = await getPublicExpoManifestAsync(projectRoot, {\n // Web doesn't require validation.\n skipValidation: platforms.length === 1 && platforms[0] === 'web',\n });\n\n if (platforms.includes('web')) {\n await new WebSupportProjectPrerequisite(projectRoot).assertAsync();\n }\n\n const useServerRendering = ['static', 'server'].includes(exp.web?.output ?? '');\n\n if (skipSSG && exp.web?.output !== 'server') {\n throw new CommandError('--no-ssg can only be used with `web.output: server`');\n }\n\n const baseUrl = getBaseUrlFromExpoConfig(exp);\n\n if (!bytecode && (platforms.includes('ios') || platforms.includes('android'))) {\n Log.warn(\n `Bytecode makes the app startup faster, disabling bytecode is highly discouraged and should only be used for debugging purposes.`\n );\n }\n\n // Print out logs\n if (baseUrl) {\n Log.log();\n Log.log(chalk.gray`Using (experimental) base path: ${baseUrl}`);\n // Warn if not using an absolute path.\n if (!baseUrl.startsWith('/')) {\n Log.log(\n chalk.yellow` Base path does not start with a slash. Requests will not be absolute.`\n );\n }\n }\n\n const mode = dev ? 'development' : 'production';\n const publicPath = path.resolve(projectRoot, env.EXPO_PUBLIC_FOLDER);\n const outputPath = path.resolve(projectRoot, outputDir);\n\n // Write the JS bundles to disk, and get the bundle file names (this could change with async chunk loading support).\n\n const files: ExportAssetMap = new Map();\n\n const devServerManager = await DevServerManager.startMetroAsync(projectRoot, {\n minify,\n mode,\n port: 8081,\n isExporting: true,\n location: {},\n resetDevServer: clear,\n maxWorkers,\n });\n\n const devServer = devServerManager.getDefaultDevServer();\n assert(devServer instanceof MetroBundlerDevServer);\n\n const bundles: Partial<Record<Platform, BundleOutput>> = {};\n const domComponentAssetsMetadata: Partial<Record<Platform, PlatformMetadata['assets']>> = {};\n\n const spaPlatforms =\n // TODO: Support server and static rendering for server component exports.\n useServerRendering && !devServer.isReactServerComponentsEnabled\n ? platforms.filter((platform) => platform !== 'web')\n : platforms;\n\n try {\n if (devServer.isReactServerComponentsEnabled) {\n // In RSC mode, we only need these to be in the client dir.\n // TODO: Merge back with other copy after we add SSR.\n try {\n await copyPublicFolderAsync(publicPath, path.join(outputPath, 'client'));\n } catch (error) {\n Log.error('Failed to copy public directory to dist directory');\n throw error;\n }\n } else {\n // NOTE(kitten): The public folder is currently always copied, regardless of targetDomain\n // split. Hence, there's another separate `copyPublicFolderAsync` call below for `web`\n await copyPublicFolderAsync(publicPath, outputPath);\n }\n\n let templateHtml: string | undefined;\n // Can be empty during web-only SSG.\n if (spaPlatforms.length) {\n await Promise.all(\n spaPlatforms.map(async (platform) => {\n // Assert early so the user doesn't have to wait until bundling is complete to find out that\n // Hermes won't be available.\n const isHermes = isEnableHermesManaged(exp, platform);\n if (isHermes) {\n await assertEngineMismatchAsync(projectRoot, exp, platform);\n }\n\n let bundle: {\n artifacts: SerialAsset[];\n assets: readonly BundleAssetWithFileHashes[];\n files?: ExportAssetMap;\n };\n\n try {\n // Run metro bundler and create the JS bundles/source maps.\n bundle = await devServer.nativeExportBundleAsync(\n exp,\n {\n platform,\n splitChunks:\n !env.EXPO_NO_BUNDLE_SPLITTING &&\n ((devServer.isReactServerComponentsEnabled && !bytecode) || platform === 'web'),\n mainModuleName: getEntryWithServerRoot(projectRoot, {\n platform,\n pkg: projectConfig.pkg,\n }),\n mode: dev ? 'development' : 'production',\n engine: isHermes ? 'hermes' : undefined,\n serializerIncludeMaps: sourceMaps,\n bytecode: bytecode && isHermes,\n reactCompiler: !!exp.experiments?.reactCompiler,\n },\n files\n );\n } catch (error) {\n Log.log('');\n if (error instanceof Error) {\n Log.exception(error);\n } else {\n Log.error('Failed to bundle the app');\n Log.log(error as any);\n }\n process.exit(1);\n }\n\n bundles[platform] = bundle;\n\n getFilesFromSerialAssets(bundle.artifacts, {\n includeSourceMaps: sourceMaps,\n files,\n isServerHosted: devServer.isReactServerComponentsEnabled,\n });\n\n // TODO: Remove duplicates...\n const expoDomComponentReferences = bundle.artifacts\n .map((artifact) =>\n Array.isArray(artifact.metadata.expoDomComponentReferences)\n ? artifact.metadata.expoDomComponentReferences\n : []\n )\n .flat();\n await Promise.all(\n // TODO: Make a version of this which uses `this.metro.getBundler().buildGraphForEntries([])` to bundle all the DOM components at once.\n expoDomComponentReferences.map(async (filePath) => {\n const { bundle: platformDomComponentsBundle, htmlOutputName } =\n await exportDomComponentAsync({\n filePath,\n projectRoot,\n dev,\n devServer,\n isHermes,\n includeSourceMaps: sourceMaps,\n exp,\n files,\n useMd5Filename: true,\n });\n\n // Merge the assets from the DOM component into the output assets.\n // @ts-expect-error: mutate assets\n bundle.assets.push(...platformDomComponentsBundle.assets);\n\n transformNativeBundleForMd5Filename({\n domComponentReference: filePath,\n nativeBundle: bundle,\n files,\n htmlOutputName,\n });\n domComponentAssetsMetadata[platform] = [\n ...(await addDomBundleToMetadataAsync(platformDomComponentsBundle)),\n ...transformDomEntryForMd5Filename({\n files,\n htmlOutputName,\n }),\n ];\n })\n );\n\n if (platform === 'web') {\n // TODO: Unify with exportStaticAsync\n // TODO: Maybe move to the serializer.\n let html = await serializeHtmlWithAssets({\n isExporting: true,\n resources: bundle.artifacts,\n template: await createTemplateHtmlFromExpoConfigAsync(projectRoot, {\n scripts: [],\n cssLinks: [],\n exp: projectConfig.exp,\n }),\n baseUrl,\n });\n\n // Add the favicon assets to the HTML.\n const modifyHtml = await getVirtualFaviconAssetsAsync(projectRoot, {\n outputDir,\n baseUrl,\n files,\n exp: projectConfig.exp,\n });\n if (modifyHtml) {\n html = modifyHtml(html);\n }\n\n // HACK: This is used for adding SSR shims in React Server Components.\n templateHtml = html;\n\n // Generate SPA-styled HTML file.\n // If web exists, then write the template HTML file.\n files.set('index.html', {\n contents: html,\n targetDomain: devServer.isReactServerComponentsEnabled ? 'server' : 'client',\n });\n }\n })\n );\n\n if (devServer.isReactServerComponentsEnabled) {\n const isWeb = platforms.includes('web');\n\n await exportApiRoutesStandaloneAsync(devServer, {\n files,\n platform: 'web',\n apiRoutesOnly: !isWeb,\n templateHtml,\n });\n }\n\n // TODO: Use same asset system across platforms again.\n const { assets, embeddedHashSet } = await exportAssetsAsync(projectRoot, {\n files,\n exp,\n outputDir: outputPath,\n bundles,\n baseUrl,\n });\n\n if (dumpAssetmap) {\n Log.log('Creating asset map');\n files.set('assetmap.json', { contents: JSON.stringify(createAssetMap({ assets })) });\n }\n\n const targetDomain = devServer.isReactServerComponentsEnabled ? 'client/' : '';\n const fileNames = Object.fromEntries(\n Object.entries(bundles).map(([platform, bundle]) => [\n platform,\n bundle.artifacts\n .filter((asset) => asset.type === 'js')\n .map((asset) => targetDomain + asset.filename),\n ])\n );\n\n // Generate a `metadata.json` for EAS Update.\n const contents = createMetadataJson({\n bundles,\n fileNames,\n embeddedHashSet,\n domComponentAssetsMetadata,\n });\n files.set('metadata.json', { contents: JSON.stringify(contents) });\n }\n\n // Additional web-only steps...\n\n if (platforms.includes('web') && useServerRendering) {\n const exportServer = exp.web?.output === 'server';\n\n if (exportServer) {\n // TODO: Remove when this is abstracted into the files map\n await copyPublicFolderAsync(publicPath, path.resolve(outputPath, 'client'));\n }\n\n if (skipSSG) {\n Log.log('Skipping static site generation');\n await exportApiRoutesStandaloneAsync(devServer, {\n files,\n platform: 'web',\n apiRoutesOnly: true,\n });\n\n // Output a placeholder index.html if one doesn't exist in the public directory.\n // This ensures native + API routes have some content at the root URL.\n const placeholderIndex = path.resolve(outputPath, 'client/index.html');\n if (!fs.existsSync(placeholderIndex)) {\n files.set('index.html', {\n contents: `<html><body></body></html>`,\n targetDomain: 'client',\n });\n }\n } else if (\n // TODO: Support static export with RSC.\n !devServer.isReactServerComponentsEnabled\n ) {\n await exportFromServerAsync(projectRoot, devServer, {\n mode,\n files,\n clear: !!clear,\n outputDir: outputPath,\n minify,\n baseUrl,\n includeSourceMaps: sourceMaps,\n routerRoot: getRouterDirectoryModuleIdWithManifest(projectRoot, exp),\n reactCompiler: !!exp.experiments?.reactCompiler,\n exportServer,\n maxWorkers,\n isExporting: true,\n exp: projectConfig.exp,\n });\n }\n }\n } finally {\n await devServerManager.stopAsync();\n }\n\n // Write all files at the end for unified logging.\n await persistMetroFilesAsync(files, outputPath);\n}\n"],"names":["exportAppAsync","projectRoot","platforms","outputDir","clear","dev","dumpAssetmap","sourceMaps","minify","bytecode","maxWorkers","skipSSG","exp","environment","process","env","NODE_ENV","setNodeEnv","require","load","projectConfig","getConfig","getPublicExpoManifestAsync","skipValidation","length","includes","WebSupportProjectPrerequisite","assertAsync","useServerRendering","web","output","CommandError","baseUrl","getBaseUrlFromExpoConfig","Log","warn","log","chalk","gray","startsWith","yellow","mode","publicPath","path","resolve","EXPO_PUBLIC_FOLDER","outputPath","files","Map","devServerManager","DevServerManager","startMetroAsync","port","isExporting","location","resetDevServer","devServer","getDefaultDevServer","assert","MetroBundlerDevServer","bundles","domComponentAssetsMetadata","spaPlatforms","isReactServerComponentsEnabled","filter","platform","copyPublicFolderAsync","join","error","templateHtml","Promise","all","map","isHermes","isEnableHermesManaged","assertEngineMismatchAsync","bundle","nativeExportBundleAsync","splitChunks","EXPO_NO_BUNDLE_SPLITTING","mainModuleName","getEntryWithServerRoot","pkg","engine","undefined","serializerIncludeMaps","reactCompiler","experiments","Error","exception","exit","getFilesFromSerialAssets","artifacts","includeSourceMaps","isServerHosted","expoDomComponentReferences","artifact","Array","isArray","metadata","flat","filePath","platformDomComponentsBundle","htmlOutputName","exportDomComponentAsync","useMd5Filename","assets","push","transformNativeBundleForMd5Filename","domComponentReference","nativeBundle","addDomBundleToMetadataAsync","transformDomEntryForMd5Filename","html","serializeHtmlWithAssets","resources","template","createTemplateHtmlFromExpoConfigAsync","scripts","cssLinks","modifyHtml","getVirtualFaviconAssetsAsync","set","contents","targetDomain","isWeb","exportApiRoutesStandaloneAsync","apiRoutesOnly","embeddedHashSet","exportAssetsAsync","JSON","stringify","createAssetMap","fileNames","Object","fromEntries","entries","asset","type","filename","createMetadataJson","exportServer","placeholderIndex","fs","existsSync","exportFromServerAsync","routerRoot","getRouterDirectoryModuleIdWithManifest","stopAsync","persistMetroFilesAsync"],"mappings":";;;;+BA2CsBA;;;eAAAA;;;;yBA3CI;;;;;;;gEAGP;;;;;;;gEACD;;;;;;;gEACH;;;;;;;gEACE;;;;;;oCAEyC;8BACxB;qCAM3B;8BAC0D;mCACK;yBACzB;uCACF;8BACL;4BAQ/B;+BACwB;6DACV;+CACyB;kCACb;uCACK;wBACiB;+BACf;oCACD;8BACE;6BACa;qBAClC;wBACS;yBACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEpB,eAAeA,eACpBC,WAAmB,EACnB,EACEC,SAAS,EACTC,SAAS,EACTC,KAAK,EACLC,GAAG,EACHC,YAAY,EACZC,UAAU,EACVC,MAAM,EACNC,QAAQ,EACRC,UAAU,EACVC,OAAO,EAaR;QAmBwDC,UAE1CA;IAnBf,sEAAsE;IACtE,MAAMC,cAAcR,MAAM,gBAAgB;IAC1CS,QAAQC,GAAG,CAACC,QAAQ,GAAGH;IACvBI,IAAAA,mBAAU,EAACJ;IAEXK,QAAQ,aAAaC,IAAI,CAAClB;IAE1B,MAAMmB,gBAAgBC,IAAAA,mBAAS,EAACpB;IAChC,MAAMW,MAAM,MAAMU,IAAAA,iDAA0B,EAACrB,aAAa;QACxD,kCAAkC;QAClCsB,gBAAgBrB,UAAUsB,MAAM,KAAK,KAAKtB,SAAS,CAAC,EAAE,KAAK;IAC7D;IAEA,IAAIA,UAAUuB,QAAQ,CAAC,QAAQ;QAC7B,MAAM,IAAIC,4DAA6B,CAACzB,aAAa0B,WAAW;IAClE;IAEA,MAAMC,qBAAqB;QAAC;QAAU;KAAS,CAACH,QAAQ,CAACb,EAAAA,WAAAA,IAAIiB,GAAG,qBAAPjB,SAASkB,MAAM,KAAI;IAE5E,IAAInB,WAAWC,EAAAA,YAAAA,IAAIiB,GAAG,qBAAPjB,UAASkB,MAAM,MAAK,UAAU;QAC3C,MAAM,IAAIC,oBAAY,CAAC;IACzB;IAEA,MAAMC,UAAUC,IAAAA,sCAAwB,EAACrB;IAEzC,IAAI,CAACH,YAAaP,CAAAA,UAAUuB,QAAQ,CAAC,UAAUvB,UAAUuB,QAAQ,CAAC,UAAS,GAAI;QAC7ES,KAAIC,IAAI,CACN,CAAC,+HAA+H,CAAC;IAErI;IAEA,iBAAiB;IACjB,IAAIH,SAAS;QACXE,KAAIE,GAAG;QACPF,KAAIE,GAAG,CAACC,gBAAK,CAACC,IAAI,CAAC,gCAAgC,EAAEN,QAAQ,CAAC;QAC9D,sCAAsC;QACtC,IAAI,CAACA,QAAQO,UAAU,CAAC,MAAM;YAC5BL,KAAIE,GAAG,CACLC,gBAAK,CAACG,MAAM,CAAC,uEAAuE,CAAC;QAEzF;IACF;IAEA,MAAMC,OAAOpC,MAAM,gBAAgB;IACnC,MAAMqC,aAAaC,eAAI,CAACC,OAAO,CAAC3C,aAAac,QAAG,CAAC8B,kBAAkB;IACnE,MAAMC,aAAaH,eAAI,CAACC,OAAO,CAAC3C,aAAaE;IAE7C,oHAAoH;IAEpH,MAAM4C,QAAwB,IAAIC;IAElC,MAAMC,mBAAmB,MAAMC,kCAAgB,CAACC,eAAe,CAAClD,aAAa;QAC3EO;QACAiC;QACAW,MAAM;QACNC,aAAa;QACbC,UAAU,CAAC;QACXC,gBAAgBnD;QAChBM;IACF;IAEA,MAAM8C,YAAYP,iBAAiBQ,mBAAmB;IACtDC,IAAAA,iBAAM,EAACF,qBAAqBG,4CAAqB;IAEjD,MAAMC,UAAmD,CAAC;IAC1D,MAAMC,6BAAoF,CAAC;IAE3F,MAAMC,eACJ,0EAA0E;IAC1ElC,sBAAsB,CAAC4B,UAAUO,8BAA8B,GAC3D7D,UAAU8D,MAAM,CAAC,CAACC,WAAaA,aAAa,SAC5C/D;IAEN,IAAI;QACF,IAAIsD,UAAUO,8BAA8B,EAAE;YAC5C,2DAA2D;YAC3D,qDAAqD;YACrD,IAAI;gBACF,MAAMG,IAAAA,mCAAqB,EAACxB,YAAYC,eAAI,CAACwB,IAAI,CAACrB,YAAY;YAChE,EAAE,OAAOsB,OAAO;gBACdlC,KAAIkC,KAAK,CAAC;gBACV,MAAMA;YACR;QACF,OAAO;YACL,yFAAyF;YACzF,sFAAsF;YACtF,MAAMF,IAAAA,mCAAqB,EAACxB,YAAYI;QAC1C;QAEA,IAAIuB;QACJ,oCAAoC;QACpC,IAAIP,aAAatC,MAAM,EAAE;YACvB,MAAM8C,QAAQC,GAAG,CACfT,aAAaU,GAAG,CAAC,OAAOP;gBACtB,4FAA4F;gBAC5F,6BAA6B;gBAC7B,MAAMQ,WAAWC,IAAAA,mCAAqB,EAAC9D,KAAKqD;gBAC5C,IAAIQ,UAAU;oBACZ,MAAME,IAAAA,uCAAyB,EAAC1E,aAAaW,KAAKqD;gBACpD;gBAEA,IAAIW;gBAMJ,IAAI;wBAiBmBhE;oBAhBrB,2DAA2D;oBAC3DgE,SAAS,MAAMpB,UAAUqB,uBAAuB,CAC9CjE,KACA;wBACEqD;wBACAa,aACE,CAAC/D,QAAG,CAACgE,wBAAwB,IAC5B,CAAA,AAACvB,UAAUO,8BAA8B,IAAI,CAACtD,YAAawD,aAAa,KAAI;wBAC/Ee,gBAAgBC,IAAAA,0CAAsB,EAAChF,aAAa;4BAClDgE;4BACAiB,KAAK9D,cAAc8D,GAAG;wBACxB;wBACAzC,MAAMpC,MAAM,gBAAgB;wBAC5B8E,QAAQV,WAAW,WAAWW;wBAC9BC,uBAAuB9E;wBACvBE,UAAUA,YAAYgE;wBACtBa,eAAe,CAAC,GAAC1E,mBAAAA,IAAI2E,WAAW,qBAAf3E,iBAAiB0E,aAAa;oBACjD,GACAvC;gBAEJ,EAAE,OAAOqB,OAAO;oBACdlC,KAAIE,GAAG,CAAC;oBACR,IAAIgC,iBAAiBoB,OAAO;wBAC1BtD,KAAIuD,SAAS,CAACrB;oBAChB,OAAO;wBACLlC,KAAIkC,KAAK,CAAC;wBACVlC,KAAIE,GAAG,CAACgC;oBACV;oBACAtD,QAAQ4E,IAAI,CAAC;gBACf;gBAEA9B,OAAO,CAACK,SAAS,GAAGW;gBAEpBe,IAAAA,oCAAwB,EAACf,OAAOgB,SAAS,EAAE;oBACzCC,mBAAmBtF;oBACnBwC;oBACA+C,gBAAgBtC,UAAUO,8BAA8B;gBAC1D;gBAEA,6BAA6B;gBAC7B,MAAMgC,6BAA6BnB,OAAOgB,SAAS,CAChDpB,GAAG,CAAC,CAACwB,WACJC,MAAMC,OAAO,CAACF,SAASG,QAAQ,CAACJ,0BAA0B,IACtDC,SAASG,QAAQ,CAACJ,0BAA0B,GAC5C,EAAE,EAEPK,IAAI;gBACP,MAAM9B,QAAQC,GAAG,CACf,uIAAuI;gBACvIwB,2BAA2BvB,GAAG,CAAC,OAAO6B;oBACpC,MAAM,EAAEzB,QAAQ0B,2BAA2B,EAAEC,cAAc,EAAE,GAC3D,MAAMC,IAAAA,4CAAuB,EAAC;wBAC5BH;wBACApG;wBACAI;wBACAmD;wBACAiB;wBACAoB,mBAAmBtF;wBACnBK;wBACAmC;wBACA0D,gBAAgB;oBAClB;oBAEF,kEAAkE;oBAClE,kCAAkC;oBAClC7B,OAAO8B,MAAM,CAACC,IAAI,IAAIL,4BAA4BI,MAAM;oBAExDE,IAAAA,wDAAmC,EAAC;wBAClCC,uBAAuBR;wBACvBS,cAAclC;wBACd7B;wBACAwD;oBACF;oBACA1C,0BAA0B,CAACI,SAAS,GAAG;2BACjC,MAAM8C,IAAAA,gDAA2B,EAACT;2BACnCU,IAAAA,oDAA+B,EAAC;4BACjCjE;4BACAwD;wBACF;qBACD;gBACH;gBAGF,IAAItC,aAAa,OAAO;oBACtB,qCAAqC;oBACrC,sCAAsC;oBACtC,IAAIgD,OAAO,MAAMC,IAAAA,sCAAuB,EAAC;wBACvC7D,aAAa;wBACb8D,WAAWvC,OAAOgB,SAAS;wBAC3BwB,UAAU,MAAMC,IAAAA,kDAAqC,EAACpH,aAAa;4BACjEqH,SAAS,EAAE;4BACXC,UAAU,EAAE;4BACZ3G,KAAKQ,cAAcR,GAAG;wBACxB;wBACAoB;oBACF;oBAEA,sCAAsC;oBACtC,MAAMwF,aAAa,MAAMC,IAAAA,qCAA4B,EAACxH,aAAa;wBACjEE;wBACA6B;wBACAe;wBACAnC,KAAKQ,cAAcR,GAAG;oBACxB;oBACA,IAAI4G,YAAY;wBACdP,OAAOO,WAAWP;oBACpB;oBAEA,sEAAsE;oBACtE5C,eAAe4C;oBAEf,iCAAiC;oBACjC,oDAAoD;oBACpDlE,MAAM2E,GAAG,CAAC,cAAc;wBACtBC,UAAUV;wBACVW,cAAcpE,UAAUO,8BAA8B,GAAG,WAAW;oBACtE;gBACF;YACF;YAGF,IAAIP,UAAUO,8BAA8B,EAAE;gBAC5C,MAAM8D,QAAQ3H,UAAUuB,QAAQ,CAAC;gBAEjC,MAAMqG,IAAAA,iDAA8B,EAACtE,WAAW;oBAC9CT;oBACAkB,UAAU;oBACV8D,eAAe,CAACF;oBAChBxD;gBACF;YACF;YAEA,sDAAsD;YACtD,MAAM,EAAEqC,MAAM,EAAEsB,eAAe,EAAE,GAAG,MAAMC,IAAAA,+BAAiB,EAAChI,aAAa;gBACvE8C;gBACAnC;gBACAT,WAAW2C;gBACXc;gBACA5B;YACF;YAEA,IAAI1B,cAAc;gBAChB4B,KAAIE,GAAG,CAAC;gBACRW,MAAM2E,GAAG,CAAC,iBAAiB;oBAAEC,UAAUO,KAAKC,SAAS,CAACC,IAAAA,6BAAc,EAAC;wBAAE1B;oBAAO;gBAAI;YACpF;YAEA,MAAMkB,eAAepE,UAAUO,8BAA8B,GAAG,YAAY;YAC5E,MAAMsE,YAAYC,OAAOC,WAAW,CAClCD,OAAOE,OAAO,CAAC5E,SAASY,GAAG,CAAC,CAAC,CAACP,UAAUW,OAAO,GAAK;oBAClDX;oBACAW,OAAOgB,SAAS,CACb5B,MAAM,CAAC,CAACyE,QAAUA,MAAMC,IAAI,KAAK,MACjClE,GAAG,CAAC,CAACiE,QAAUb,eAAea,MAAME,QAAQ;iBAChD;YAGH,6CAA6C;YAC7C,MAAMhB,WAAWiB,IAAAA,sCAAkB,EAAC;gBAClChF;gBACAyE;gBACAL;gBACAnE;YACF;YACAd,MAAM2E,GAAG,CAAC,iBAAiB;gBAAEC,UAAUO,KAAKC,SAAS,CAACR;YAAU;QAClE;QAEA,+BAA+B;QAE/B,IAAIzH,UAAUuB,QAAQ,CAAC,UAAUG,oBAAoB;gBAC9BhB;YAArB,MAAMiI,eAAejI,EAAAA,YAAAA,IAAIiB,GAAG,qBAAPjB,UAASkB,MAAM,MAAK;YAEzC,IAAI+G,cAAc;gBAChB,0DAA0D;gBAC1D,MAAM3E,IAAAA,mCAAqB,EAACxB,YAAYC,eAAI,CAACC,OAAO,CAACE,YAAY;YACnE;YAEA,IAAInC,SAAS;gBACXuB,KAAIE,GAAG,CAAC;gBACR,MAAM0F,IAAAA,iDAA8B,EAACtE,WAAW;oBAC9CT;oBACAkB,UAAU;oBACV8D,eAAe;gBACjB;gBAEA,gFAAgF;gBAChF,sEAAsE;gBACtE,MAAMe,mBAAmBnG,eAAI,CAACC,OAAO,CAACE,YAAY;gBAClD,IAAI,CAACiG,aAAE,CAACC,UAAU,CAACF,mBAAmB;oBACpC/F,MAAM2E,GAAG,CAAC,cAAc;wBACtBC,UAAU,CAAC,0BAA0B,CAAC;wBACtCC,cAAc;oBAChB;gBACF;YACF,OAAO,IACL,wCAAwC;YACxC,CAACpE,UAAUO,8BAA8B,EACzC;oBAUmBnD;gBATnB,MAAMqI,IAAAA,wCAAqB,EAAChJ,aAAauD,WAAW;oBAClDf;oBACAM;oBACA3C,OAAO,CAAC,CAACA;oBACTD,WAAW2C;oBACXtC;oBACAwB;oBACA6D,mBAAmBtF;oBACnB2I,YAAYC,IAAAA,8CAAsC,EAAClJ,aAAaW;oBAChE0E,eAAe,CAAC,GAAC1E,mBAAAA,IAAI2E,WAAW,qBAAf3E,iBAAiB0E,aAAa;oBAC/CuD;oBACAnI;oBACA2C,aAAa;oBACbzC,KAAKQ,cAAcR,GAAG;gBACxB;YACF;QACF;IACF,SAAU;QACR,MAAMqC,iBAAiBmG,SAAS;IAClC;IAEA,kDAAkD;IAClD,MAAMC,IAAAA,kCAAsB,EAACtG,OAAOD;AACtC"}
@@ -27,6 +27,7 @@ const _log = /*#__PURE__*/ _interop_require_wildcard(require("../log"));
27
27
  const _attachAtlas = require("../start/server/metro/debugging/attachAtlas");
28
28
  const _FileNotifier = require("../utils/FileNotifier");
29
29
  const _dir = require("../utils/dir");
30
+ const _errors = require("../utils/errors");
30
31
  const _exit = require("../utils/exit");
31
32
  function _interop_require_default(obj) {
32
33
  return obj && obj.__esModule ? obj : {
@@ -77,6 +78,11 @@ function _interop_require_wildcard(obj, nodeInterop) {
77
78
  async function exportAsync(projectRoot, options) {
78
79
  // Ensure the output directory is created
79
80
  const outputPath = _path().default.resolve(projectRoot, options.outputDir);
81
+ if (outputPath === projectRoot) {
82
+ throw new _errors.CommandError('--output-dir cannot be the same as the project directory.');
83
+ } else if (_path().default.relative(projectRoot, outputPath).startsWith('..')) {
84
+ throw new _errors.CommandError('--output-dir must be a subdirectory of the project directory. Generating outside of the project directory is not supported.');
85
+ }
80
86
  // Delete the output directory if it exists
81
87
  await (0, _dir.removeAsync)(outputPath);
82
88
  // Create the output directory
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/export/exportAsync.ts"],"sourcesContent":["import chalk from 'chalk';\nimport path from 'path';\n\nimport { exportAppAsync } from './exportApp';\nimport { Options } from './resolveOptions';\nimport * as Log from '../log';\nimport { waitUntilAtlasExportIsReadyAsync } from '../start/server/metro/debugging/attachAtlas';\nimport { FileNotifier } from '../utils/FileNotifier';\nimport { ensureDirectoryAsync, removeAsync } from '../utils/dir';\nimport { ensureProcessExitsAfterDelay } from '../utils/exit';\n\nexport async function exportAsync(projectRoot: string, options: Options) {\n // Ensure the output directory is created\n const outputPath = path.resolve(projectRoot, options.outputDir);\n // Delete the output directory if it exists\n await removeAsync(outputPath);\n // Create the output directory\n await ensureDirectoryAsync(outputPath);\n\n // Export the app\n await exportAppAsync(projectRoot, options);\n\n // Stop any file watchers to prevent the CLI from hanging.\n FileNotifier.stopAll();\n // Wait until Atlas is ready, when enabled\n // NOTE(cedric): this is a workaround, remove when `process.exit` is removed\n await waitUntilAtlasExportIsReadyAsync(projectRoot);\n\n // Final notes\n Log.log(chalk.greenBright`Exported: ${options.outputDir}`);\n\n // Exit the process to stop any hanging processes from reading the app.config.js or server rendering.\n ensureProcessExitsAfterDelay();\n}\n"],"names":["exportAsync","projectRoot","options","outputPath","path","resolve","outputDir","removeAsync","ensureDirectoryAsync","exportAppAsync","FileNotifier","stopAll","waitUntilAtlasExportIsReadyAsync","Log","log","chalk","greenBright","ensureProcessExitsAfterDelay"],"mappings":";;;;+BAWsBA;;;eAAAA;;;;gEAXJ;;;;;;;gEACD;;;;;;2BAEc;6DAEV;6BAC4B;8BACpB;qBACqB;sBACL;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEtC,eAAeA,YAAYC,WAAmB,EAAEC,OAAgB;IACrE,yCAAyC;IACzC,MAAMC,aAAaC,eAAI,CAACC,OAAO,CAACJ,aAAaC,QAAQI,SAAS;IAC9D,2CAA2C;IAC3C,MAAMC,IAAAA,gBAAW,EAACJ;IAClB,8BAA8B;IAC9B,MAAMK,IAAAA,yBAAoB,EAACL;IAE3B,iBAAiB;IACjB,MAAMM,IAAAA,yBAAc,EAACR,aAAaC;IAElC,0DAA0D;IAC1DQ,0BAAY,CAACC,OAAO;IACpB,0CAA0C;IAC1C,4EAA4E;IAC5E,MAAMC,IAAAA,6CAAgC,EAACX;IAEvC,cAAc;IACdY,KAAIC,GAAG,CAACC,gBAAK,CAACC,WAAW,CAAC,UAAU,EAAEd,QAAQI,SAAS,CAAC,CAAC;IAEzD,qGAAqG;IACrGW,IAAAA,kCAA4B;AAC9B"}
1
+ {"version":3,"sources":["../../../src/export/exportAsync.ts"],"sourcesContent":["import chalk from 'chalk';\nimport path from 'path';\n\nimport { exportAppAsync } from './exportApp';\nimport { Options } from './resolveOptions';\nimport * as Log from '../log';\nimport { waitUntilAtlasExportIsReadyAsync } from '../start/server/metro/debugging/attachAtlas';\nimport { FileNotifier } from '../utils/FileNotifier';\nimport { ensureDirectoryAsync, removeAsync } from '../utils/dir';\nimport { CommandError } from '../utils/errors';\nimport { ensureProcessExitsAfterDelay } from '../utils/exit';\n\nexport async function exportAsync(projectRoot: string, options: Options) {\n // Ensure the output directory is created\n const outputPath = path.resolve(projectRoot, options.outputDir);\n\n if (outputPath === projectRoot) {\n throw new CommandError('--output-dir cannot be the same as the project directory.');\n } else if (path.relative(projectRoot, outputPath).startsWith('..')) {\n throw new CommandError(\n '--output-dir must be a subdirectory of the project directory. Generating outside of the project directory is not supported.'\n );\n }\n\n // Delete the output directory if it exists\n await removeAsync(outputPath);\n // Create the output directory\n await ensureDirectoryAsync(outputPath);\n\n // Export the app\n await exportAppAsync(projectRoot, options);\n\n // Stop any file watchers to prevent the CLI from hanging.\n FileNotifier.stopAll();\n // Wait until Atlas is ready, when enabled\n // NOTE(cedric): this is a workaround, remove when `process.exit` is removed\n await waitUntilAtlasExportIsReadyAsync(projectRoot);\n\n // Final notes\n Log.log(chalk.greenBright`Exported: ${options.outputDir}`);\n\n // Exit the process to stop any hanging processes from reading the app.config.js or server rendering.\n ensureProcessExitsAfterDelay();\n}\n"],"names":["exportAsync","projectRoot","options","outputPath","path","resolve","outputDir","CommandError","relative","startsWith","removeAsync","ensureDirectoryAsync","exportAppAsync","FileNotifier","stopAll","waitUntilAtlasExportIsReadyAsync","Log","log","chalk","greenBright","ensureProcessExitsAfterDelay"],"mappings":";;;;+BAYsBA;;;eAAAA;;;;gEAZJ;;;;;;;gEACD;;;;;;2BAEc;6DAEV;6BAC4B;8BACpB;qBACqB;wBACrB;sBACgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEtC,eAAeA,YAAYC,WAAmB,EAAEC,OAAgB;IACrE,yCAAyC;IACzC,MAAMC,aAAaC,eAAI,CAACC,OAAO,CAACJ,aAAaC,QAAQI,SAAS;IAE9D,IAAIH,eAAeF,aAAa;QAC9B,MAAM,IAAIM,oBAAY,CAAC;IACzB,OAAO,IAAIH,eAAI,CAACI,QAAQ,CAACP,aAAaE,YAAYM,UAAU,CAAC,OAAO;QAClE,MAAM,IAAIF,oBAAY,CACpB;IAEJ;IAEA,2CAA2C;IAC3C,MAAMG,IAAAA,gBAAW,EAACP;IAClB,8BAA8B;IAC9B,MAAMQ,IAAAA,yBAAoB,EAACR;IAE3B,iBAAiB;IACjB,MAAMS,IAAAA,yBAAc,EAACX,aAAaC;IAElC,0DAA0D;IAC1DW,0BAAY,CAACC,OAAO;IACpB,0CAA0C;IAC1C,4EAA4E;IAC5E,MAAMC,IAAAA,6CAAgC,EAACd;IAEvC,cAAc;IACde,KAAIC,GAAG,CAACC,gBAAK,CAACC,WAAW,CAAC,UAAU,EAAEjB,QAAQI,SAAS,CAAC,CAAC;IAEzD,qGAAqG;IACrGc,IAAAA,kCAA4B;AAC9B"}
@@ -115,10 +115,10 @@ function parseGradleProperties(content) {
115
115
  async function maybeThrowFromInconsistentEngineAsync(projectRoot, configFilePath, platform, isHermesManaged) {
116
116
  const configFileName = _path().default.basename(configFilePath);
117
117
  if (platform === 'android' && await maybeInconsistentEngineAndroidAsync(projectRoot, isHermesManaged)) {
118
- throw new Error(`JavaScript engine configuration is inconsistent between ${configFileName} and Android native project.\n` + `In ${configFileName}: Hermes is ${isHermesManaged ? 'enabled' : 'not enabled'}\n` + `In Android native project: Hermes is ${isHermesManaged ? 'not enabled' : 'enabled'}\n` + `Please check the following files for inconsistencies:\n` + ` - ${configFilePath}\n` + ` - ${_path().default.join(projectRoot, 'android', 'gradle.properties')}\n` + ` - ${_path().default.join(projectRoot, 'android', 'app', 'build.gradle')}\n` + 'Learn more: https://expo.fyi/hermes-android-config');
118
+ throw new Error(`JavaScript engine configuration is inconsistent between ${configFileName} and Android native project.\n` + `In ${configFileName}: Hermes is ${isHermesManaged ? 'enabled' : 'not enabled'}\n` + `In Android native project: Hermes is ${isHermesManaged ? 'not enabled' : 'enabled'}\n` + `Check the following files for inconsistencies:\n` + ` - ${configFilePath}\n` + ` - ${_path().default.join(projectRoot, 'android', 'gradle.properties')}\n` + ` - ${_path().default.join(projectRoot, 'android', 'app', 'build.gradle')}\n` + 'Learn more: https://expo.fyi/hermes-android-config');
119
119
  }
120
120
  if (platform === 'ios' && await maybeInconsistentEngineIosAsync(projectRoot, isHermesManaged)) {
121
- throw new Error(`JavaScript engine configuration is inconsistent between ${configFileName} and iOS native project.\n` + `In ${configFileName}: Hermes is ${isHermesManaged ? 'enabled' : 'not enabled'}\n` + `In iOS native project: Hermes is ${isHermesManaged ? 'not enabled' : 'enabled'}\n` + `Please check the following files for inconsistencies:\n` + ` - ${configFilePath}\n` + ` - ${_path().default.join(projectRoot, 'ios', 'Podfile')}\n` + ` - ${_path().default.join(projectRoot, 'ios', 'Podfile.properties.json')}\n` + 'Learn more: https://expo.fyi/hermes-ios-config');
121
+ throw new Error(`JavaScript engine configuration is inconsistent between ${configFileName} and iOS native project.\n` + `In ${configFileName}: Hermes is ${isHermesManaged ? 'enabled' : 'not enabled'}\n` + `In iOS native project: Hermes is ${isHermesManaged ? 'not enabled' : 'enabled'}\n` + `Check the following files for inconsistencies:\n` + ` - ${configFilePath}\n` + ` - ${_path().default.join(projectRoot, 'ios', 'Podfile')}\n` + ` - ${_path().default.join(projectRoot, 'ios', 'Podfile.properties.json')}\n` + 'Learn more: https://expo.fyi/hermes-ios-config');
122
122
  }
123
123
  }
124
124
  async function maybeInconsistentEngineAndroidAsync(projectRoot, isHermesManaged) {