expo 55.0.0-canary-20260119-70f7c28 → 55.0.0-canary-20260119-17896bf
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Expo.podspec +0 -1
- package/android/build.gradle +5 -5
- package/android/src/main/java/expo/modules/ExpoReactHostFactory.kt +32 -67
- package/android/src/main/java/expo/modules/ReactActivityDelegateWrapper.kt +9 -6
- package/android/src/main/java/expo/modules/ReactNativeHostWrapper.kt +51 -0
- package/android/src/main/java/expo/modules/ReactNativeHostWrapperBase.kt +107 -0
- package/android/src/main/java/expo/modules/fetch/ExpoFetchModule.kt +3 -4
- package/android/src/main/java/expo/modules/fetch/NativeResponse.kt +3 -3
- package/android/src/main/java/expo/modules/fetch/ResponseSink.kt +3 -7
- package/android/src/test/java/expo/modules/ReactActivityDelegateWrapperDelayLoadTest.kt +3 -2
- package/build/Expo.d.ts +1 -1
- package/build/Expo.d.ts.map +1 -1
- package/build/async-require/getDevServer.d.ts.map +1 -1
- package/build/async-require/hmr.d.ts +8 -8
- package/build/async-require/hmr.d.ts.map +1 -1
- package/build/async-require/hmr.native.d.ts +3 -0
- package/build/async-require/hmr.native.d.ts.map +1 -0
- package/build/dom/dom-entry.d.ts.map +1 -1
- package/build/dom/dom.types.d.ts +0 -5
- package/build/dom/dom.types.d.ts.map +1 -1
- package/build/dom/internal.d.ts +0 -1
- package/build/dom/internal.d.ts.map +1 -1
- package/build/dom/webview-wrapper.d.ts +2 -2
- package/build/dom/webview-wrapper.d.ts.map +1 -1
- package/build/hooks/useEvent.d.ts +2 -2
- package/bundledNativeModules.json +101 -99
- package/ios/AppDelegates/AppDelegatesLoaderDelegate.swift +0 -2
- package/ios/AppDelegates/EXAppDelegateWrapper.h +30 -0
- package/ios/AppDelegates/EXAppDelegateWrapper.mm +112 -0
- package/ios/AppDelegates/EXReactRootViewFactory.h +1 -8
- package/ios/AppDelegates/EXReactRootViewFactory.mm +0 -26
- package/ios/AppDelegates/ExpoAppDelegate.swift +52 -13
- package/ios/AppDelegates/ExpoReactNativeFactory.swift +1 -22
- package/ios/Expo.h +1 -2
- package/ios/Fetch/ExpoFetchModule.swift +2 -2
- package/package.json +23 -29
- package/src/Expo.fx.tsx +25 -1
- package/src/Expo.fx.web.tsx +2 -2
- package/src/Expo.ts +0 -3
- package/src/__tests__/__fbBatchedBridgeConfig-test.ts +3 -7
- package/src/async-require/asyncRequireModule.ts +2 -2
- package/src/async-require/getDevServer.ts +9 -3
- package/src/async-require/hmr.native.ts +3 -0
- package/src/async-require/hmr.ts +103 -118
- package/src/async-require/index.ts +1 -1
- package/src/async-require/setupFastRefresh.ts +2 -3
- package/src/dom/dom-entry.tsx +8 -15
- package/src/dom/dom.types.ts +0 -6
- package/src/dom/internal.ts +0 -2
- package/src/dom/webview-wrapper.tsx +6 -14
- package/src/hooks/useEvent.ts +2 -2
- package/template.tgz +0 -0
- package/types/react-native-web.d.ts +1 -1
- package/build/async-require/buildErrors.d.ts +0 -5
- package/build/async-require/buildErrors.d.ts.map +0 -1
- package/build/async-require/getFullBundlerUrl.d.ts +0 -2
- package/build/async-require/getFullBundlerUrl.d.ts.map +0 -1
- package/build/async-require/hmrUtils.d.ts +0 -13
- package/build/async-require/hmrUtils.d.ts.map +0 -1
- package/build/async-require/hmrUtils.native.d.ts +0 -13
- package/build/async-require/hmrUtils.native.d.ts.map +0 -1
- package/build/dom/dom-internal.types.d.ts +0 -11
- package/build/dom/dom-internal.types.d.ts.map +0 -1
- package/ios/AppDelegates/ExpoReactNativeFactory.h +0 -12
- package/ios/AppDelegates/ExpoReactNativeFactory.mm +0 -45
- package/local-build-cache-provider.d.ts +0 -1
- package/local-build-cache-provider.js +0 -1
- package/src/async-require/buildErrors.ts +0 -14
- package/src/async-require/getFullBundlerUrl.ts +0 -13
- package/src/async-require/hmrUtils.native.ts +0 -97
- package/src/async-require/hmrUtils.ts +0 -54
- package/src/dom/dom-internal.types.ts +0 -9
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo",
|
|
3
|
-
"version": "55.0.0-canary-20260119-
|
|
3
|
+
"version": "55.0.0-canary-20260119-17896bf",
|
|
4
4
|
"description": "The Expo SDK",
|
|
5
5
|
"main": "src/Expo.ts",
|
|
6
6
|
"module": "src/Expo.ts",
|
|
@@ -40,8 +40,6 @@
|
|
|
40
40
|
"fetch.d.ts",
|
|
41
41
|
"fingerprint.js",
|
|
42
42
|
"fingerprint.d.ts",
|
|
43
|
-
"local-build-cache-provider.js",
|
|
44
|
-
"local-build-cache-provider.d.ts",
|
|
45
43
|
"react-native.config.js",
|
|
46
44
|
"requiresExtraSetup.json",
|
|
47
45
|
"tsconfig.base.json",
|
|
@@ -77,44 +75,40 @@
|
|
|
77
75
|
"homepage": "https://github.com/expo/expo/tree/main/packages/expo",
|
|
78
76
|
"dependencies": {
|
|
79
77
|
"@babel/runtime": "^7.20.0",
|
|
80
|
-
"@expo/cli": "
|
|
81
|
-
"@expo/config": "12.0.14-canary-20260119-
|
|
82
|
-
"@expo/config-plugins": "54.
|
|
83
|
-
"@expo/devtools": "0.1.9-canary-20260119-
|
|
84
|
-
"@expo/fingerprint": "0.15.5-canary-20260119-
|
|
85
|
-
"@expo/local-build-cache-provider": "0.0.1-canary-20260119-70f7c28",
|
|
78
|
+
"@expo/cli": "54.1.0-canary-20260119-17896bf",
|
|
79
|
+
"@expo/config": "12.0.14-canary-20260119-17896bf",
|
|
80
|
+
"@expo/config-plugins": "54.0.5-canary-20260119-17896bf",
|
|
81
|
+
"@expo/devtools": "0.1.9-canary-20260119-17896bf",
|
|
82
|
+
"@expo/fingerprint": "0.15.5-canary-20260119-17896bf",
|
|
86
83
|
"@expo/metro": "~54.2.0",
|
|
87
|
-
"@expo/metro-config": "54.
|
|
88
|
-
"@expo/vector-icons": "^15.0.
|
|
89
|
-
"@expo/log-box": "0.0.13-canary-20260119-70f7c28",
|
|
84
|
+
"@expo/metro-config": "54.0.14-canary-20260119-17896bf",
|
|
85
|
+
"@expo/vector-icons": "^15.0.3",
|
|
90
86
|
"@ungap/structured-clone": "^1.3.0",
|
|
91
|
-
"babel-preset-expo": "54.
|
|
92
|
-
"expo-asset": "12.0.13-canary-20260119-
|
|
93
|
-
"expo-constants": "18.
|
|
94
|
-
"expo-file-system": "19.0.22-canary-20260119-
|
|
95
|
-
"expo-font": "14.
|
|
96
|
-
"expo-keep-awake": "15.0.9-canary-20260119-
|
|
97
|
-
"expo-modules-autolinking": "3.
|
|
98
|
-
"expo-modules-core": "
|
|
87
|
+
"babel-preset-expo": "54.0.10-canary-20260119-17896bf",
|
|
88
|
+
"expo-asset": "12.0.13-canary-20260119-17896bf",
|
|
89
|
+
"expo-constants": "18.0.14-canary-20260119-17896bf",
|
|
90
|
+
"expo-file-system": "19.0.22-canary-20260119-17896bf",
|
|
91
|
+
"expo-font": "14.0.11-canary-20260119-17896bf",
|
|
92
|
+
"expo-keep-awake": "15.0.9-canary-20260119-17896bf",
|
|
93
|
+
"expo-modules-autolinking": "3.0.25-canary-20260119-17896bf",
|
|
94
|
+
"expo-modules-core": "3.0.30-canary-20260119-17896bf",
|
|
99
95
|
"pretty-format": "^29.7.0",
|
|
100
96
|
"react-refresh": "^0.14.2",
|
|
101
97
|
"whatwg-url-without-unicode": "8.0.0-3"
|
|
102
98
|
},
|
|
103
99
|
"devDependencies": {
|
|
104
|
-
"@expo/dom-webview": "0.2.9-canary-20260119-70f7c28",
|
|
105
|
-
"@expo/metro-runtime": "6.2.0-canary-20260119-70f7c28",
|
|
106
100
|
"@types/node": "^22.14.0",
|
|
107
|
-
"@types/react": "~19.
|
|
101
|
+
"@types/react": "~19.1.10",
|
|
108
102
|
"@types/react-test-renderer": "~19.1.0",
|
|
109
|
-
"expo-module-scripts": "5.
|
|
110
|
-
"react": "19.
|
|
111
|
-
"react-dom": "19.
|
|
112
|
-
"react-native": "0.
|
|
103
|
+
"expo-module-scripts": "5.0.9-canary-20260119-17896bf",
|
|
104
|
+
"react": "19.1.0",
|
|
105
|
+
"react-dom": "19.1.0",
|
|
106
|
+
"react-native": "0.81.5",
|
|
113
107
|
"web-streams-polyfill": "^3.3.2"
|
|
114
108
|
},
|
|
115
109
|
"peerDependencies": {
|
|
116
|
-
"@expo/dom-webview": "0.2.9-canary-20260119-
|
|
117
|
-
"@expo/metro-runtime": "6.
|
|
110
|
+
"@expo/dom-webview": "0.2.9-canary-20260119-17896bf",
|
|
111
|
+
"@expo/metro-runtime": "6.1.3-canary-20260119-17896bf",
|
|
118
112
|
"react": "*",
|
|
119
113
|
"react-native": "*",
|
|
120
114
|
"react-native-webview": "*"
|
package/src/Expo.fx.tsx
CHANGED
|
@@ -4,7 +4,8 @@ import './async-require';
|
|
|
4
4
|
import 'expo-asset';
|
|
5
5
|
import 'expo/virtual/rsc';
|
|
6
6
|
|
|
7
|
-
import
|
|
7
|
+
import Constants from 'expo-constants';
|
|
8
|
+
import { AppRegistry, NativeModules, LogBox, Platform } from 'react-native';
|
|
8
9
|
|
|
9
10
|
import { isRunningInExpoGo } from './environment/ExpoGo';
|
|
10
11
|
import { AppEntryNotFound } from './errors/AppEntryNotFound';
|
|
@@ -25,6 +26,29 @@ if (isRunningInExpoGo()) {
|
|
|
25
26
|
ErrorUtils.setGlobalHandler(createErrorHandler(globalHandler));
|
|
26
27
|
}
|
|
27
28
|
|
|
29
|
+
// Warn if the New Architecture is not explicitly enabled in the app config and we are running in Expo Go.
|
|
30
|
+
// This could be problematic because you will be developing your app with the New Architecture enabled and
|
|
31
|
+
// but your builds will have the New Architecture disabled.
|
|
32
|
+
if (__DEV__ && isRunningInExpoGo() && process.env.NODE_ENV === 'development') {
|
|
33
|
+
(['android', 'ios'] as const).forEach((platform) => {
|
|
34
|
+
const newArchPlatformConfig = Constants.expoConfig?.[platform]?.newArchEnabled;
|
|
35
|
+
const newArchRootConfig = Constants.expoConfig?.newArchEnabled;
|
|
36
|
+
|
|
37
|
+
const isNewArchExplicitlyDisabled =
|
|
38
|
+
newArchPlatformConfig === false ||
|
|
39
|
+
(newArchPlatformConfig === undefined && newArchRootConfig === false);
|
|
40
|
+
|
|
41
|
+
if (Platform.OS === platform && isNewArchExplicitlyDisabled) {
|
|
42
|
+
// Wrap it in rAF to show the warning after the React Native DevTools message
|
|
43
|
+
requestAnimationFrame(() => {
|
|
44
|
+
console.warn(
|
|
45
|
+
`🚨 React Native's New Architecture is always enabled in Expo Go, but it is explicitly disabled in your project's app config. This may lead to unexpected behavior when creating a production or development build. Remove "newArchEnabled": false from your app.json.\nLearn more: https://docs.expo.dev/guides/new-architecture/`
|
|
46
|
+
);
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
28
52
|
// Disable the "Open debugger to view warnings" React Native DevTools warning in
|
|
29
53
|
// Expo Go and expo-dev-client, because launching the debugger from there will not
|
|
30
54
|
// get the correct JS target.
|
package/src/Expo.fx.web.tsx
CHANGED
|
@@ -9,9 +9,9 @@ import 'expo/virtual/rsc';
|
|
|
9
9
|
if (__DEV__) {
|
|
10
10
|
if (
|
|
11
11
|
// Skip mocking if someone is shimming this value out.
|
|
12
|
-
!('__fbBatchedBridgeConfig' in
|
|
12
|
+
!('__fbBatchedBridgeConfig' in global)
|
|
13
13
|
) {
|
|
14
|
-
Object.defineProperty(
|
|
14
|
+
Object.defineProperty(global, '__fbBatchedBridgeConfig', {
|
|
15
15
|
get() {
|
|
16
16
|
throw new Error(
|
|
17
17
|
"Your web project is importing a module from 'react-native' instead of 'react-native-web'. Learn more: https://expo.fyi/fb-batched-bridge-config-web"
|
package/src/Expo.ts
CHANGED
|
@@ -6,18 +6,14 @@ jest.mock('../async-require/getDevServer');
|
|
|
6
6
|
|
|
7
7
|
if (Platform.OS === 'web') {
|
|
8
8
|
it('provides a helpful error message on web', () => {
|
|
9
|
-
const error =
|
|
10
|
-
/Your web project is importing a module from 'react-native' instead of 'react-native-web'/;
|
|
11
9
|
// @ts-ignore
|
|
12
|
-
expect(() => global.__fbBatchedBridgeConfig).toThrow(
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
expect(() => global.__fbBatchedBridgeConfig).toThrow(
|
|
11
|
+
/Your web project is importing a module from 'react-native' instead of 'react-native-web'/
|
|
12
|
+
);
|
|
15
13
|
});
|
|
16
14
|
} else {
|
|
17
15
|
it(`does not change the functionality of __fbBatchedBridgeConfig on native`, () => {
|
|
18
16
|
// @ts-ignore
|
|
19
17
|
expect(() => global.__fbBatchedBridgeConfig).not.toThrow();
|
|
20
|
-
// @ts-ignore
|
|
21
|
-
expect(() => globalThis.__fbBatchedBridgeConfig).not.toThrow();
|
|
22
18
|
});
|
|
23
19
|
}
|
|
@@ -20,8 +20,8 @@ type DependencyMapPaths = { [moduleID: number | string]: unknown } | null;
|
|
|
20
20
|
declare let __METRO_GLOBAL_PREFIX__: string;
|
|
21
21
|
|
|
22
22
|
function maybeLoadBundle(moduleID: number, paths: DependencyMapPaths): void | Promise<void> {
|
|
23
|
-
const loadBundle: (bundlePath: unknown) => Promise<void> = (
|
|
24
|
-
`${__METRO_GLOBAL_PREFIX__
|
|
23
|
+
const loadBundle: (bundlePath: unknown) => Promise<void> = (global as any)[
|
|
24
|
+
`${__METRO_GLOBAL_PREFIX__}__loadBundleAsync`
|
|
25
25
|
];
|
|
26
26
|
|
|
27
27
|
if (loadBundle != null) {
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { getFullBundlerUrl } from './getFullBundlerUrl';
|
|
2
|
-
|
|
3
1
|
const getDevServer = () => {
|
|
4
2
|
// Disable for SSR
|
|
5
3
|
if (typeof window === 'undefined') {
|
|
@@ -16,7 +14,15 @@ const getDevServer = () => {
|
|
|
16
14
|
|
|
17
15
|
/** URL but ensures that platform query param is added. */
|
|
18
16
|
get fullBundleUrl() {
|
|
19
|
-
|
|
17
|
+
if (document?.currentScript && 'src' in document.currentScript) {
|
|
18
|
+
return document.currentScript.src;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const bundleUrl = new URL(location.href);
|
|
22
|
+
|
|
23
|
+
bundleUrl.searchParams.set('platform', 'web');
|
|
24
|
+
|
|
25
|
+
return bundleUrl.toString();
|
|
20
26
|
},
|
|
21
27
|
url: location.origin + location.pathname,
|
|
22
28
|
};
|
package/src/async-require/hmr.ts
CHANGED
|
@@ -10,24 +10,35 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import MetroHMRClient from '@expo/metro/metro-runtime/modules/HMRClient';
|
|
12
12
|
import prettyFormat, { plugins } from 'pretty-format';
|
|
13
|
+
import { DeviceEventEmitter } from 'react-native';
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
15
|
+
// Ensure events are sent so custom Fast Refresh views are shown.
|
|
16
|
+
function showLoading(message: string, _type: 'load' | 'refresh') {
|
|
17
|
+
DeviceEventEmitter.emit('devLoadingView:showMessage', {
|
|
18
|
+
message,
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function hideLoading() {
|
|
23
|
+
DeviceEventEmitter.emit('devLoadingView:hide', {});
|
|
24
|
+
}
|
|
22
25
|
|
|
23
26
|
const pendingEntryPoints: string[] = [];
|
|
24
27
|
|
|
25
28
|
// @ts-expect-error: Account for multiple versions of pretty-format inside of a monorepo.
|
|
26
29
|
const prettyFormatFunc = typeof prettyFormat === 'function' ? prettyFormat : prettyFormat.default;
|
|
27
30
|
|
|
28
|
-
|
|
31
|
+
type HMRClientType = {
|
|
32
|
+
send: (msg: string) => void;
|
|
33
|
+
isEnabled: () => boolean;
|
|
34
|
+
disable: () => void;
|
|
35
|
+
enable: () => void;
|
|
36
|
+
hasPendingUpdates: () => boolean;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
let hmrClient: HMRClientType | null = null;
|
|
29
40
|
let hmrUnavailableReason: string | null = null;
|
|
30
|
-
|
|
41
|
+
let currentCompileErrorMessage: string | null = null;
|
|
31
42
|
let didConnect: boolean = false;
|
|
32
43
|
const pendingLogs: [LogLevel, any[]][] = [];
|
|
33
44
|
|
|
@@ -42,6 +53,14 @@ type LogLevel =
|
|
|
42
53
|
| 'groupEnd'
|
|
43
54
|
| 'debug';
|
|
44
55
|
|
|
56
|
+
export type HMRClientNativeInterface = {
|
|
57
|
+
enable(): void;
|
|
58
|
+
disable(): void;
|
|
59
|
+
registerBundle(requestUrl: string): void;
|
|
60
|
+
log(level: LogLevel, data: any[]): void;
|
|
61
|
+
setup(props: { isEnabled: boolean }): void;
|
|
62
|
+
};
|
|
63
|
+
|
|
45
64
|
function assert(foo: any, msg: string): asserts foo {
|
|
46
65
|
if (!foo) throw new Error(msg);
|
|
47
66
|
}
|
|
@@ -50,7 +69,7 @@ function assert(foo: any, msg: string): asserts foo {
|
|
|
50
69
|
* HMR Client that receives from the server HMR updates and propagates them
|
|
51
70
|
* runtime to reflects those changes.
|
|
52
71
|
*/
|
|
53
|
-
const HMRClient = {
|
|
72
|
+
const HMRClient: HMRClientNativeInterface = {
|
|
54
73
|
enable() {
|
|
55
74
|
if (hmrUnavailableReason !== null) {
|
|
56
75
|
// If HMR became unavailable while you weren't using it,
|
|
@@ -108,19 +127,12 @@ const HMRClient = {
|
|
|
108
127
|
return;
|
|
109
128
|
}
|
|
110
129
|
try {
|
|
111
|
-
const webMetadata =
|
|
112
|
-
process.env.EXPO_OS === 'web'
|
|
113
|
-
? {
|
|
114
|
-
platform: 'web',
|
|
115
|
-
mode: 'BRIDGE',
|
|
116
|
-
}
|
|
117
|
-
: undefined;
|
|
118
130
|
hmrClient.send(
|
|
119
131
|
JSON.stringify({
|
|
120
|
-
// TODO: Type this properly.
|
|
121
|
-
...webMetadata,
|
|
122
132
|
type: 'log',
|
|
123
133
|
level,
|
|
134
|
+
platform: 'web',
|
|
135
|
+
mode: 'BRIDGE',
|
|
124
136
|
data: data.map((item) =>
|
|
125
137
|
typeof item === 'string'
|
|
126
138
|
? item
|
|
@@ -142,63 +154,50 @@ const HMRClient = {
|
|
|
142
154
|
|
|
143
155
|
// Called once by the bridge on startup, even if Fast Refresh is off.
|
|
144
156
|
// It creates the HMR client but doesn't actually set up the socket yet.
|
|
145
|
-
setup(
|
|
146
|
-
|
|
147
|
-
bundleEntry?: string,
|
|
148
|
-
host?: string,
|
|
149
|
-
port?: number | string,
|
|
150
|
-
isEnabledOrUndefined?: boolean,
|
|
151
|
-
scheme: string = 'http'
|
|
152
|
-
) {
|
|
153
|
-
let isEnabled = !!isEnabledOrUndefined;
|
|
154
|
-
let serverScheme: string;
|
|
155
|
-
let serverHost: string;
|
|
156
|
-
|
|
157
|
-
if (process.env.EXPO_OS === 'web') {
|
|
158
|
-
assert(
|
|
159
|
-
platformOrOptions && typeof platformOrOptions === 'object',
|
|
160
|
-
'Expected platformOrOptions to be an options object on web.'
|
|
161
|
-
);
|
|
162
|
-
assert(!hmrClient, 'Cannot initialize hmrClient twice');
|
|
163
|
-
isEnabled = platformOrOptions.isEnabled;
|
|
157
|
+
setup({ isEnabled }: { isEnabled: boolean }) {
|
|
158
|
+
assert(!hmrClient, 'Cannot initialize hmrClient twice');
|
|
164
159
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
160
|
+
const serverScheme = window.location.protocol === 'https:' ? 'wss' : 'ws';
|
|
161
|
+
const client = new MetroHMRClient(`${serverScheme}://${window.location.host}/hot`);
|
|
162
|
+
hmrClient = client;
|
|
163
|
+
|
|
164
|
+
const fullBundleUrl = (() => {
|
|
165
|
+
const currentScript = document?.currentScript;
|
|
166
|
+
const bundleUrl = new URL(
|
|
167
|
+
currentScript && 'src' in currentScript ? currentScript.src : location.href,
|
|
168
|
+
location.href
|
|
171
169
|
);
|
|
172
|
-
assert(bundleEntry, 'Missing required parameter `bundleEntry`');
|
|
173
|
-
assert(host, 'Missing required parameter `host`');
|
|
174
|
-
assert(!hmrClient, 'Cannot initialize hmrClient twice');
|
|
175
170
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
171
|
+
if (!bundleUrl.searchParams.has('platform')) {
|
|
172
|
+
bundleUrl.searchParams.set('platform', process.env.EXPO_OS ?? 'web');
|
|
173
|
+
}
|
|
179
174
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
hmrClient = client;
|
|
175
|
+
return bundleUrl.toString();
|
|
176
|
+
})();
|
|
183
177
|
|
|
184
178
|
pendingEntryPoints.push(
|
|
185
179
|
// HMRServer understands regular bundle URLs, so prefer that in case
|
|
186
180
|
// there are any important URL parameters we can't reconstruct from
|
|
187
181
|
// `setup()`'s arguments.
|
|
188
|
-
|
|
189
|
-
serverScheme,
|
|
190
|
-
serverHost,
|
|
191
|
-
bundleEntry,
|
|
192
|
-
platform: typeof platformOrOptions === 'string' ? platformOrOptions : undefined,
|
|
193
|
-
})
|
|
182
|
+
fullBundleUrl
|
|
194
183
|
);
|
|
195
184
|
|
|
196
185
|
client.on('connection-error', (e: Error) => {
|
|
197
|
-
|
|
186
|
+
let error = `Cannot connect to Metro.
|
|
187
|
+
|
|
188
|
+
Try the following to fix the issue:
|
|
189
|
+
- Ensure the Metro dev server is running and available on the same network as this device`;
|
|
190
|
+
error += `
|
|
191
|
+
|
|
192
|
+
URL: ${window.location.host}
|
|
193
|
+
|
|
194
|
+
Error: ${e.message}`;
|
|
195
|
+
|
|
196
|
+
setHMRUnavailableReason(error);
|
|
198
197
|
});
|
|
199
198
|
|
|
200
199
|
client.on('update-start', ({ isInitialUpdate }: { isInitialUpdate?: boolean }) => {
|
|
201
|
-
|
|
200
|
+
currentCompileErrorMessage = null;
|
|
202
201
|
didConnect = true;
|
|
203
202
|
|
|
204
203
|
if (client.isEnabled() && !isInitialUpdate) {
|
|
@@ -206,32 +205,35 @@ const HMRClient = {
|
|
|
206
205
|
}
|
|
207
206
|
});
|
|
208
207
|
|
|
209
|
-
client.on(
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
deleted,
|
|
216
|
-
}: {
|
|
217
|
-
isInitialUpdate?: boolean;
|
|
218
|
-
added: unknown[];
|
|
219
|
-
modified: unknown[];
|
|
220
|
-
deleted: unknown[];
|
|
221
|
-
}) => {
|
|
222
|
-
// NOTE(@krystofwoldrich): I don't know why sometimes empty updates are sent. But they should not reset the overlay.
|
|
223
|
-
const isEmpty = added.length === 0 && modified.length === 0 && deleted.length === 0;
|
|
224
|
-
if (client.isEnabled() && !isInitialUpdate && !isEmpty) {
|
|
225
|
-
resetErrorOverlay();
|
|
226
|
-
}
|
|
208
|
+
client.on('update', ({ isInitialUpdate }: { isInitialUpdate?: boolean }) => {
|
|
209
|
+
if (client.isEnabled() && !isInitialUpdate) {
|
|
210
|
+
dismissRedbox();
|
|
211
|
+
// @ts-expect-error
|
|
212
|
+
globalThis.__expo_dev_resetErrors?.();
|
|
213
|
+
// LogBox.clearAllLogs();
|
|
227
214
|
}
|
|
228
|
-
);
|
|
215
|
+
});
|
|
229
216
|
|
|
230
217
|
client.on('update-done', () => {
|
|
231
218
|
hideLoading();
|
|
232
219
|
});
|
|
233
220
|
|
|
234
|
-
client.on('error', (data) =>
|
|
221
|
+
client.on('error', (data: { type: string; message: string }) => {
|
|
222
|
+
hideLoading();
|
|
223
|
+
|
|
224
|
+
if (data.type === 'GraphNotFoundError') {
|
|
225
|
+
client.close();
|
|
226
|
+
setHMRUnavailableReason('Metro has restarted since the last edit. Reload to reconnect.');
|
|
227
|
+
} else if (data.type === 'RevisionNotFoundError') {
|
|
228
|
+
client.close();
|
|
229
|
+
setHMRUnavailableReason('Metro and the client are out of sync. Reload to reconnect.');
|
|
230
|
+
} else {
|
|
231
|
+
currentCompileErrorMessage = `${data.type} ${data.message}`;
|
|
232
|
+
if (client.isEnabled()) {
|
|
233
|
+
showCompileError();
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
});
|
|
235
237
|
|
|
236
238
|
client.on('close', (closeEvent?: { code: number; reason: string }) => {
|
|
237
239
|
hideLoading();
|
|
@@ -260,37 +262,6 @@ const HMRClient = {
|
|
|
260
262
|
registerBundleEntryPoints(hmrClient);
|
|
261
263
|
flushEarlyLogs();
|
|
262
264
|
},
|
|
263
|
-
|
|
264
|
-
// Related Metro error's formatting
|
|
265
|
-
// https://github.com/facebook/metro/blob/34bb8913ec4b5b02690b39d2246599faf094f721/packages/metro/src/lib/formatBundlingError.js#L36
|
|
266
|
-
_onMetroError(error: unknown) {
|
|
267
|
-
if (!hmrClient) {
|
|
268
|
-
return;
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
assert(typeof error === 'object' && error != null, 'Expected data to be an object');
|
|
272
|
-
|
|
273
|
-
hideLoading();
|
|
274
|
-
|
|
275
|
-
if ('type' in error) {
|
|
276
|
-
if (error.type === 'GraphNotFoundError') {
|
|
277
|
-
hmrClient.close();
|
|
278
|
-
setHMRUnavailableReason('Expo CLI has restarted since the last edit. Reload to reconnect.');
|
|
279
|
-
return;
|
|
280
|
-
} else if (error.type === 'RevisionNotFoundError') {
|
|
281
|
-
hmrClient.close();
|
|
282
|
-
setHMRUnavailableReason(
|
|
283
|
-
`Expo CLI and the ${process.env.EXPO_OS} client are out of sync. Reload to reconnect.`
|
|
284
|
-
);
|
|
285
|
-
return;
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
buildErrorQueue.add(error);
|
|
290
|
-
if (hmrClient.isEnabled()) {
|
|
291
|
-
showCompileError();
|
|
292
|
-
}
|
|
293
|
-
},
|
|
294
265
|
};
|
|
295
266
|
|
|
296
267
|
function setHMRUnavailableReason(reason: string) {
|
|
@@ -315,7 +286,7 @@ function setHMRUnavailableReason(reason: string) {
|
|
|
315
286
|
}
|
|
316
287
|
}
|
|
317
288
|
|
|
318
|
-
function registerBundleEntryPoints(client:
|
|
289
|
+
function registerBundleEntryPoints(client: HMRClientType | null) {
|
|
319
290
|
if (hmrUnavailableReason != null) {
|
|
320
291
|
// "Bundle Splitting – Metro disconnected"
|
|
321
292
|
window.location.reload();
|
|
@@ -343,14 +314,28 @@ function flushEarlyLogs() {
|
|
|
343
314
|
}
|
|
344
315
|
}
|
|
345
316
|
|
|
317
|
+
function dismissRedbox() {
|
|
318
|
+
// TODO(EvanBacon): Error overlay for web.
|
|
319
|
+
}
|
|
320
|
+
|
|
346
321
|
function showCompileError() {
|
|
347
|
-
if (
|
|
322
|
+
if (currentCompileErrorMessage === null) {
|
|
348
323
|
return;
|
|
349
324
|
}
|
|
350
325
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
326
|
+
// Even if there is already a redbox, syntax errors are more important.
|
|
327
|
+
// Otherwise you risk seeing a stale runtime error while a syntax error is more recent.
|
|
328
|
+
dismissRedbox();
|
|
329
|
+
|
|
330
|
+
const message = currentCompileErrorMessage;
|
|
331
|
+
currentCompileErrorMessage = null;
|
|
332
|
+
|
|
333
|
+
const error = new Error(message);
|
|
334
|
+
// Symbolicating compile errors is wasted effort
|
|
335
|
+
// because the stack trace is meaningless:
|
|
336
|
+
// @ts-expect-error
|
|
337
|
+
error.preventSymbolication = true;
|
|
338
|
+
throw error;
|
|
354
339
|
}
|
|
355
340
|
|
|
356
341
|
export default HMRClient;
|
|
@@ -7,4 +7,4 @@
|
|
|
7
7
|
import { buildAsyncRequire } from './buildAsyncRequire';
|
|
8
8
|
|
|
9
9
|
// @ts-ignore: ignore the global which may not always be defined in jest environments.
|
|
10
|
-
|
|
10
|
+
global[`${global.__METRO_GLOBAL_PREFIX__ ?? ''}__loadBundleAsync`] = buildAsyncRequire();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// This needs to run before the renderer initializes.
|
|
2
2
|
|
|
3
3
|
const ReactRefreshRuntime = require('react-refresh/runtime');
|
|
4
|
-
ReactRefreshRuntime.injectIntoGlobalHook(
|
|
4
|
+
ReactRefreshRuntime.injectIntoGlobalHook(global);
|
|
5
5
|
|
|
6
6
|
const Refresh = {
|
|
7
7
|
performFullRefresh() {
|
|
@@ -27,5 +27,4 @@ const Refresh = {
|
|
|
27
27
|
|
|
28
28
|
// The metro require polyfill can not have dependencies (applies for all polyfills).
|
|
29
29
|
// Expose `Refresh` by assigning it to global to make it available in the polyfill.
|
|
30
|
-
|
|
31
|
-
globalThis[(globalThis.__METRO_GLOBAL_PREFIX__ ?? '') + '__ReactRefresh'] = Refresh;
|
|
30
|
+
global[(global.__METRO_GLOBAL_PREFIX__ || '') + '__ReactRefresh'] = Refresh;
|
package/src/dom/dom-entry.tsx
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// Entry file for a DOM Component.
|
|
2
2
|
import '@expo/metro-runtime';
|
|
3
3
|
|
|
4
|
+
import { withErrorOverlay } from '@expo/metro-runtime/error-overlay';
|
|
4
5
|
import React from 'react';
|
|
5
6
|
|
|
6
7
|
import { JSONValue } from './dom.types';
|
|
@@ -8,13 +9,12 @@ import { addEventListener, getActionsObject } from './marshal';
|
|
|
8
9
|
import registerRootComponent from '../launch/registerRootComponent';
|
|
9
10
|
|
|
10
11
|
interface MarshalledProps {
|
|
11
|
-
|
|
12
|
+
name: string[];
|
|
12
13
|
props: Record<string, JSONValue>;
|
|
13
14
|
[key: string]: undefined | JSONValue;
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
interface WindowType {
|
|
17
|
-
$$EXPO_DOM_HOST_OS?: string;
|
|
18
18
|
$$EXPO_INITIAL_PROPS?: MarshalledProps;
|
|
19
19
|
}
|
|
20
20
|
|
|
@@ -65,13 +65,6 @@ function convertError(error: any) {
|
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
export function registerDOMComponent(AppModule: any) {
|
|
68
|
-
if (typeof window.$$EXPO_DOM_HOST_OS === 'undefined') {
|
|
69
|
-
throw new Error(
|
|
70
|
-
'Top OS ($$EXPO_DOM_HOST_OS) is not defined. This is a bug in the DOM Component runtime.'
|
|
71
|
-
);
|
|
72
|
-
}
|
|
73
|
-
process.env.EXPO_DOM_HOST_OS = window.$$EXPO_DOM_HOST_OS;
|
|
74
|
-
|
|
75
68
|
function DOMComponentRoot(props: Record<string, unknown>) {
|
|
76
69
|
// Props listeners
|
|
77
70
|
const [marshalledProps, setProps] = React.useState(() => {
|
|
@@ -99,7 +92,7 @@ export function registerDOMComponent(AppModule: any) {
|
|
|
99
92
|
// Create a named map { [name: string]: ProxyFunction }
|
|
100
93
|
// TODO(@kitten): Unclear how this is typed or shaped
|
|
101
94
|
return Object.fromEntries(
|
|
102
|
-
marshalledProps.names.map((key: string) => {
|
|
95
|
+
(marshalledProps.names as string[]).map((key: string) => {
|
|
103
96
|
return [key, ACTIONS[key]];
|
|
104
97
|
})
|
|
105
98
|
);
|
|
@@ -109,12 +102,12 @@ export function registerDOMComponent(AppModule: any) {
|
|
|
109
102
|
}
|
|
110
103
|
|
|
111
104
|
try {
|
|
112
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
113
|
-
require('@expo/log-box/lib').setupLogBox();
|
|
114
|
-
}
|
|
115
|
-
|
|
116
105
|
React.startTransition(() => {
|
|
117
|
-
|
|
106
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
107
|
+
registerRootComponent(withErrorOverlay(DOMComponentRoot));
|
|
108
|
+
} else {
|
|
109
|
+
registerRootComponent(DOMComponentRoot);
|
|
110
|
+
}
|
|
118
111
|
});
|
|
119
112
|
} catch (e) {
|
|
120
113
|
const error = convertError(e);
|
package/src/dom/dom.types.ts
CHANGED
|
@@ -36,10 +36,4 @@ export interface DOMProps extends Omit<RNWebViewProps, 'source'> {
|
|
|
36
36
|
* @default false
|
|
37
37
|
*/
|
|
38
38
|
useExpoDOMWebView?: boolean;
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Allows dynamically redirecting a component to a different source, for example a prebuilt version.
|
|
42
|
-
* @internal
|
|
43
|
-
*/
|
|
44
|
-
overrideUri?: string;
|
|
45
39
|
}
|
package/src/dom/internal.ts
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
export { default as WebView } from './webview-wrapper';
|
|
2
2
|
|
|
3
|
-
export * from './dom-internal.types';
|
|
4
|
-
|
|
5
3
|
// Skip all dom-only functions to give 'undefined is not a function' errors.
|
|
6
4
|
export const registerDOMComponent: undefined | typeof import('./dom-entry').registerDOMComponent =
|
|
7
5
|
undefined;
|