Skip to content

Commit

Permalink
Hot Loading Indicators
Browse files Browse the repository at this point in the history
Summary:
public

Introduce a header bar similar to the one shown when loading the bundle to indicate that the packager server is processing an HMR update. Hook into HMR events to show this bar when appropriate.

Reviewed By: javache

Differential Revision: D2873521

fb-gh-sync-id: a77cbb2368b75b045aa8c6ababce2f731baf514b
  • Loading branch information
martinbigio authored and facebook-github-bot-7 committed Feb 1, 2016
1 parent 180ead0 commit 36efbc3
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 44 deletions.
74 changes: 48 additions & 26 deletions Libraries/Utilities/HMRClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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];

// 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;
require('SourceMapsCache').fetch({
text: code,
url: sourceURLs[i],
sourceMappingURL: sourceMappingURLs[i],
});

injectFunction(code, sourceURLs[i]);
})
return;
}
// 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;

// TODO: add support for opening filename by clicking on the stacktrace
const error = data.body;
throw new Error(error.type + ' ' + error.description);
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}`);
}
}
};
},
};
Expand Down
42 changes: 25 additions & 17 deletions React/Modules/RCTDevLoadingView.m
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,13 @@ - (void)setBridge:(RCTBridge *)bridge
[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;
Expand All @@ -77,34 +76,23 @@ - (void)showWithURL:(NSURL *)URL
[_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
Expand All @@ -119,6 +107,26 @@ - (void)hide
});
}

- (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
Expand Down
5 changes: 4 additions & 1 deletion local-cli/server/util/attachHMRServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 => {
Expand Down Expand Up @@ -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 => {
Expand Down

0 comments on commit 36efbc3

Please sign in to comment.