react-native-webpack-server
react-native-webpack-server copied to clipboard
Fix hot module replacement for RN 0.12
New in [email protected]: when using the Chrome debugger, the app bundle is now run inside a web worker: https://github.com/facebook/react-native/pull/1632, https://github.com/facebook/react-native/commit/8db35d492b846f51a758e8ee7e5e402c6bad3785
This means that an app bundle built with webpack's hot module replacement enabled will raise errors such as #99, and hot module replacement will fail.
I'm able to get HMR working on the rn-0.12-hmr branch by doing the following:
-
Use webpack-dev-middleware + webpack-hot-middleware instead of webpack/hot/only-dev-server + webpack-dev-server/client:
webpack-dev-server depends on
window.postMessage
to broadcast "webpackHotUpdate" events to any loaded scripts (usually just'webpack/hot/dev-server'
or'webpack/hot/only-dev-server'
), which does not work in the context of a web worker since web workers have a differentpostMessage
API. webpack-hot-middleware is an alternative which combines the functionality of bothwebpack/hot/only-dev-server
andwebpack-dev-server/client
. -
Patch webpack so it uses
importScripts
inside a web worker instead of the default behaviour of appending a<script>
with the new hot-reloaded module: https://github.com/elliottsj/webpack/commit/743a00a8bc491f1900ce9f49150229183f874da1.~~Known issue: this inexplicable error is thrown every time a module is hot reloaded:~~ Edit: turns out this was caused by adding
webpack.HotModuleReplacementPlugin()
to the config twice instead of once (-‸ლ)~~Not sure why this happens; the original error message & stack gets lost somewhere.~~
Try out rn-0.12-hmr/Examples/BabelES6 for a working example.
My patch to webpack seems quite hacky; I think the proper solution is to make something like 'WebWorkerMainTemplate.runtime.js', but I don't know enough about webpack internals to know what to do here.
Does anyone have any ideas on the proper way to do HMR from inside the web worker? cc @gaearon @sokra
WebWorkerMainTemplate.runtime.js
is the way to go. Settings target: "webworker"
will enabled it. Should be pretty easy to write as importScripts
is sync.
WebWorkerHotUpdateChunkTemplatePlugin.js
is also needed to defined the hot update chunk format for web workers, but it can be equal to JsonpHotUpdateChunkTemplatePlugin.js
.
If someone want to do a PR to webpack, I would be happy...
Opened PR to support HMR in web workers: https://github.com/webpack/webpack/pull/1521
I tried using your branch, but I get this warning the first time I change a file (and HMR doesn't work):
...
Any opinions?
UPDATE: Nevermind. It worked with your webpack PR.
@dapetcu21 Hi, i'm stuck with this webworker error and maybe you can help me. Where did you put the "var worker = new Worker("bundle.js");"?
@paolorovella You don't need var worker = new Worker("bundle.js");
. The RN debugger will load the bundle into a web worker for you; try out the rn-0.12-hmr/Examples/BabelES6 example.
I finally did it! I'm using RN 0.12 + react-native-webpack-server#rn-0.12-hmr + elliottsj/webpack#web-worker-hmr + webpack-hot-middleware
without var worker = new Worker('bundle.js');
and without target:"webworker
...thank you so much :)
@paolorovella: Yup. Exactly same setup worked for me, as well. I was initially trying the rn-0.12-hack
branch that was mentioned earlier.
Just pushed an update to rn-0.12-hmr/Examples/BabelES6: it now uses the changes from https://github.com/webpack/webpack/pull/1521 instead of the hack.
Hi! Since i was very happy for the working HMR in my simulator, i've decided to try on my iPhone 6. Unfortunately it doesn't work and this is my console. Any ideas?
You need to change localhost to your computer's IP/hostname in AppDelegate.m
Also, webpack's publicPath should include your hostname as well
I've already done it but it doesn't work :/ if it can helps, if i go to http://localhost:8082/ i get "Cannot get /" but if i go to http://192.168.1.156:8082/ the page is not available.
Firewall settings?
On 22 Oct 2015, at 17:49, Paolo Rovella [email protected] wrote:
I've already done it but it doesn't work :/ if it can helps, if i go to http://localhost:8082/ i get "Cannot get /" but if i go to http://192.168.1.156:8082/ the page is not available.
— Reply to this email directly or view it on GitHub.
Firewall deactivated :) could it be a port forwarding router problem? 8082 closed port i mean
It could be that rnws binds only to localhost: app.listen('localhost', port)
@dapetcu21 i've changed in package.json
-> HOT=1 ./node_modules/.bin/react-native-webpack-server start --hot --hostname 192.168.1.156
and now http://192.168.1.156:8082/index.ios.js gives me the bundle but when i update a component the HMR is not starting
@dapetcu21 i've forgotten to set http://192.168.1.156:8082 in 'webpack-hot-middleware/client?path=http://192.168.1.156:8082/__webpack_hmr&overlay=false'
now everything is working :) thank you so much
@elliottsj You're missing webpack-hot-middleware
in the package.json
of https://github.com/mjohnston/react-native-webpack-server/blob/rn-0.12-hmr/Examples/BabelES6/package.json
@elliottsj Hot reloading still doesn't seem to work - and now neither does LiveReload
@elliottsj Here's some output if it helps... this occurs after I save a file (the debugger/websocket stuff is connected already, it looks like the hotpack files might not be reloading properly or triggering intent refresh or something, not sure...?)
webpack built 872a39c5ec3c5bdae6a4 in 441ms
Hash: 872a39c5ec3c5bdae6a4
Version: webpack 1.12.2
Time: 441ms
Asset Size Chunks Chunk Names
index.ios.js 117 kB 0 [emitted] index.ios
index.android.js 104 kB 1 [emitted] index.android
0.dfd585fc6ce8bf86eb49.hot-update.js 3.79 kB 0 [emitted] index.ios
dfd585fc6ce8bf86eb49.hot-update.json 36 bytes [emitted]
index.ios.js.map 160 kB 0 [emitted] index.ios
0.dfd585fc6ce8bf86eb49.hot-update.js.map 4.2 kB 0 [emitted] index.ios
index.android.js.map 140 kB 1 [emitted] index.android
chunk {0} index.ios.js, 0.dfd585fc6ce8bf86eb49.hot-update.js, index.ios.js.map, 0.dfd585fc6ce8bf86eb49.hot-update.js.map (index.ios) 86.1 kB [rendered]
chunk {1} index.android.js, index.android.js.map (index.android) 73.9 kB [rendered]
webpack: bundle is now VALID.
[3:29:27 PM] <START> find dependencies
[3:29:27 PM] <END> find dependencies (96ms)
[3:29:27 PM] <START> transform
transforming [========================================] 100% 314/314
[3:29:27 PM] <END> transform (114ms)
Invalid HMR message: {"action":"built","time":441,"hash":"872a39c5ec3c5bdae6a4","warnings":[],"errors":[],"modules":{"0":"multi index.android","1":"./~/react-native/Libraries/react-native/react-native.js","2":"./~/react-transform-hmr/~/react-proxy/~/lodash/lang/isObject.js","3":"./~/react-transform-hmr/~/react-proxy/~/lodash/internal/isArrayLike.js","4":"./~/react-transform-hmr/~/react-proxy/~/lodash/internal/isObjectLike.js","5":"./~/react-transform-hmr/~/react-proxy/~/lodash/internal/getNative.js","6":"./~/react-transform-hmr/~/react-proxy/~/lodash/internal/isLength.js","7":"(webpack)/buildin/module.js","8":"./~/babel-runtime/helpers/interop-require-default.js","9":"./~/react-transform-hmr/lib/index.js","10":"./~/react-transform-hmr/~/react-proxy/~/lodash/internal/isIndex.js","11":"./~/react-transform-hmr/~/react-proxy/~/lodash/lang/isArguments.js","12":"./~/react-transform-hmr/~/react-proxy/~/lodash/lang/isArray.js","13":"./~/babel-runtime/~/core-js/library/modules/$.core.js","14":"./~/react-transform-hmr/~/react-proxy/~/lodash/function/restParam.js","15":"./~/react-transform-hmr/~/react-proxy/~/lodash/object/keys.js","16":"external "NativeModules"","17":"./~/react-native-button/Button.js","18":"./~/react-native-button/coalesceNonElementChildren.js","19":"./~/react-native-form/index.js","20":"./~/babel-runtime/core-js/object/assign.js","21":"./~/babel-runtime/helpers/extends.js","22":"./~/babel-runtime/~/core-js/library/fn/object/assign.js","23":"./~/babel-runtime/~/core-js/library/modules/$.assign.js","24":"./~/babel-runtime/~/core-js/library/modules/$.cof.js","25":"./~/babel-runtime/~/core-js/library/modules/$.def.js","26":"./~/babel-runtime/~/core-js/library/modules/$.defined.js","27":"./~/babel-runtime/~/core-js/library/modules/$.fails.js","28":"./~/babel-runtime/~/core-js/library/modules/$.global.js","29":"./~/babel-runtime/~/core-js/library/modules/$.iobject.js","30":"./~/babel-runtime/~/core-js/library/modules/$.js","31":"./~/babel-runtime/~/core-js/library/modules/$.to-object.js","32":"./~/babel-runtime/~/core-js/library/modules/es6.object.assign.js","33":"./~/react-transform-hmr/~/global/window.js","34":"./~/react-transform-hmr/~/react-proxy/modules/bindAutoBindMethods.js","35":"./~/react-transform-hmr/~/react-proxy/modules/createClassProxy.js","36":"./~/react-transform-hmr/~/react-proxy/modules/createPrototypeProxy.js","37":"./~/react-transform-hmr/~/react-proxy/modules/deleteUnknownAutoBindMethods.js","38":"./~/react-transform-hmr/~/react-proxy/modules/index.js","39":"./~/react-transform-hmr/~/react-proxy/~/lodash/array/difference.js","40":"./~/react-transform-hmr/~/react-proxy/~/lodash/internal/SetCache.js","41":"./~/react-transform-hmr/~/react-proxy/~/lodash/internal/arrayPush.js","42":"./~/react-transform-hmr/~/react-proxy/~/lodash/internal/assignWith.js","43":"./~/react-transform-hmr/~/react-proxy/~/lodash/internal/baseAssign.js","44":"./~/react-transform-hmr/~/react-proxy/~/lodash/internal/baseCopy.js","45":"./~/react-transform-hmr/~/react-proxy/~/lodash/internal/baseDifference.js","46":"./~/react-transform-hmr/~/react-proxy/~/lodash/internal/baseFlatten.js","47":"./~/react-transform-hmr/~/react-proxy/~/lodash/internal/baseIndexOf.js","48":"./~/react-transform-hmr/~/react-proxy/~/lodash/internal/baseProperty.js","49":"./~/react-transform-hmr/~/react-proxy/~/lodash/internal/bindCallback.js","50":"./~/react-transform-hmr/~/react-proxy/~/lodash/internal/cacheIndexOf.js","51":"./~/react-transform-hmr/~/react-proxy/~/lodash/internal/cachePush.js","52":"./~/react-transform-hmr/~/react-proxy/~/lodash/internal/createAssigner.js","53":"./~/react-transform-hmr/~/react-proxy/~/lodash/internal/createCache.js","54":"./~/react-transform-hmr/~/react-proxy/~/lodash/internal/getLength.js","55":"./~/react-transform-hmr/~/react-proxy/~/lodash/internal/indexOfNaN.js","56":"./~/react-transform-hmr/~/react-proxy/~/lodash/internal/isIterateeCall.js","57":"./~/react-transform-hmr/~/react-proxy/~/lodash/internal/shimKeys.js","58":"./~/react-transform-hmr/~/react-proxy/~/lodash/lang/isFunction.js","59":"./~/react-transform-hmr/~/react-proxy/~/lodash/lang/isNative.js","60":"./~/react-transform-hmr/~/react-proxy/~/lodash/object/assign.js","61":"./~/react-transform-hmr/~/react-proxy/~/lodash/object/keysIn.js","62":"./~/react-transform-hmr/~/react-proxy/~/lodash/utility/identity.js","63":"./~/react-transform-hmr/~/react-proxy/~/react-deep-force-update/lib/index.js","64":"external "ActionSheetIOS"","65":"external "ActivityIndicatorIOS"","66":"external "AdSupportIOS"","67":"external "AlertIOS"","68":"external "Animated"","69":"external "AppRegistry"","70":"external "AppStateIOS"","71":"external "AsyncStorage"","72":"external "BackAndroid"","73":"external "CameraRoll"","74":"external "DatePickerIOS"","75":"external "Dimensions"","76":"external "DrawerLayoutAndroid"","77":"external "Easing"","78":"external "EdgeInsetsPropType"","79":"external "Image"","80":"external "ImagePickerIOS"","81":"external "InteractionManager"","82":"external "LayoutAnimation"","83":"external "LinkedStateMixin"","84":"external "LinkingIOS"","85":"external "ListView"","86":"external "MapView"","87":"external "Modal"","88":"external "Navigator"","89":"external "NavigatorIOS"","90":"external "NetInfo"","91":"external "PanResponder"","92":"external "PickerIOS"","93":"external "PixelRatio"","94":"external "Platform"","95":"external "PointPropType"","96":"external "ProgressBarAndroid"","97":"external "ProgressViewIOS"","98":"external "PushNotificationIOS"","99":"external "RCTDeviceEventEmitter"","100":"external "RCTNativeAppEventEmitter"","101":"external "React"","102":"external "ReactComponentWithPureRenderMixin"","103":"external "ReactDefaultPerf"","104":"external "ReactFragment"","105":"external "ReactTestUtils"","106":"external "ReactUpdates"","107":"external "ScrollView"","108":"external "SegmentedControlIOS"","109":"external "Settings"","110":"external "SliderIOS"","111":"external "StatusBarIOS"","112":"external "StyleSheet"","113":"external "SwitchAndroid"","114":"external "SwitchIOS"","115":"external "TabBarIOS"","116":"external "Text"","117":"external "TextInput"","118":"external "ToastAndroid"","119":"external "ToolbarAndroid"","120":"external "TouchableHighlight"","121":"external "TouchableNativeFeedback"","122":"external "TouchableOpacity"","123":"external "TouchableWithoutFeedback"","124":"external "VibrationIOS"","125":"external "View"","126":"external "WebView"","127":"external "cloneWithProps"","128":"external "processColor"","129":"external "requireNativeComponent"","130":"external "update"","131":"./src/main.android.js","132":"./src/main.ios.js","133":"./~/react-native-webpack-server/hot/entry.js","134":"(webpack)-hot-middleware/client-overlay.js","135":"(webpack)-hot-middleware/client.js?path=http://localhost:8082/__webpack_hmr&overlay=false","136":"(webpack)-hot-middleware/~/querystring/decode.js","137":"(webpack)-hot-middleware/~/querystring/encode.js","138":"(webpack)-hot-middleware/~/querystring/index.js","139":"(webpack)-hot-middleware/~/strip-ansi/index.js","140":"(webpack)-hot-middleware/~/strip-ansi/~/ansi-regex/index.js","141":"(webpack)-hot-middleware/process-update.js"}} ReferenceError: hotDownloadManifest is not defined
Here's my webpack.config.js
:
var path = require('path');
var webpack = require('webpack');
var config = {
context: __dirname,
debug: true,
devtool: 'source-map',
watch: true,
entry: {
'index.ios': ['./src/main.ios.js']
'index.android': ['./src/main.android.js'],
},
output: {
path: path.resolve(__dirname, 'build'),
filename: '[name].js',
},
module: {
loaders: [
{
test: /\.(js|jsx|es6)$/,
loader: 'babel-loader',
include: [
path.resolve(__dirname, 'src'),
path.resolve(__dirname, 'node_modules/react-native-button'),
path.resolve(__dirname, 'node_modules/react-native-form')
],
query: {
optional: [
'runtime'
],
stage: 0,
plugins: []
}
}
]
},
resolve: { extensions: ['', '.js', '.jsx', '.es6'] },
plugins: []
};
// Hot loader
if (process.env.HOT) {
config.devtool = 'source-map';
config.entry['index.ios'].unshift(
'react-native-webpack-server/hot/entry',
'webpack-hot-middleware/client?path=http://localhost:8082/__webpack_hmr&overlay=false'
);
config.output.publicPath = 'http://localhost:8082/';
config.plugins.unshift(
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin()
);
config.module.loaders[0].query.plugins.push('react-transform');
config.module.loaders[0].query.extra = {
'react-transform': {
transforms: [
{
transform: 'react-transform-hmr',
imports: ['react-native'],
locals: ['module']
}
]
}
};
}
// Production config
if (process.env.NODE_ENV === 'production') {
config.plugins.push(new webpack.optimize.OccurrenceOrderPlugin());
config.plugins.push(new webpack.optimize.UglifyJsPlugin());
}
module.exports = config;
Here's my package.json
:
{
"name": "App",
"version": "0.0.1",
"private": true,
"scripts": {
"bundle": "react-native-webpack-server bundle",
"start": "react-native-webpack-server start",
"hot": "HOT=1 react-native-webpack-server start --hot",
"start-android-webpack-server": "HOT=1 react-native-webpack-server start --hot -e index.android -P 9090 -p 9091 -w 9092",
"install-app-to-android-device": "cd android && ./gradlew installDebug",
"setup-reverse-tcp-for-android-device": "adb reverse tcp:8081 tcp:9090",
"launch-android-app-on-device": "cd android && adb shell am start -n com.\"$npm_package_name\"/.MainActivity",
"android": "npm run-script setup-reverse-tcp-for-android-device && npm run-script install-app-to-android-device && npm run-script launch-android-app-on-device && echo \"Please Reload JS on the app from the menu after the webpack server starts below\" && npm run-script start-android-webpack-server"
},
"dependencies": {
"react-native": "~0.12.0",
"react-native-button": "^1.2.1",
"react-native-form": "^0.1.6"
},
"devDependencies": {
"babel-core": "^5.8.25",
"babel-loader": "^5.3.2",
"babel-plugin-react-transform": "^1.1.1",
"babel-runtime": "^5.8.25",
"eslint-plugin-react": "^3.6.1",
"react-native-webpack-server": "mjohnston/react-native-webpack-server#rn-0.12-hmr",
"react-transform-hmr": "^1.0.1",
"webpack": "elliottsj/webpack#web-worker-hmr"
}
}
@niftylettuce You also need target: 'webworker'
in your webpack config, e.g. https://github.com/mjohnston/react-native-webpack-server/blob/rn-0.12-hmr/Examples/BabelES6/webpack.config.js#L7
I'm happy to help on Discord#react-native-webpack if you need more help :smile:
That didn't work, I got hotModule not defined error above if I put webworker:true in config On Oct 26, 2015 4:53 PM, "Spencer Elliott" [email protected] wrote:
@niftylettuce https://github.com/niftylettuce You also need target: 'webworker' in your webpack config, e.g. https://github.com/mjohnston/react-native-webpack-server/blob/rn-0.12-hmr/Examples/BabelES6/webpack.config.js#L7
I'm happy to help on Discord#react-native-webpack http://www.reactiflux.com/ if you need more help [image: :smile:]
— Reply to this email directly or view it on GitHub https://github.com/mjohnston/react-native-webpack-server/issues/103#issuecomment-151281886 .
Got it working! :balloon:
Then share it! Step by step :-)
Sent from my iPhone
On 27 Oct 2015, at 01:09, niftylettuce [email protected] wrote:
Got it working!
— Reply to this email directly or view it on GitHub.
@niftylettuce Did you make it worked? I have the same issue with you:
Invalid HMR message: ....
I also add target: 'webworker'
to config file but nothing happen.
Please share your tips.
@niftylettuce I also have the same issue as you. How did you make it work? Hope you can help us, thanks!
I don't recommend to use hotloading until it has complete Android and iOS support. The headache and time ensued for me getting it to work, but now having to turn it off is not worth having it. Just CMD+R and reload. You don't need experimental hot reloading. On Nov 4, 2015 12:55 PM, "RyGuyM" [email protected] wrote:
@niftylettuce https://github.com/niftylettuce I also have the same issue as you. How did you make it work? Hope you can help us, thanks!
— Reply to this email directly or view it on GitHub https://github.com/mjohnston/react-native-webpack-server/issues/103#issuecomment-153808955 .