2015-12-29 00:43:08 +00:00
/ * *
* 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
2016-02-27 23:57:14 +00:00
* @ flow
2015-12-29 00:43:08 +00:00
* /
'use strict' ;
2016-02-12 16:09:43 +00:00
const Platform = require ( 'Platform' ) ;
2016-03-02 12:27:13 +00:00
const invariant = require ( 'fbjs/lib/invariant' ) ;
2015-12-30 02:24:06 +00:00
2015-12-29 00:43:08 +00:00
/ * *
* HMR Client that receives from the server HMR updates and propagates them
* runtime to reflects those changes .
* /
const HMRClient = {
2016-02-27 23:57:14 +00:00
enable ( platform : string , bundleEntry : string , host : string , port : number ) {
2015-12-30 02:24:06 +00:00
invariant ( platform , 'Missing required parameter `platform`' ) ;
invariant ( bundleEntry , 'Missing required paramenter `bundleEntry`' ) ;
2016-02-12 16:09:43 +00:00
invariant ( host , 'Missing required paramenter `host`' ) ;
2016-01-04 17:55:09 +00:00
2016-01-27 22:55:02 +00:00
// need to require WebSocket inside of `enable` function because
2015-12-29 00:43:21 +00:00
// this module is defined as a `polyfillGlobal`.
// See `InitializeJavascriptAppEngine.js`
const WebSocket = require ( 'WebSocket' ) ;
2015-12-29 00:43:08 +00:00
2016-02-12 16:09:43 +00:00
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 ) ;
2015-12-29 00:43:21 +00:00
activeWS . onerror = ( e ) => {
2016-03-21 21:07:09 +00:00
let error = (
2016-01-04 17:55:09 +00:00
` Hot loading isn't working because it cannot connect to the development server.
2016-03-21 21:07:09 +00:00
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 += (
`
2016-01-04 17:55:09 +00:00
URL : $ { host } : $ { port }
Error : $ { e . message } `
) ;
2016-03-21 21:07:09 +00:00
throw new Error ( error ) ;
2015-12-29 00:43:21 +00:00
} ;
2016-01-07 21:14:18 +00:00
activeWS . onmessage = ( { data } ) => {
2016-02-27 23:57:14 +00:00
// Moving to top gives errors due to NativeModules not being initialized
const HMRLoadingView = require ( 'HMRLoadingView' ) ;
2016-01-07 21:14:18 +00:00
data = JSON . parse ( data ) ;
2016-01-27 22:55:02 +00:00
2016-02-12 16:09:43 +00:00
switch ( data . type ) {
2016-02-01 20:41:04 +00:00
case 'update-start' : {
2016-02-27 23:57:14 +00:00
HMRLoadingView . showMessage ( 'Hot Loading...' ) ;
2016-02-01 20:41:04 +00:00
break ;
}
case 'update' : {
2016-02-26 23:14:47 +00:00
const {
modules ,
sourceMappingURLs ,
sourceURLs ,
inverseDependencies ,
} = data . body ;
2016-01-27 22:55:02 +00:00
2016-02-12 16:09:43 +00:00
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 ( ) ;
}
2016-01-27 22:55:02 +00:00
2016-03-21 22:50:15 +00:00
modules . forEach ( ( { id , code } , i ) => {
2016-02-01 20:41:04 +00:00
code = code + '\n\n' + sourceMappingURLs [ i ] ;
2016-01-27 22:55:02 +00:00
2016-02-01 20:41:04 +00:00
// 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
2016-02-12 16:09:43 +00:00
const injectFunction = typeof global . nativeInjectHMRUpdate === 'function'
? global . nativeInjectHMRUpdate
2016-02-01 20:41:04 +00:00
: eval ;
2016-01-07 21:14:18 +00:00
2016-03-21 00:38:33 +00:00
code = [
` __accept( ` ,
2016-03-21 22:50:15 +00:00
` ${ id } , ` ,
2016-03-21 00:38:33 +00:00
` function(global,require,module,exports){ ` ,
` ${ code } ` ,
'\n},' ,
` ${ JSON . stringify ( inverseDependencies ) } ` ,
` ); ` ,
] . join ( '' ) ;
2016-02-26 23:14:47 +00:00
2016-02-01 20:41:04 +00:00
injectFunction ( code , sourceURLs [ i ] ) ;
} ) ;
2016-02-27 23:57:14 +00:00
HMRLoadingView . hide ( ) ;
2016-02-01 20:41:04 +00:00
break ;
}
case 'update-done' : {
2016-02-27 23:57:14 +00:00
HMRLoadingView . hide ( ) ;
2016-02-01 20:41:04 +00:00
break ;
}
case 'error' : {
2016-02-27 23:57:14 +00:00
HMRLoadingView . hide ( ) ;
2016-02-01 20:41:04 +00:00
throw new Error ( data . body . type + ' ' + data . body . description ) ;
}
default : {
throw new Error ( ` Unexpected message: ${ data } ` ) ;
}
}
2015-12-29 00:43:21 +00:00
} ;
2015-12-29 00:43:08 +00:00
} ,
} ;
module . exports = HMRClient ;