-
Notifications
You must be signed in to change notification settings - Fork 24.3k
/
HMRClient.js
157 lines (133 loc) · 4.95 KB
/
HMRClient.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule HMRClient
* @flow
*/
'use strict';
const Platform = require('Platform');
const invariant = require('fbjs/lib/invariant');
/**
* HMR Client that receives from the server HMR updates and propagates them
* runtime to reflects those changes.
*/
const HMRClient = {
enable(platform: string, bundleEntry: string, host: string, port: number) {
invariant(platform, 'Missing required parameter `platform`');
invariant(bundleEntry, 'Missing required paramenter `bundleEntry`');
invariant(host, 'Missing required paramenter `host`');
// need to require WebSocket inside of `enable` function because
// this module is defined as a `polyfillGlobal`.
// See `InitializeJavascriptAppEngine.js`
const WebSocket = require('WebSocket');
const wsHostPort = port !== null && port !== ''
? `${host}:${port}`
: host;
// Build the websocket url
const wsUrl = `ws://${wsHostPort}/hot?` +
`platform=${platform}&` +
`bundleEntry=${bundleEntry.replace('.bundle', '.js')}`;
const activeWS = new WebSocket(wsUrl);
activeWS.onerror = (e) => {
let error = (
`Hot loading isn't working because it cannot connect to the development server.
Try the following to fix the issue:
- Ensure that the packager server is running and available on the same network`
);
if (Platform.OS === 'ios') {
error += (
`
- Ensure that the Packager server URL is correctly set in AppDelegate`
);
} else {
error += (
`
- Ensure that your device/emulator is connected to your machine and has USB debugging enabled - run 'adb devices' to see a list of connected devices
- If you're on a physical device connected to the same machine, run 'adb reverse tcp:8081 tcp:8081' to forward requests from your device
- If your device is on the same Wi-Fi network, set 'Debug server host & port for device' in 'Dev settings' to your machine's IP address and the port of the local dev server - e.g. 10.0.1.1:8081`
);
}
error += (
`
URL: ${host}:${port}
Error: ${e.message}`
);
throw new Error(error);
};
activeWS.onmessage = ({data}) => {
// Moving to top gives errors due to NativeModules not being initialized
const HMRLoadingView = require('HMRLoadingView');
data = JSON.parse(data);
switch (data.type) {
case 'update-start': {
HMRLoadingView.showMessage('Hot Loading...');
break;
}
case 'update': {
const {
modules,
sourceMappingURLs,
sourceURLs,
inverseDependencies,
} = data.body;
if (Platform.OS === 'ios') {
const RCTRedBox = require('NativeModules').RedBox;
RCTRedBox && RCTRedBox.dismiss && RCTRedBox.dismiss();
} else {
const RCTExceptionsManager = require('NativeModules').ExceptionsManager;
RCTExceptionsManager && RCTExceptionsManager.dismissRedbox && RCTExceptionsManager.dismissRedbox();
}
let serverHost;
if (Platform.OS === 'android') {
serverHost = require('NativeModules').AndroidConstants.ServerHost;
} else {
serverHost = port ? `${host}:${port}` : host;
}
modules.forEach(({id, code}, i) => {
code = code + '\n\n' + sourceMappingURLs[i];
require('SourceMapsCache').fetch({
text: code,
url: `http://${serverHost}${sourceURLs[i]}`,
sourceMappingURL: sourceMappingURLs[i],
});
// on JSC we need to inject from native for sourcemaps to work
// (Safari doesn't support `sourceMappingURL` nor any variant when
// evaluating code) but on Chrome we can simply use eval
const injectFunction = typeof global.nativeInjectHMRUpdate === 'function'
? global.nativeInjectHMRUpdate
: eval;
code = [
`__accept(`,
`${id},`,
`function(global,require,module,exports){`,
`${code}`,
'\n},',
`${JSON.stringify(inverseDependencies)}`,
`);`,
].join('');
injectFunction(code, sourceURLs[i]);
});
HMRLoadingView.hide();
break;
}
case 'update-done': {
HMRLoadingView.hide();
break;
}
case 'error': {
HMRLoadingView.hide();
throw new Error(data.body.type + ' ' + data.body.description);
}
default: {
throw new Error(`Unexpected message: ${data}`);
}
}
};
},
};
module.exports = HMRClient;