diff --git a/Libraries/Utilities/HMRClient.js b/Libraries/Utilities/HMRClient.js index 79be2be45..ed55ee6b9 100644 --- a/Libraries/Utilities/HMRClient.js +++ b/Libraries/Utilities/HMRClient.js @@ -11,6 +11,7 @@ 'use strict'; const invariant = require('invariant'); +const processColor = require('processColor'); /** * HMR Client that receives from the server HMR updates and propagates them @@ -49,39 +50,60 @@ Error: ${e.message}` ); }; activeWS.onmessage = ({data}) => { + const DevLoadingView = require('NativeModules').DevLoadingView; data = JSON.parse(data); - if (data.type === 'update') { - const modules = data.body.modules; - const sourceMappingURLs = data.body.sourceMappingURLs; - const sourceURLs = data.body.sourceURLs; - const RCTRedBox = require('NativeModules').RedBox; - RCTRedBox && RCTRedBox.dismiss && RCTRedBox.dismiss(); + switch(data.type) { + case 'update-start': { + DevLoadingView.showMessage( + 'Hot Loading...', + processColor('#000000'), + processColor('#aaaaaa'), + ); + break; + } + case 'update': { + const modules = data.body.modules; + const sourceMappingURLs = data.body.sourceMappingURLs; + const sourceURLs = data.body.sourceURLs; - modules.forEach((code, i) => { - code = code + '\n\n' + sourceMappingURLs[i]; + const RCTRedBox = require('NativeModules').RedBox; + RCTRedBox && RCTRedBox.dismiss && RCTRedBox.dismiss(); - require('SourceMapsCache').fetch({ - text: code, - url: sourceURLs[i], - sourceMappingURL: sourceMappingURLs[i], + modules.forEach((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 __injectHMRUpdate === 'function' + ? __injectHMRUpdate + : eval; + + injectFunction(code, sourceURLs[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 __injectHMRUpdate === 'function' - ? __injectHMRUpdate - : eval; - - injectFunction(code, sourceURLs[i]); - }) - return; + 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}`); + } } - - // TODO: add support for opening filename by clicking on the stacktrace - const error = data.body; - throw new Error(error.type + ' ' + error.description); }; }, }; diff --git a/React/Modules/RCTDevLoadingView.m b/React/Modules/RCTDevLoadingView.m index b652f7ce9..5c799791c 100644 --- a/React/Modules/RCTDevLoadingView.m +++ b/React/Modules/RCTDevLoadingView.m @@ -55,14 +55,13 @@ RCT_EXPORT_MODULE() [self showWithURL:bridge.bundleURL]; } -- (void)showWithURL:(NSURL *)URL +RCT_EXPORT_METHOD(showMessage:(NSString *)message color:(UIColor *)color backgroundColor:(UIColor *)backgroundColor) { if (!isEnabled) { return; } dispatch_async(dispatch_get_main_queue(), ^{ - _showDate = [NSDate date]; if (!_window && !RCTRunningInTestEnvironment()) { CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width; @@ -77,34 +76,23 @@ RCT_EXPORT_MODULE() [_window makeKeyAndVisible]; } - NSString *source; - if (URL.fileURL) { - _window.backgroundColor = [UIColor blackColor]; - _label.textColor = [UIColor grayColor]; - source = @"pre-bundled file"; - } else { - _window.backgroundColor = [UIColor colorWithHue:1./3 saturation:1 brightness:.35 alpha:1]; - _label.textColor = [UIColor whiteColor]; - source = [NSString stringWithFormat:@"%@:%@", URL.host, URL.port]; - } - - _label.text = [NSString stringWithFormat:@"Loading from %@...", source]; + _label.text = message; + _label.textColor = color; + _window.backgroundColor = backgroundColor; _window.hidden = NO; }); } -- (void)hide +RCT_EXPORT_METHOD(hide) { if (!isEnabled) { return; } dispatch_async(dispatch_get_main_queue(), ^{ - const NSTimeInterval MIN_PRESENTED_TIME = 0.6; NSTimeInterval presentedTime = [[NSDate date] timeIntervalSinceDate:_showDate]; NSTimeInterval delay = MAX(0, MIN_PRESENTED_TIME - presentedTime); - CGRect windowFrame = _window.frame; [UIView animateWithDuration:0.25 delay:delay @@ -119,6 +107,26 @@ RCT_EXPORT_MODULE() }); } +- (void)showWithURL:(NSURL *)URL +{ + UIColor *color; + UIColor *backgroundColor; + NSString *source; + if (URL.fileURL) { + color = [UIColor grayColor]; + backgroundColor = [UIColor blackColor]; + source = @"pre-bundled file"; + } else { + color = [UIColor whiteColor]; + backgroundColor = [UIColor colorWithHue:1./3 saturation:1 brightness:.35 alpha:1]; + source = [NSString stringWithFormat:@"%@:%@", URL.host, URL.port]; + } + + [self showMessage:[NSString stringWithFormat:@"Loading from %@...", source] + color:color + backgroundColor:backgroundColor]; +} + @end #else diff --git a/local-cli/server/util/attachHMRServer.js b/local-cli/server/util/attachHMRServer.js index 9eb62b551..3fc85e98c 100644 --- a/local-cli/server/util/attachHMRServer.js +++ b/local-cli/server/util/attachHMRServer.js @@ -112,6 +112,7 @@ function attachHMRServer({httpServer, path, packagerServer}) { return; } + client.ws.send(JSON.stringify({type: 'update-start'})); stat.then(() => { return packagerServer.getShallowDependencies(filename) .then(deps => { @@ -240,7 +241,9 @@ function attachHMRServer({httpServer, path, packagerServer}) { () => { // do nothing, file was removed }, - ); + ).finally(() => { + client.ws.send(JSON.stringify({type: 'update-done'})); + }); }); client.ws.on('error', e => {