Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Auto-refresh simulator #5

Closed
nick opened this issue Jan 30, 2015 · 28 comments
Closed

Auto-refresh simulator #5

nick opened this issue Jan 30, 2015 · 28 comments
Labels
Resolution: Locked This issue was locked by the bot.

Comments

@nick
Copy link

nick commented Jan 30, 2015

Is it possible to have the simulator automatically refresh when a file is changed instead of Cmd-R?

@vjeux
Copy link
Contributor

vjeux commented Jan 30, 2015

Yes. We need to port that over. Expect it in a few days/weeks.

@a2
Copy link
Contributor

a2 commented Jan 30, 2015

I was thinking about this yesterday. A solution (although not optimal) would be to run a server locally in the simulator and have some process watch the local files and tell the simulator server that it should refresh. I was specifically looking at swisspol/GCDWebServer.

@vjeux
Copy link
Contributor

vjeux commented Jan 30, 2015

cc @amasad

@amasad
Copy link
Contributor

amasad commented Jan 31, 2015

@a2 this is an interesting approach. We already have a solid filewatcher on the server so it might be easier to do it there. The current solution that we have is that the client keeps polling the package and checking for changes. It works well. But it's a little bit janky. If we can open a persistent connection to the server and the server can ping the client to refresh once a file changes (and a package has been updated) would be ideal. In the future, this would also help us in doing things like hot code swapping.

@gaearon
Copy link
Collaborator

gaearon commented Jan 31, 2015

Why not leverage existing solutions like Webpack and webpack-dev-server? It does what you described. It uses chokidar for watching. The client code learns by a socket that update is available and either refreshes (without hot reloading), or does the hot reloading thing if it's configured.

See also #10 (comment) where I also rant about not using Webpack.

@amasad
Copy link
Contributor

amasad commented Jan 31, 2015

Webpack doesn't understand our module infrastructure out of the box. We have plans to support different module formats and different compilers. Additionally chokidar has so many problems but it's suffice to say it doesn't work on large codebases like ours. Regardless, we should get to a place where you decide what packager/module to use on the server.

@gaearon
Copy link
Collaborator

gaearon commented Jan 31, 2015

Webpack doesn't understand our module infrastructure out of the box.

Do you mean custom stuff like package-scoped “global” filenames? This can probably be done with a plugin. Or is it too vastly different?

Additionally chokidar has so many problems but it's suffice to say it doesn't work on large codebases like ours.

They fixed a lot of issues in 1.0. I used to find it unreliable for months, but I suggest you give it another try unless you're absolutely sure.

@gaearon
Copy link
Collaborator

gaearon commented Jan 31, 2015

Also Webpack does not depend on chokidar itself, its new default watching plugin does. It's entirely possible to plug another watcher implementation, but have exactly the same infrastructure for hot updates, etc.

@gaearon
Copy link
Collaborator

gaearon commented Jan 31, 2015

By the way, I'm sorry if this is something you don't plan to consider, I totally understand that.

I'm just saying it's a shame we'll have a different "push code updates" system on React Native because, if it is implemented, I expect it to only support "refresh" signals, whereas an existing Webpack solution supports Hot Module Replacement. Hot Module Replacement is vastly superior to a "refresh" signal system but supports it as a degraded simple case, so it's usable from day one.

Many React developers consider hot replacement useful. It's not trivial to implement, so if we're not reusing Webpack's HMR runtime, we likely won't get it soon..

@amasad
Copy link
Contributor

amasad commented Jan 31, 2015

I think we want to be flexible enough for users to make their own choices and maybe support some of the popular things out of the box. I'm on mobile now but I'll reply later with some of the constraints we had when building this and why we couldn't pick one of the ready made solutions.

@gaearon
Copy link
Collaborator

gaearon commented Jan 31, 2015

Thank you, appreciated!

It would be awesome if you exposed a way to reload a page and a way to "inject a script" to JS side. Then we'd be able to use any server and any (hot or not) reloading solution.. I think.

@amasad
Copy link
Contributor

amasad commented Feb 1, 2015

