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

Support for configurable debug origin/port (issue 1429) #1546

Closed
wants to merge 16 commits into from

Conversation

bparadie
Copy link

@bparadie bparadie commented Jun 7, 2015

This PR adds support for configurable debug origin/port information as discussed in #1429 .

Summary

Here is a brief summary of my changes:

  • I added a new target called ReactWithoutPackager to React.xcodeproj that is a copy of the React target but does not execute the launchPackager.command script.
  • UIExplorer now links against libReactWithoutPackager.a, which attracts the ReactWithoutPackager target w/o launchPackager.command.
  • I added support for --origin parameter to packager.sh
  • I added a run script to UIExplorer that launches launchPackager.command with --origin and --port parameters.
  • Because I am now passing --origin and --port as parameters to launchPackager.command and open w/t --args does not seem to work with Terminal, I changed that code to using osascript instead.

Changing the port number

This is a screenshot after changing the port number to 8086 in Info.plist and rebuilding UIExplorer:

screen shot 2015-06-06 at 4 46 09 pm

Backwards compatibility

I decided to make this change backwards compatible so clients can choose to continue using the old hard-coded origin/port (http://localhost:8081). The main reason is that many devs probably pick an example project and start modifying it to fit their needs. If we required Info.plist entries for origin/port values those old modified examples would break.

Usage in examples

At this point I only modified UIExplorer to show that origin/port can be configured. But I could change all examples if needed.

Utility function

There are three places where I added code that looks up the values for origin/port from Info.plist. That code is fairly trivial but could still be extracted and shared as a utility function. Please advise if that is necessary and let me know where I should add that utility function to.

@facebook-github-bot
Copy link
Contributor

Thank you for your pull request and welcome to our community. We require contributors to sign our Contributor License Agreement, and we don't seem to have you on file. In order for us to review and merge your code, please sign up at https://code.facebook.com/cla - and if you have received this in error or have any questions, please drop us a line at cla@fb.com. Thanks!

@facebook-github-bot
Copy link
Contributor

Thank you for signing our Contributor License Agreement. We can now accept your code for this (and any) Facebook open source project. Thanks!

@facebook-github-bot facebook-github-bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Jun 7, 2015
@amasad
Copy link
Contributor

amasad commented Jun 15, 2015

I believe @frantic is the best person to review this

@amasad amasad assigned frantic and unassigned amasad Jun 15, 2015
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/bash;
shellScript = "export ORIGIN=$(/usr/libexec/PlistBuddy -c \"Print :RCTWebSocketExecutor:origin\" \"${INFOPLIST_FILE}\")\nexport PORT=$(/usr/libexec/PlistBuddy -c \"Print :RCTWebSocketExecutor:port\" \"${INFOPLIST_FILE}\")\n\nif nc -w 5 -z localhost $PORT ; then\n if ! curl -s \"${ORIGIN}:${PORT}/status\" | grep -q \"packager-status:running\" ; then\n echo \"Port ${PORT} already in use, packager is either not running or not running correctly\"\n exit 2\n fi\nelse\n # open w/t --args doesn't work:\n # open $SRCROOT/../../packager/launchPackager.command --args 111 222 || echo \"Can't start packager automatically\"\n osascript -e 'tell app \"Terminal\"\n do script \"'$SRCROOT'/../../packager/launchPackager.command --origin='${ORIGIN}' --port='${PORT}'\"\n end tell' || echo \"Can't start packager automatically\"\nfi";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This script is very long, can you extract it to a separate file and call that file from here?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@frantic Sure, can do. What's a good place to place that shell script? This one?: ./scripts.

@frantic
Copy link
Contributor

frantic commented Jun 15, 2015

Good work, thank you! But I feel like we should probably do the other way around - have React target be pure and ReactWithPackager do what React target does now. @nicklockwood / @tadeuzagallo - do you think my suggestion makes sence?

@ide
Copy link
Contributor

ide commented Jun 15, 2015

@frantic fwiw I agree with that structure, and would take it a step further by skipping ReactWithPackager and just having SampleApp, UIExplorer, TicTacToe, etc... call the packager from their own pbxproj files.

@bparadie
Copy link
Author

@frantic @ide Thanks for the feedback. This is one of my weekend projects, please expect some delays etc.
Just to confirm: You suggest switching the default so Info.plist would be supported by the React target and only the ReactWithPackager would launch the packager, correct?

Now, you guys realize that that will break modified old projects. The react-native Get Started section says:

Quick start 
- npm install -g react-native-cli
- react-native init AwesomeProject

All those old AwesomeProjects will be broken if the React target stops launching the packager. Are you ok with that? Can you just add a 'Breaking Changes' section to the next release and we all move on with our lives?

command: 'origin',
default: 'http://localhost',
type: 'string',
}, {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fyi "origin" (as in specs like CORS) includes the port number

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ide I wanted to model it after HTML's location.origin. But you are right, origin includes the port number. Not sure whether hostname would be a better choice, because it doesn't include the protocol part. Is there a better name than origin? I went through the HTML location properties. But nothing seems to fit...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we could split up protocol and hostname since most of the time (for development) the protocol is http and only the hostname needs to change.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ide What I am hearing you say is that we should model everything after HTML location and replace origin with hostname and protocol. Is that what you are proposing? If so: I like it!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes! protocol, hostname, and port as three separately configurable fields. Could even use Node's url.format() to construct the complete origin string if that helps.

@bparadie
Copy link
Author

Ok, I've made the following changes:

  • replaced 'origin' with 'protocol' + 'hostname' as suggested by @ide
  • moved the debug URL creation code to its own utility function as suggested by @frantic
  • moved launch mechanics out to launchPackager.command as suggested by @frantic
  • removed launch script from React project and added launch scripts to examples as suggested by @ide

But:

These are the custom port setting for each example:

Port Example
8081 UIExplorer
8087 SampleApp
8088 2048
8089 Movies
8090 TicTacToe

Breaking changes: required/optional changes.

If you have an old project and update your react-native module to this version then your old project will not launch the packager, because I removed the launch script from the React project.

Here are the changes that are required/optional...

REQUIRED: Add a launch script

Add a run script to your project with this line

$SRCROOT/../../packager/launchPackager.command ${INFOPLIST_FILE}
OPTIONAL: Use RCTWebSocketExecutorURL

Use RCTWebSocketExecutorURL from RCTUtils.h for creating your jsCodeLocation in AppDelegate.m, i.e.

jsCodeLocation = RCTWebSocketExecutorURL(@"/Examples/SampleApp/index.ios.bundle");
OPTIONAL: Add a RCTWebSocketExecutor dictionary

Add a RCTWebSocketExecutor dictionary for custom settings to your Info.plist, i.e.
screen shot 2015-06-21 at 1 57 36 pm

Please let me know if this looks good to you.
If so I'll squash/rebase my PR.
Thx!

@bparadie
Copy link
Author

Hmm, Travis CI build failed. It looks like I need to add the launch scripts to every test targets. Give me a minute!

@bparadie
Copy link
Author

One remaining problem is that package.json runs packager.sh for the scripts/start and bin/react-native-start those will always launch the packager with the default settings, that is, port=8081.

@bparadie
Copy link
Author

@frantic I am a little bit puzzled why Travis CI is failing.

2015-06-21 22:27:29.662 [info][tid:com.facebook.React.JavaScript] "Running application "AppEventsTest" with appParams: {"rootTag":1,"initialProps":{}}. __DEV__ === true, development-level warning are ON, performance optimizations are OFF"
2015-06-21 22:27:29.672 [error][tid:com.facebook.React.JavaScript] "Error: Invariant Violation: Application AppEventsTest has not been registered. This is either due to a require() error during initialization or failure to call AppRegistry.registerComponent.
 stack: 
  runApplication          IntegrationTestsA…:36107
  jsCall                  IntegrationTestsA…:7411
  _callFunction           IntegrationTestsA…:7679
  <unknown>               IntegrationTestsA…:7708
  <unknown>               IntegrationTestsA…:7702
  perform                 IntegrationTestsA…:6198
  batchedUpdates          IntegrationTestsA…:14132
  batchedUpdates          IntegrationTestsA…:4741
  <unknown>               IntegrationTestsA…:7701
  applyWithErrorReporter  IntegrationTestsA…:7446
  guardReturn             IntegrationTestsA…:7468
  processBatch            IntegrationTestsA…:7700
 URL: http://localhost:8081/Examples/UIExplorer/UIExplorerIntegrationTests/js/IntegrationTestsApp.includeRequire.runModule.bundle?dev=true
 line: 1762
 message: Invariant Violation: Application AppEventsTest has not been registered. This is either due to a require() error during initialization or failure to call AppRegistry.registerComponent."

I even removed my workaround for #1654 . But that didn't help either. Would you know what's going on here? Thanks!

@bparadie
Copy link
Author

I can now at least reproduce the problem locally w/t rm -rf node_modules && npm install && ./scripts/objc-test.sh... I had to nuke the node_modules folder first, though. But I am getting the same error with the master branch. Something is not right...

@bparadie
Copy link
Author

Ok, I found the problem (don't ask how I found it): react-native's package.json requires version 5.4.3 for the babel node nodule. Unfortunately babel's package.json sloppily accepts ^5.4.3 for babel-core. Now, if you start with a fresh clone (as Travis CI does) you'll end up with babel 5.4.3 using babel-core 5.6.2 (which is the latest babel-core version). Here is the problem: babel-core 5.6.2 will break ./scripts/objc-test.sh tests. The version that works is babel-core 5.5.6.

For that reason this PR contains this workaround. In package.json I explicitly request babel-core 5.5.6:

    "babel": "5.4.3",
    "babel-core": "5.5.6",

Would somebody please figure out why babel-core 5.6.2 breaks the build loop?

@bparadie
Copy link
Author

Almost there:

screen shot 2015-06-21 at 8 50 24 pm

The last remaining build loop error is: flow server is busy:

Flow server launched for /private/tmp/react-native-x3yOQW0y/EndToEndTest
Spawned flow server (child pid=2838)
Logs will go to /var/folders/vy/rcv48w3j4w79llzf_x6qnvw40000gn/T/flow/zSprivatezStmpzSreact-native-x3yOQW0yzSEndToEndTest.log
The flow server will be ready in a moment.
Error: flow server is busy
Error: flow server is busy
Error: flow server is busy
No errors!
[Info] Loading settings for scheme 'EndToEndTest' ...

That's not really my problem, is it?

@frantic
Copy link
Contributor

frantic commented Jun 22, 2015

flow server is busy is just a warning, after that it says No errors and continues the build, so that's not the reason for the failure. This is:

/Users/travis/Library/Developer/Xcode/DerivedData/EndToEndTest-bmjlkbqwxoavxthdezsighobnyjh/Build/Intermediates/EndToEndTest.build/Debug-iphonesimulator/EndToEndTest.build/Script-4CED847C1B3756CA00715E21.sh: line 2: /tmp/react-native-x3yOQW0y/EndToEndTest/../../packager/launchPackager.command: No such file or directory

vjeux and others added 15 commits September 16, 2015 14:50
Summary: I can't find anywhere these are being used by the bridge / native
views anymore. I don't think they work anymore. ART has a similar
API but uses a different code path.

We might as well clean this up. Makes it easier to reason about.

@​public

Reviewed By: @vjeux

Differential Revision: D2445353
Summary: @​public

RCTNetworking currently relies on network responses to include an accurate text encoding, otherwise it is unable to convert the response data to text unless it's encoded as UTF8.

See: facebook#1780 (comment) for details.

This diff makes use of a new feature in iOS8 to detect the encoding of the text authomatically

Reviewed By: @sahrens

Differential Revision: D2443446
Jest 0.5.2 ships with a fix for bound functions, which RN exercises. And with this Travis change, the automated tests will install Node 4.x with nvm before running.

Test Plan:`nvm use 4 && npm i && npm test`
See if Travis tests pass.
Summary: beeper node modules has a `return` statement outside of a function which doesn't parse. To fix it, we mock it. Also, setupEnvPolyfills is no longer being used.
Closes facebook#2770

Reviewed By: @​svcscm

Differential Revision: D2448882

Pulled By: @vjeux
@jsierles
Copy link
Contributor

Just to add my 2c here. This issue is important because it stops developers from getting on board as quickly as possible with debugging from devices. We still have to manually update RCTWebSocketManager.m, and these changes are overwritten when updating React Native. Now that hot reloading is a reality in React Native projects, it's even more important.

@bparadie
Copy link
Author

Time is up. I am closing this PR.

@bparadie bparadie closed this Sep 22, 2015
@jsierles
Copy link
Contributor

Hmm, too bad on this one. Given android is out now, maybe it's time to look at a single cross platform solution that doesn't depend on plist files or anything platform-specific. A global config file - maybe package.json?

@PaulBGD
Copy link

PaulBGD commented Oct 9, 2015

Sad, this is something that would be really useful.

@qimingweng
Copy link

I've posted this on product pains so it would be great if you could upvote it there and show the react-native team that this is an important feature https://productpains.com/post/react-native/allow-packager-port-to-be-configurable-change-from-8081/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed.
Projects
None yet
Development

Successfully merging this pull request may close these issues.