Skip to content

Commit

Permalink
Pipe platform and bundleEntry through WebSocket connection
Browse files Browse the repository at this point in the history
Reviewed By: vjeux

Differential Revision: D2793572

fb-gh-sync-id: 6ce2467b8d528d1a91c1b4fc51741f2502674022
  • Loading branch information
martinbigio authored and facebook-github-bot-8 committed Dec 30, 2015
1 parent dd8e1f9 commit 5f850fb
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 19 deletions.
12 changes: 10 additions & 2 deletions Libraries/Utilities/HMRClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,28 @@
*/
'use strict';

const invariant = require('invariant');

/**
* HMR Client that receives from the server HMR updates and propagates them
* runtime to reflects those changes.
*/
const HMRClient = {
enable() {
enable(platform, bundleEntry) {
invariant(platform, 'Missing required parameter `platform`');
invariant(bundleEntry, 'Missing required paramenter `bundleEntry`');

// need to require WebSocket inside of `enable` function because the
// this module is defined as a `polyfillGlobal`.
// See `InitializeJavascriptAppEngine.js`
const WebSocket = require('WebSocket');

// TODO(martinb): parametrize the url and receive entryFile to minimize
// the number of updates we want to receive from the server.
const activeWS = new WebSocket('ws://localhost:8081/hot');
const activeWS = new WebSocket(
'ws://localhost:8081/hot?platform=' + platform + '&bundleEntry=' +
bundleEntry.replace('.bundle', '.js')
);
activeWS.onerror = (e) => {
console.error('[Hot Module Replacement] Unexpected error', e);
};
Expand Down
22 changes: 15 additions & 7 deletions React/Executors/RCTJSCExecutor.m
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ @implementation RCTJSCExecutor
{
RCTJavaScriptContext *_context;
NSThread *_javaScriptThread;
NSURL *_bundleURL;
}

@synthesize valid = _valid;
Expand Down Expand Up @@ -145,22 +146,22 @@ static void RCTInstallJSCProfiler(RCTBridge *bridge, JSContextRef context)
}
}

static BOOL isHotLoadingEnabled()
{
NSString *enabledQS = [[RCTBundleURLProcessor sharedProcessor] getQueryStringValue:@"hot"];
return (enabledQS != nil && [enabledQS isEqualToString:@"true"]) ? YES : NO;
}

static void RCTInstallHotLoading(RCTBridge *bridge, RCTJSCExecutor *executor)
{
[bridge.devMenu addItem:[RCTDevMenuItem toggleItemWithKey:RCTHotLoadingEnabledDefaultsKey title:@"Enable Hot Loading" selectedTitle:@"Disable Hot Loading" handler:^(BOOL enabledOnCurrentBundle) {
[executor executeBlockOnJavaScriptQueue:^{
NSString *enabledQS = [[RCTBundleURLProcessor sharedProcessor] getQueryStringValue:@"hot"];
BOOL enabledOnConfig = (enabledQS != nil && [enabledQS isEqualToString:@"true"]) ? YES : NO;

BOOL enabledOnConfig = isHotLoadingEnabled();
// reload bundle when user change Hot Loading setting
if (enabledOnConfig != enabledOnCurrentBundle) {
[[RCTBundleURLProcessor sharedProcessor] setQueryStringValue:enabledOnCurrentBundle ? @"true" : @"false" forAttribute:@"hot"];
[bridge reload];
}

if (enabledOnCurrentBundle) {
[bridge enqueueJSCall:@"HMRClient.enable" args:@[@YES]];
}
}];
}]];
}
Expand Down Expand Up @@ -534,6 +535,13 @@ - (void)executeApplicationScript:(NSData *)script
onComplete(error);
}
}), 0, @"js_call", (@{ @"url": sourceURL.absoluteString }))];

#if RCT_DEV
if (isHotLoadingEnabled()) {
// strip initial slash
[_bridge enqueueJSCall:@"HMRClient.enable" args:@[@"ios", [sourceURL.path substringFromIndex: 1]]];
}
#endif
}

- (void)executeBlockOnJavaScriptQueue:(dispatch_block_t)block
Expand Down
27 changes: 17 additions & 10 deletions local-cli/server/util/attachHMRServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,30 @@
*/
'use strict';

const querystring = require('querystring');
const url = require('url');

/**
* Attaches a WebSocket based connection to the Packager to expose
* Hot Module Replacement updates to the simulator.
*/
function attachHMRServer({httpServer, path, packagerServer}) {
let activeWS;
let client = null;

function disconnect() {
activeWS = null;
client = null;
}

packagerServer.addFileChangeListener(filename => {
if (!activeWS) {
if (!client) {
return;
}

packagerServer.buildBundleForHMR({
entryFile: filename,
// TODO(martinb): receive platform on query string when client connects
platform: 'ios',
platform: client.platform,
})
.then(bundle => activeWS.send(bundle));
.then(bundle => client.ws.send(bundle));
});

const WebSocketServer = require('ws').Server;
Expand All @@ -41,14 +43,19 @@ function attachHMRServer({httpServer, path, packagerServer}) {
console.log('[Hot Module Replacement] Server listening on', path);
wss.on('connection', ws => {
console.log('[Hot Module Replacement] Client connected');
activeWS = ws;

ws.on('error', e => {
const params = querystring.parse(url.parse(ws.upgradeReq.url).query);
client = {
ws,
platform: params.platform,
bundleEntry: params.bundleEntry,
};

client.ws.on('error', e => {
console.error('[Hot Module Replacement] Unexpected error', e);
disconnect();
});

ws.on('close', () => disconnect());
client.ws.on('close', () => disconnect());
});
}

Expand Down

0 comments on commit 5f850fb

Please sign in to comment.