In addition to having a proprietary module format, and because we have a large codebase and needed to use watchman for high performance and more reliable file watching, performance was a big concern. We needed the compiler to work in parallel and we even hand optimized source map generation so we can give error stacks on the client with correct line numbers. Maybe everything can be written as a plugin to webpack but at what point you're reimplementing the program you're supposed to be plugging into. Finally, our vision to what our server should be doing is beyond packaging. We want to integrate Jest testing, Flow type checking, code optimization (dead code elimination, inlining etc).

That shouldn't mean that external react-native users shouldn't or can't use webpack, or for that matter shouldn't replace any of the things I mentioned. You should be able to use Mocha instead of Jest, or 6to5 instead of jstransform etc.

Anyways things are still pretty much work in progress, and feedback like this helps. Thanks

@ykagan
Copy link

ykagan commented Feb 1, 2015

I'm curious if you guys think it would help for us to provide support for webpack's loader and plugin API out of the box for our packaging system?

That would give us access to most of webpack's module ecosystem while still giving us flexibility to implement features that webpack may not be designed for - particularly features around testing, code intelligence, flow integration, etc.

@gaearon
Copy link
Collaborator

gaearon commented Feb 1, 2015

I'm sure Webpack's plugin API would be very hard (it's very tied to how Webpack processes modules, down to compilation phases) so it's probably entirely out of the question.

Implementing Webpack loader support is easier, but only for trivial things like transforming files. It's a lot more work for complex loader features (pitching loaders, async transformers, marking dependencies, require.resolve, etc). RN packager could implement a subset of those, but it is not worth it in my opinion, as it would only cause fragmentation in Webpack ecosystem (is that particular loader supported by RN?) and I doubt RN team wants to be constrained by Webpack APIs.

A more sustainable alternative, in my opinion, is to let users choose a bundler, and add whatever polyfills/bridges we may need for Webpack to work with RN:

  • WebSocket API or equivalent
  • An equivalent of window.reload()
  • An equivalent of loading <script> tag dynamically

I really wish @sokra was with us in this discussion!

@gaearon
Copy link
Collaborator

gaearon commented Feb 2, 2015

@sokra I heard you have access to this repo now, care to weigh in?

@sokra
Copy link

sokra commented Feb 2, 2015

Hi,

it looks like react-native just expects a URL to the bundle file, which is provided by the packager. Technically the packager could be replaced with webpack.

react-native also uses a non-standard way to append the SourceMap to the source (RAW_SOURCE_MAP = ... is appended). This could be implemented as webpack plugin. Or react-native could be changed to use the standard //#sourceMappingURL (errorToString may need to be changed to be async, because it need to fetch the SourceMap from the server).

I also think it's better to use webpack, because the current packager may only support a subset of npm modules (there are really weird modules that need to be parsed).

So until now, nothing complex...

For Code Splitting and Hot Module Replacement we need something to eval a javascript from a remote URL. Best is when react-native exposes a way to do that. i. e. importScripts like in a WebWorker or even better something async.

Hot Module Replacement also need to do a full reload of the app. This need to be accessible from the js side. (Looks like this is currently not possible)

If we got this, Hot Module Replacement would work, but only with polling... For a live experience we need a server to react-native connection, i. e. a WebSocket (Or we could use long polling).

The version from reactconf seem to have at least something for server to react-native notification, because saving causes a reload in the video...

@gaearon
Copy link
Collaborator

gaearon commented Feb 2, 2015

The version from reactconf seem to have at least something for server to react-native notification, because saving causes a reload in the video...

I think an earlier comment by @amasad says that:

The current solution that we have is that the client keeps polling the package and checking for changes.

@amasad
Copy link
Contributor

amasad commented Feb 4, 2015

@sokra @gaearon So initial experimentation looks good. However, like I expected, perf is the biggest concern:

  • It takes ~45 seconds to build our bundle.
  • It takes ~8 seconds to rebuild anytime a file is changed (with sourcemaps, without it's very fast)

Here is what I want:

  • I want loaders to run in parallel so that initial build doesn't take forever. I can do it in the loader code, when I get a request I send it to my worker farm. Is this the best way to do it?
  • Combining source maps and inlining it in the file (which is what we need to do) adds too much overhead. What we do in our packager is we hand build the sourcemap after creating the bundle which ends up being incredibly fast. How do we do that in Webpack? is there a way to hook into the last step of the bundle creation?
  • Is there a way to cache loader results on disk so on startup we won't have to build the whole thing? We just stat the files to see if they changed.

@jlongster
Copy link

Just to chime in, I would <3 to see this collaboration happen, since I've experienced similar perf problems. Makes me so happy to see a big company like facebook drive an existing project to be better :) (though I totally get why you did your own in the first place)

@sokra
Copy link

sokra commented Feb 4, 2015

I want loaders to run in parallel so that initial build doesn't take forever. I can do it in the loader code, when I get a request I send it to my worker farm. Is this the best way to do it?

I had the feature that loaders can run in a separate process in webpack 0.6 or so, but spawning a separate processes was pretty expensive and sending source code between processes too. Now better alternatives envolved in the node.js community like https://github.com/xk/node-threads-a-gogo and we could try it again with threads.

It takes ~8 seconds to rebuild anytime a file is changed (with sourcemaps, without it's very fast)

Combining source maps and inlining it in the file (which is what we need to do) adds too much overhead. What we do in our packager is we hand build the sourcemap after creating the bundle which ends up being incredibly fast. How do we do that in Webpack? is there a way to hook into the last step of the bundle creation?

Yeah... (high quality) SourceMaps are pretty slow. They are complex and the source-map lib is slow.

The current implementation in react-native is faster, because it only maps lines 1 to 1 (note: the jsx transformer keeps line numbers)... Maybe a similar alternative SourceMap devtool could be added to webpack. (More people would like that)

webpack also use some cools tricks to get faster SourceMaps:

  • devtool: "eval-source-map" Wraps every module in eval("... //#sourceMappingURL=data:..."). So we can create the SourceMap once and cache the result for recompilations.
  • devtool: "eval" Wrapps every module in eval("... //#sourceURL=..."). This doesn't show original sources, but at least give the module a proper name. (That's really fast.)

Of couse this is not supported by react-native currently...

@sokra
Copy link

sokra commented Feb 4, 2015

Is there a way to cache loader results on disk so on startup we won't have to build the whole thing? We just stat the files to see if they changed.

webpack/webpack#250

@amasad
Copy link
Contributor

amasad commented Feb 4, 2015

Now better alternatives envolved in the node.js community like https://github.com/xk/node-threads-a-gogo and we could try it again with threads.

Doesn't look like this project is actively supported. And looks like there is no windows support. Not that we currently support windows but we want to be able to.

node-worker-farm works really well and super easy to manage. https://github.com/rvagg/node-worker-farm

Maybe a similar alternative SourceMap devtool could be added to webpack. (More people would like that)

Is source map devtool currently pluggable? Is there documentation on how to write the plugin?

webpack/webpack#250

Cool. It seems that you want to be able to cache your entire state? But I can say from experience that caching just the transformation (loader results in webpack lingo) should get you a lot of the benefits.

@gaearon
Copy link
Collaborator

gaearon commented Feb 4, 2015

Is source map devtool currently pluggable? Is there documentation on how to write the plugin?

Yeah, absolutely, it's pluggable. Here's the default SourceMapDevToolPlugin:

https://github.com/webpack/webpack/blob/master/lib/SourceMapDevToolPlugin.js

Here's Webpack plugin API:

http://webpack.github.io/docs/plugins.html

You can remove devtool from config and instead put your plugin in plugins.

@frantic
Copy link
Contributor

frantic commented Feb 6, 2015

Or react-native could be changed to use the standard //#sourceMappingURL (errorToString may need to be changed to be async, because it need to fetch the SourceMap from the server).

Actually we started with this approach, but then tried including source maps inline and it turned out to be a better dev experience.

ide referenced this issue in expo/react-native Sep 15, 2015
[website] Extract platform metadata from components
dustturtle added a commit to dustturtle/react-native that referenced this issue Jul 6, 2016
…crash on simulator, on device I got nothing but app freezed)!

My app has an old version of JSONKit which is still using MRC. I think JSONKit is not needed if system version is available. Kicking out of JSONKit will make react native stronger.
Crash stack:
* thread facebook#11: tid = 0xbd672f, 0x000000010a10edeb imobii-waiqin`jk_encode_add_atom_to_buffer(encodeState=0x00007f9b820a1000, objectPtr=22 key/value pairs) + 16971 at JSONKit.m:2807, name = 'com.facebook.React.JavaScript', stop reason = EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
    frame #0: 0x000000010a10edeb imobii-waiqin`jk_encode_add_atom_to_buffer(encodeState=0x00007f9b820a1000, objectPtr=22 key/value pairs) + 16971 at JSONKit.m:2807
    frame facebook#1: 0x000000010a10ef67 imobii-waiqin`jk_encode_add_atom_to_buffer(encodeState=0x00007f9b820a1000, objectPtr=2 key/value pairs) + 17351 at JSONKit.m:2811
    frame facebook#2: 0x000000010a10ef67 imobii-waiqin`jk_encode_add_atom_to_buffer(encodeState=0x00007f9b820a1000, objectPtr=25 key/value pairs) + 17351 at JSONKit.m:2811
    frame facebook#3: 0x000000010a10e768 imobii-waiqin`jk_encode_add_atom_to_buffer(encodeState=0x00007f9b820a1000, objectPtr=@"3 elements") + 15304 at JSONKit.m:2778
  * frame facebook#4: 0x000000010a10a26a imobii-waiqin`-[JKSerializer serializeObject:options:encodeOption:block:delegate:selector:error:](self=0x00007f9b831fbc80, _cmd="serializeObject:options:encodeOption:block:delegate:selector:error:", object=@"3 elements", optionFlags=0, encodeOption=10, block=0x0000000000000000, delegate=0x0000000000000000, selector=<no value available>, error=domain: class name = NSInvocation - code: 0) + 2250 at JSONKit.m:2876
    frame facebook#5: 0x000000010a109992 imobii-waiqin`+[JKSerializer serializeObject:options:encodeOption:block:delegate:selector:error:](self=JKSerializer, _cmd="serializeObject:options:encodeOption:block:delegate:selector:error:", object=@"3 elements", optionFlags=0, encodeOption=10, block=0x0000000000000000, delegate=0x0000000000000000, selector=<no value available>, error=domain: class name = NSInvocation - code: 0) + 178 at JSONKit.m:2831
    frame facebook#6: 0x000000010a10f700 imobii-waiqin`-[NSArray(self=@"3 elements", _cmd="JSONStringWithOptions:error:", serializeOptions=0, error=domain: class name = NSInvocation - code: 0) JSONStringWithOptions:error:] + 112 at JSONKit.m:2985
    frame facebook#7: 0x000000010ac13c02 imobii-waiqin`_RCTJSONStringifyNoRetry(jsonObject=@"3 elements", error=domain: class name = NSInvocation - code: 0) + 338 at RCTUtils.m:49
    frame facebook#8: 0x000000010ac13990 imobii-waiqin`RCTJSONStringify(jsonObject=@"3 elements", error=0x0000000000000000) + 128 at RCTUtils.m:77
    frame facebook#9: 0x000000010ab5fdfa imobii-waiqin`__27-[RCTContextExecutor setUp]_block_invoke_2(.block_descriptor=<unavailable>, moduleName=@"UIManager") + 218 at RCTContextExecutor.m:363
    frame facebook#10: 0x00000001134495cc CoreFoundation`__invoking___ + 140
    frame facebook#11: 0x000000011344941e CoreFoundation`-[NSInvocation invoke] + 286
    frame facebook#12: 0x000000010db13db3 JavaScriptCore`JSC::ObjCCallbackFunctionImpl::call(JSContext*, OpaqueJSValue*, unsigned long, OpaqueJSValue const* const*, OpaqueJSValue const**) + 451
    frame facebook#13: 0x000000010db13926 JavaScriptCore`JSC::objCCallbackFunctionCallAsFunction(OpaqueJSContext const*, OpaqueJSValue*, OpaqueJSValue*, unsigned long, OpaqueJSValue const* const*, OpaqueJSValue const**) + 262
    frame facebook#14: 0x000000010db14bad JavaScriptCore`long long JSC::APICallbackFunction::call<JSC::ObjCCallbackFunction>(JSC::ExecState*) + 573
    frame facebook#15: 0x000000010dade340 JavaScriptCore`JSC::LLInt::setUpCall(JSC::ExecState*, JSC::Instruction*, JSC::CodeSpecializationKind, JSC::JSValue, JSC::LLIntCallLinkInfo*) + 528
    frame facebook#16: 0x000000010dae535d JavaScriptCore`llint_entry + 22900
    frame facebook#17: 0x000000010dadf7d9 JavaScriptCore`vmEntryToJavaScript + 326
    frame facebook#18: 0x000000010d9b1959 JavaScriptCore`JSC::JITCode::execute(JSC::VM*, JSC::ProtoCallFrame*) + 169
    frame facebook#19: 0x000000010d9985ad JavaScriptCore`JSC::Interpreter::executeCall(JSC::ExecState*, JSC::JSObject*, JSC::CallType, JSC::CallData const&, JSC::JSValue, JSC::ArgList const&) + 493
    frame facebook#20: 0x000000010d76cb7e JavaScriptCore`JSC::call(JSC::ExecState*, JSC::JSValue, JSC::CallType, JSC::CallData const&, JSC::JSValue, JSC::ArgList const&) + 62
    frame facebook#21: 0x000000010d929a55 JavaScriptCore`JSC::callGetter(JSC::ExecState*, JSC::JSValue, JSC::JSValue) + 149
    frame facebook#22: 0x000000010dad49fb JavaScriptCore`llint_slow_path_get_by_id + 2203
    frame facebook#23: 0x000000010dae22f0 JavaScriptCore`llint_entry + 10503
    frame facebook#24: 0x000000010dae5368 JavaScriptCore`llint_entry + 22911
    frame facebook#25: 0x000000010dae52fd JavaScriptCore`llint_entry + 22804
    frame facebook#26: 0x000000010dae5368 JavaScriptCore`llint_entry + 22911
    frame facebook#27: 0x000000010dae5368 JavaScriptCore`llint_entry + 22911
    frame facebook#28: 0x000000010dae52fd JavaScriptCore`llint_entry + 22804
    frame facebook#29: 0x000000010dae5368 JavaScriptCore`llint_entry + 22911
    frame facebook#30: 0x000000010dae5368 JavaScriptCore`llint_entry + 22911
    frame facebook#31: 0x000000010dae5368 JavaScriptCore`llint_entry + 22911
    frame facebook#32: 0x000000010dae552a JavaScriptCore`llint_entry + 23361
    frame facebook#33: 0x000000010dae5368 JavaScriptCore`llint_entry + 22911
    frame facebook#34: 0x000000010dae5368 JavaScriptCore`llint_entry + 22911
    frame facebook#35: 0x000000010dadf7d9 JavaScriptCore`vmEntryToJavaScript + 326
    frame facebook#36: 0x000000010d9b1959 JavaScriptCore`JSC::JITCode::execute(JSC::VM*, JSC::ProtoCallFrame*) + 169
    frame facebook#37: 0x000000010d998264 JavaScriptCore`JSC::Interpreter::execute(JSC::ProgramExecutable*, JSC::ExecState*, JSC::JSObject*) + 10404
    frame facebook#38: 0x000000010d7a8786 JavaScriptCore`JSC::evaluate(JSC::ExecState*, JSC::SourceCode const&, JSC::JSValue, WTF::NakedPtr<JSC::Exception>&) + 470
    frame facebook#39: 0x000000010d9f6fb8 JavaScriptCore`JSEvaluateScript + 424
    frame facebook#40: 0x000000010ab6379e imobii-waiqin`__68-[RCTContextExecutor executeApplicationScript:sourceURL:onComplete:]_block_invoke.264(.block_descriptor=<unavailable>) + 414 at RCTContextExecutor.m:589
    frame facebook#41: 0x000000010ab63262 imobii-waiqin`__68-[RCTContextExecutor executeApplicationScript:sourceURL:onComplete:]_block_invoke(.block_descriptor=<unavailable>) + 498 at RCTContextExecutor.m:589
    frame facebook#42: 0x000000010ab63df8 imobii-waiqin`-[RCTContextExecutor executeBlockOnJavaScriptQueue:](self=0x00007f9b832f6040, _cmd="executeBlockOnJavaScriptQueue:", block=0x00007f9b80c92970) + 248 at RCTContextExecutor.m:627
    frame facebook#43: 0x000000010eb1d7a7 Foundation`__NSThreadPerformPerform + 283
    frame facebook#44: 0x0000000113486301 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
    frame facebook#45: 0x000000011347c22c CoreFoundation`__CFRunLoopDoSources0 + 556
    frame facebook#46: 0x000000011347b6e3 CoreFoundation`__CFRunLoopRun + 867
    frame facebook#47: 0x000000011347b0f8 CoreFoundation`CFRunLoopRunSpecific + 488
    frame facebook#48: 0x000000010ab5e41b imobii-waiqin`+[RCTContextExecutor runRunLoopThread](self=RCTContextExecutor, _cmd="runRunLoopThread") + 363 at RCTContextExecutor.m:284
    frame facebook#49: 0x000000010ebc012b Foundation`__NSThread__start__ + 1198
    frame facebook#50: 0x00000001140869b1 libsystem_pthread.dylib`_pthread_body + 131
    frame facebook#51: 0x000000011408692e libsystem_pthread.dylib`_pthread_start + 168
    frame facebook#52: 0x0000000114084385 libsystem_pthread.dylib`thread_start + 13
daniel-beard added a commit to daniel-beard/react-native that referenced this issue Sep 13, 2016
…L-620

REBEL-620: Providing better alert information when developers are try…
facebook-github-bot pushed a commit that referenced this issue Nov 7, 2017
Summary:
A blog post with notes from the second React Native monthly meeting. I've gathered notes after the meeting in this blog post.

No test plan, submitting just a documentation file.

[DOCS] [ENHANCEMENT] [blog/2017-11-06-react-native-monthly-5.md] - Submitting notes from React Native monthly #5.

cc hramos
Closes #16694

Differential Revision: D6259640

Pulled By: hramos

fbshipit-source-id: 328ab6018300bef91bdc8561ac8cbd64d3d93129
cdlewis pushed a commit to cdlewis/react-native that referenced this issue Nov 19, 2017
Summary:
A blog post with notes from the second React Native monthly meeting. I've gathered notes after the meeting in this blog post.

No test plan, submitting just a documentation file.

[DOCS] [ENHANCEMENT] [blog/2017-11-06-react-native-monthly-5.md] - Submitting notes from React Native monthly facebook#5.

cc hramos
Closes facebook#16694

Differential Revision: D6259640

Pulled By: hramos

fbshipit-source-id: 328ab6018300bef91bdc8561ac8cbd64d3d93129
DaKaZ pushed a commit to DaKaZ/react-native that referenced this issue Jan 4, 2018
# This is the 1st commit message:

adds --port option to `react-native run-ios` as well as patches port option with run-android to properly detect and start the packager

# This is the commit message facebook#2:

refactor iOS build to use preprocessor variable set from env variable; clean up sytle issues

# This is the commit message facebook#3:

add ifndef for default ports and change name of env var to RCT_METRO_PORT

# This is the commit message facebook#4:

move defines to RCTDefines.h

# This is the commit message facebook#5:

add new line

# This is the commit message facebook#6:

fix code formating issue
@facebook facebook locked as resolved and limited conversation to collaborators May 29, 2018
@react-native-bot react-native-bot added the Resolution: Locked This issue was locked by the bot. label Jul 23, 2018
react-one pushed a commit to react-one/react-native that referenced this issue Sep 24, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Resolution: Locked This issue was locked by the bot.
Projects
None yet
Development

No branches or pull requests