mirror of
https://github.com/status-im/react-native.git
synced 2025-01-09 17:15:54 +00:00
436db67126
Summary:In order to be able to Hot Load Redux stores and modules that export functions, we need to build infrastructure to bubble up the HMR updates similar to how webpack does: https://webpack.github.io/docs/hot-module-replacement-with-webpack.html. In here we introduce the minimum of this infrastructure we need to make this work. The Packager server needs to send the inverse dependencies to the HMR runtime that runs on the client so that it can bubble up the patches if they cannot be self accepted by the module that was changed. This diff relies on https://github.com/facebook/node-haste/pull/40/files which adds support for getting the inverse dependencies. Reviewed By: davidaurelio Differential Revision: D2950662 fb-gh-sync-id: 26dcd4aa15da76a727026a9d7ee06e7ae4d22eaa shipit-source-id: 26dcd4aa15da76a727026a9d7ee06e7ae4d22eaa
140 lines
4.2 KiB
JavaScript
140 lines
4.2 KiB
JavaScript
/**
|
|
* 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
|
|
*/
|
|
'use strict';
|
|
|
|
const Platform = require('Platform');
|
|
const invariant = require('invariant');
|
|
const processColor = require('processColor');
|
|
|
|
/**
|
|
* HMR Client that receives from the server HMR updates and propagates them
|
|
* runtime to reflects those changes.
|
|
*/
|
|
const HMRClient = {
|
|
enable(platform, bundleEntry, host, port) {
|
|
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) => {
|
|
throw new Error(
|
|
`Hot loading isn't working because it cannot connect to the development server.
|
|
|
|
Ensure the following:
|
|
- Node server is running and available on the same network
|
|
- run 'npm start' from react-native root
|
|
- Node server URL is correctly set in AppDelegate
|
|
|
|
URL: ${host}:${port}
|
|
|
|
Error: ${e.message}`
|
|
);
|
|
};
|
|
activeWS.onmessage = ({data}) => {
|
|
let DevLoadingView = require('NativeModules').DevLoadingView;
|
|
if (!DevLoadingView) {
|
|
DevLoadingView = {
|
|
showMessage() {},
|
|
hide() {},
|
|
};
|
|
}
|
|
data = JSON.parse(data);
|
|
|
|
switch (data.type) {
|
|
case 'update-start': {
|
|
DevLoadingView.showMessage(
|
|
'Hot Loading...',
|
|
processColor('#000000'),
|
|
processColor('#aaaaaa'),
|
|
);
|
|
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();
|
|
}
|
|
|
|
modules.forEach(({name, code}, i) => {
|
|
code = code + '\n\n' + sourceMappingURLs[i];
|
|
|
|
require('SourceMapsCache').fetch({
|
|
text: code,
|
|
url: 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;
|
|
|
|
// TODO: (martinb) yellow box if cannot accept module
|
|
code = `
|
|
__accept(
|
|
${name},
|
|
function(global, require, module, exports) {
|
|
${code}
|
|
},
|
|
${JSON.stringify(inverseDependencies)}
|
|
);`;
|
|
|
|
injectFunction(code, sourceURLs[i]);
|
|
});
|
|
|
|
DevLoadingView.hide();
|
|
break;
|
|
}
|
|
case 'update-done': {
|
|
DevLoadingView.hide();
|
|
break;
|
|
}
|
|
case 'error': {
|
|
DevLoadingView.hide();
|
|
throw new Error(data.body.type + ' ' + data.body.description);
|
|
}
|
|
default: {
|
|
throw new Error(`Unexpected message: ${data}`);
|
|
}
|
|
}
|
|
};
|
|
},
|
|
};
|
|
|
|
module.exports = HMRClient;
|