facebook / react-native

A framework for building native applications using React
https://reactnative.dev
MIT License
117.04k stars 24.07k forks source link

NODE_BINARY in .xcode.env not working #35657

Open MicahDavid opened 1 year ago

MicahDavid commented 1 year ago

Description

I would like to use the .xcode.env to set my node version. My .xcode.env looks like:

export NODE_BINARY=$(command -v node)

When I execute this command in a terminal window, it returns the proper node version. I've tested, and the only way I can set the node version is using Build Phases -> Bunde React Native Code and Images -> and exporting NODE_BINARY in the shell commands there to the absolute path:

export NODE_BINARY=/Users/myuser/.nvm/versions/node/v14.18.1/bin/node

Can anyone suggest why NODE_BINARY is not being set through the .xcode.env file? Do I have to take any extra steps to use this during archive?

Version

0.70.4

Output of npx react-native info

System: OS: macOS 12.6 CPU: (12) x64 Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz Memory: 23.84 MB / 32.00 GB Shell: 3.2.57 - /bin/bash Binaries: Node: 14.18.1 - ~/.nvm/versions/node/v14.18.1/bin/node Yarn: 1.22.18 - ~/.nvm/versions/node/v14.18.1/bin/yarn npm: 6.14.15 - ~/.nvm/versions/node/v14.18.1/bin/npm Watchman: 2022.03.21.00 - /usr/local/bin/watchman Managers: CocoaPods: 1.11.3 - /Users/micahsklut/.rbenv/shims/pod SDKs: iOS SDK: Platforms: DriverKit 22.2, iOS 16.2, macOS 13.1, tvOS 16.1, watchOS 9.1 Android SDK: API Levels: 29, 30, 31 Build Tools: 29.0.2, 30.0.2, 30.0.3, 31.0.0 System Images: android-29 | Intel x86 Atom_64, android-29 | Google APIs Intel x86 Atom_64, android-30 | Google APIs Intel x86 Atom Android NDK: Not Found IDEs: Android Studio: 2021.3 AI-213.7172.25.2113.9123335 Xcode: 14.2/14C18 - /usr/bin/xcodebuild Languages: Java: 1.8.0_292 - /usr/bin/javac npmPackages: @react-native-community/cli: Not Found react: 18.1.0 => 18.1.0 react-native: ^0.70.4 => 0.70.6 react-native-macos: Not Found npmGlobalPackages: react-native: Not Found

Steps to reproduce

Run Archive. The system node is being used, unless I set it as explained above.

Snack, code example, screenshot, or link to a repository

Screen Shot 2022-12-15 at 6 29 09 PM
codesalley commented 1 year ago

in my case it was NVM. Either let nvm go or reconfigure it In your build phases scripts

if [[ -s "$HOME/.nvm/nvm.sh" ]]; then
. "$HOME/.nvm/nvm.sh"
elif [[ -x "$(command -v brew)" && -s "$(brew --prefix nvm)/nvm.sh" ]]; then
. "$(brew --prefix nvm)/nvm.sh"
fi
jaimeagudo commented 1 year ago

In my case I had to add export NODE_BINARY=$(command -v node)\n to the PODS build phases script tail, .xcode.env seemed to make no difference

shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\nexport NODE_BINARY=$(command -v node)\n";

Running react-native": "0.69.7" on arm64

jaimeagudo commented 1 year ago

Apparently this is caused by nvm A less invasive workaround (that breaks nvm):

ln -s $(which node) /usr/local/bin/node

djMax commented 1 year ago

nvm is common enough that I would suggest this should work out of the box.

badsyntax commented 11 months ago

Loading nvm from within .xcode.env seems to resolve this for me:

export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm

export NODE_BINARY=$(command -v node)
lucianomlima commented 9 months ago

In my Xcode build logs show me this error:

../node_modules/react-native/scripts/xcode/with-environment.sh: line 35: node: command not found

But after errors, show "Now using node v20.7.0." and this happen too with Upload Debug Symbols to Sentry build phase. I'm using Xcode 14.3.1 and RN v0.69.12. Everything works on terminal (iTerm + zsh)

cipolleschi commented 9 months ago

The problem is that Xcode scripts works in a different environment than a regular terminal/ Xcode also overrides some basic ENV var that can shadow and mask other variables we might set.

If you don't have node in the default PATHs, like /usr/local/bin, for example, Xcode is not able to find it. A simple solution could be to create a symlink to node in /usr/local/bin:

sudo ln -s $(command -v node) /usr/local/bin/node

We are investigating better way to handle this, but we haven't found a robust approach yet, unfortunately. :(

lucianomlima commented 9 months ago

The problem is that Xcode scripts works in a different environment than a regular terminal/ Xcode also overrides some basic ENV var that can shadow and mask other variables we might set.

If you don't have node in the default PATHs, like /usr/local/bin, for example, Xcode is not able to find it. A simple solution could be to create a symlink to node in /usr/local/bin:

sudo ln -s $(command -v node) /usr/local/bin/node

We are investigating better way to handle this, but we haven't found a robust approach yet, unfortunately. :(

In my case, Xcode can find node (using the ,export NVM_DIR=path/to/.nvm approach) but can't find command, that is a built-in shell library. Sounds weird.

cipolleschi commented 8 months ago

@lucianomlima yeah, that's definitely very weird. Can you try add a script phase after building just calling which command? :/

lucianomlima commented 8 months ago

which command shows me : command: shell built-in command but I do some tests and I realize that nothing going work with Xcode build and .xcode.env. Now my .xcode.env is:

export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" --no-use

nvm use default # I need to put this because when use nvm current returns none

export NODE_BINARY=$NVM_DIR/versions/node/v20.7.0/bin/node

echo $NVM_DIR # Prints /Users/luciano.lima/.nvm
echo $NODE_BINARY # Prints /Users/luciano.lima/.nvm/versions/node/v20.7.0/bin/node

And, on Xcode log, I have these messages:

Now using node v20.7.0 (npm v10.1.0)
/Users/luciano.lima/.nvm # echo $NVM_DIR
/Users/luciano.lima/.nvm/versions/node/v20.7.0/bin/node # echo $NODE_BINARY
Node found at: /Users/luciano.lima/.nvm/versions/node/v20.7.0/bin/node

And some time later:

+ type node
+ echo 'error: node not found! Modules won'\''t be collected.' 'Please export NODE_BINARY in '\''Build Phase'\'' - '\''Bundle React Native code and images'\''' 'to an absolute path of your node binary. Check your node path by '\''which node'\''.'
error: node not found! Modules won't be collected. Please export NODE_BINARY in 'Build Phase' - 'Bundle React Native code and images' to an absolute path of your node binary. Check your node path by 'which node'.
+ exit 0
Command PhaseScriptExecution emitted errors but did not return a nonzero exit code to indicate failure

So, even using an absolute path to NODE_BINARY, build script phase fails.

The only way that make things works is with symlink like @cipolleschi suggests. Now my .xcode.env have only this:

export NODE_BINARY=/usr/local/bin/node

And now finally works. 🤷

cipolleschi commented 8 months ago

From which script phase the message:

+ type node
+ echo 'error: node not found! Modules won'\''t be collected.' 'Please export NODE_BINARY in '\''Build Phase'\'' - '\''Bundle React Native code and images'\''' 'to an absolute path of your node binary. Check your node path by '\''which node'\''.'
error: node not found! Modules won't be collected. Please export NODE_BINARY in 'Build Phase' - 'Bundle React Native code and images' to an absolute path of your node binary. Check your node path by 'which node'.
+ exit 0
Command PhaseScriptExecution emitted errors but did not return a nonzero exit code to indicate failure

arrives? I have no memory of any of our scripts emitting that message! Could it be a third party library? The problem is likely that that script is not using loading the with-environment.sh script that is responsible to load the .xcode.env. Without loading that, it is expected not to find the ENV vars.

lucianomlima commented 8 months ago

It's from @sentry/react-native and my script build phase is

export SENTRY_PROPERTIES=sentry.properties
export EXTRA_PACKAGER_ARGS="--sourcemap-output $DERIVED_FILE_DIR/main.jsbundle.map"
set -e

WITH_ENVIRONMENT="../node_modules/react-native/scripts/xcode/with-environment.sh"
REACT_NATIVE_XCODE="../node_modules/react-native/scripts/react-native-xcode.sh"
SENTRY_CLI="../node_modules/@sentry/cli/bin/sentry-cli"

/bin/sh -c "$WITH_ENVIRONMENT \"$SENTRY_CLI react-native xcode $REACT_NATIVE_XCODE\""
/bin/sh ../node_modules/@sentry/react-native/scripts/collect-modules.sh

Maybe the last line is where the problem is? I'll try to add WITH_ENVIRONMENT to it.

adamjw3 commented 8 months ago

i think i'm getting a similar issue

Node found at: /opt/homebrew/bin/node
/Users/adamwright/Documents/Development/AB3MobileUpgrade/AB3MobileUpgrade/ios/Pods/../../node_modules/react-native/React/FBReactNativeSpec/../../scripts/react_native_pods_utils/script_phases.sh: line 34: /opt/homebrew/bin/node: No such file or directory
Command PhaseScriptExecution failed with a nonzero exit code

My .xcode.env is

# This `.xcode.env` file is versioned and is used to source the environment
# used when running script phases inside Xcode.
# To customize your local environment, you can create an `.xcode.env.local`
# file that is not versioned.
# NODE_BINARY variable contains the PATH to the node executable.
#
# Customize the NODE_BINARY variable here.
# For example, to use nvm with brew, add the following line
# . "$(brew --prefix nvm)/nvm.sh" --no-use
export NODE_BINARY=$(command -v node)export NODE_BINARY=/opt/homebrew/bin/node

but my node path when running which node is -/usr/local/bin/node

How can i fix this?

cipolleschi commented 8 months ago

Hey @adamjw3! Your Xcode env has 2 export NODE_BINARY on the same line. That would not work.

You should have either

export NODE_BINARY=$(command -v node)

Or

export NODE_BINARY=/usr/local/bin/node
adamjw3 commented 8 months ago

@cipolleschi thanks, they are on two lines in the file and it was auto generated like that! i commented out

export NODE_BINARY=$(command -v node)

and updated the other with my node path

export NODE_BINARY=/usr/local/bin/node

project now builds

Thanks

jswangtao commented 8 months ago

I am using RN version 0.72.3, which can run, package and flash back. I feel that it is the reason for switching to the default version with NVM. I have added a script here, and switching to 20 or above is normal. It should be 18, but our team is using 20, so switching to 20 is necessary image

export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm

nvm use 20

export NODE_BINARY=node
../node_modules/react-native/scripts/react-native-xcode.sh
banane commented 7 months ago

What worked for us was to get the NVM directory: export NODE_BINARY=$HOME/.nvm/nodes/versions/v18.0.0/bin/node

We have NVM setup in our README so could reasonably expect local devs to have that set, and doesn't to explicitly state the node version. Then, it runs same locally and on CircleCi.

aTreey commented 5 months ago

The problem is that Xcode scripts works in a different environment than a regular terminal/ Xcode also overrides some basic ENV var that can shadow and mask other variables we might set.

If you don't have node in the default PATHs, like /usr/local/bin, for example, Xcode is not able to find it. A simple solution could be to create a symlink to node in /usr/local/bin:

sudo ln -s $(command -v node) /usr/local/bin/node

We are investigating better way to handle this, but we haven't found a robust approach yet, unfortunately. :(

This analysis is correct. I solved this problem by completely uninstalling node and then downloading the .pkg installation from the node.js ,because the installation location of the installation package is /usr/local/bin/node by default.

gabriellend commented 4 months ago

Just adding more info in case it's helpful. I'm using Homebrew and this is happening too, right after downgrading from node 20 to node 18. Not using Expo, RN 0.70.6. Here are some of the xcode logs when the error occurs:

...Desktop/Inventory/ios/Pods/../../node_modules/react-native/React/FBReactNativeSpec/../../scripts/xcode/with-environment.sh: line 35: .xcode.env: command not found .../Desktop/Inventory/ios/Pods/../../node_modules/react-native/React/FBReactNativeSpec/../../scripts/xcode/with-environment.sh: line 35: node: command not found [Warning] You need to configure your node path in the environment. You can set it up quickly by running: echo 'export NODE_BINARY=' > .xcode.env in the ios folder. This is needed by React Native to work correctly. We fallback to the DEPRECATED behavior of finding . This will be REMOVED in a future version. You can read more about this here: https://reactnative.dev/docs/environment-setup#optional-configuring-your-environment [Error] Could not find node. It looks like that the .xcode.env or .xcode.env.local Command PhaseScriptExecution failed with a nonzero exit code

I have .xcode.env inside my ios folder with the line: export NODE_BINARY=$(command -v node). command -v node prints out the correct path(/opt/homebrew/opt/node@18/bin/node). Switching out $(command -v node) with that path works.

I get now that Xcode runs in a different environment that doesn't have access to variables that the terminal has, but it was working before I changed the node version, and that is all I changed, so it seems weird that it suddenly wouldn't work.

guikubivan commented 3 months ago

Note, this other issue seems to suggest the .xcode.env thing will fix it, so just referencing here that that solution does not work: https://github.com/facebook/react-native/issues/33695

moulie415 commented 3 months ago

This fixed the issue for me https://stackoverflow.com/a/66497247/6590549. I had a symlinked version of node that was node longer actually installed via nvm.

neuron-mobility-frontend commented 1 month ago

Apparently this is caused by nvm A less invasive workaround (that breaks nvm):

ln -s $(which node) /usr/local/bin/node

The problem is that Xcode scripts works in a different environment than a regular terminal/ Xcode also overrides some basic ENV var that can shadow and mask other variables we might set. If you don't have node in the default PATHs, like /usr/local/bin, for example, Xcode is not able to find it. A simple solution could be to create a symlink to node in /usr/local/bin:

sudo ln -s $(command -v node) /usr/local/bin/node

We are investigating better way to handle this, but we haven't found a robust approach yet, unfortunately. :(

This analysis is correct. I solved this problem by completely uninstalling node and then downloading the .pkg installation from the node.js ,because the installation location of the installation package is /usr/local/bin/node by default.

Thanks for good answer. The important thing is uninstalling unused node version.

vinnyA3 commented 1 month ago

I created an .xcode.env.local file and modified my NODE_BINARY path there -- local will override the default that you may have configured for the project in .xcode.env (just make sure not to commit your .xcode.env.local)

For context: I'm lazy-loading nvm, so I just made sure to load it up and set the correct path in my local file.

ArindamRayMukherjee commented 1 month ago

I just spent half a day debugging a strange problem. XCode seems to be exiting with error code 65 due to the autogenerated .xcode.env.local. On deleting that file the next xcode-build command works fine. Here's the sequence of events.

0) Everything working fine for my mobile app codebase for deployment to the local iOS simulator 1) Upgraded to RN 0.74.1 (don't know if this is related though) 2) Ran local deployment react-native run-ios to iOS simulator, everything works fine. 3) In the next run of react-native run-ios, xcode-build exits with an error code 65 . 4) I try cleaning the various generated dirs using these two yarn commands "cleanstall": "rm -fr node_modules ios/Podfile.lock ios/Pods ios/build ~/Library/Developer/Xcode/DerivedData && yarn install" and "run-ios": "cd ios && rm -f Podfile.lock && pod repo update && NO_FLIPPER=1 RCT_NEW_ARCH_ENABLED=1 pod install && cd .. && react-native run-ios --verbose", but problem persists. 4) Opening project in XCode and debugging it there shows it exits just after accessing .xcode.env.local which has this line export NODE_BINARY=/var/folders/_r/51ztwzn17fd1qzm2l87zjzz40000gn/T/yarn--1716631514203-0.5113628975765909/node. I think strange because .xcode.env has export NODE_BINARY=$(command -v node) and that just works fine to point out the right node binary. 5) I delete .xcode.env.local and do react-native run-ios again and things work fine again. 6) I find this thread and try to reproduce the sequence of events so I could add screenshots etc here, but 3 does NOT fail anymore!

Apologies for the long description, just trying to paint as detailed a picture so something clicks for someone who knows the picture deeper. This behaviour is worrisome because its an obscure problem that might revisit in a couple of months and burn another half day.

Are there any preventive measures I can take? For example I was thinking of making .xcode.env.local the same as .xcode.env so it also has export NODE_BINARY=$(command -v node) and committing that to the repo (so far these files were being mentioned in .gitignore )

vinnyA3 commented 1 month ago

@ArindamRayMukherjee Don't worry about .xcode.env.local, it's meant to override the project's configured node version in .xcode.env. Depending on how one manages node versions, it might be needed to override (see my previous comment above).

Don't commit it. First, double check that it's not already committed in the repo -- it maybe ignored by git now, but perhaps someone committed it by mistake before. If it in the repo, my recommendation is to open a PR to remove it.

ArindamRayMukherjee commented 1 month ago

@vinnyA3 Apologies, I had not succeeded in putting the question through properly. I've updated my comment above, may I request a second read through? I'm trying to understand why an autogenerated file .xcode.env.local causes XCode to exit with code 65. Moreover this happens sporadically, not always. One thing is for certain, after a Xcode error 65 happens, deleting .xcode.env.local causes the next build to work. See the man extract below for what the error means(quite generic as you can see). man_syscode_exit_exit_code_65 copy

Committing .xcode.env.local with same contents as .xcode.env so it also has export NODE_BINARY=$(command -v node) was meant to act as a possible preventive measure so other team mates do not face the same issue. It is quite hard to trace back from a code 65 exit that .xcode.env.local is the problem.

vinnyA3 commented 1 month ago

@ArindamRayMukherjee why the local file is causing that specific error, I'm not sure. There must be more info in the log view of xcode. I have had issues the bundle phase script failing, and the source was because of the default xcode env file -- maybe it's the same error? Not sure off top of my head.

That said, I did find out that, depending how the project is configured, pod install can auto-generate the file:
https://github.com/facebook/react-native/issues/43285

It's not clear to me why this file is autogenerated in the first place, but if you check that thread, there are solutions

ArindamRayMukherjee commented 1 month ago

@vinnyA3 Many thanks! Yes that thread exactly mentions this! And I've gone for the simple solution of removing the file in my yarn commands.

WilGatlin commented 4 weeks ago

On 0.71.17, we found the only way to solve this error was to temporarily delete .xcode.env. You are able to add it back after a successful build and the rebuild without issues.

betopompolo commented 3 days ago

I got the following setup on my local:

I did almost the same modifications as @lucianomlima (here) to my .xcode.env. Here's the complete file:

# This `.xcode.env` file is versioned and is used to source the environment
# used when running script phases inside Xcode.
# To customize your local environment, you can create an `.xcode.env.local`
# file that is not versioned.
# NODE_BINARY variable contains the PATH to the node executable.
#
# Customize the NODE_BINARY variable here.

# Usage with nvm
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
nvm use $(<../.nvmrc) # Considering that .xcode.env is at ios/ and .nvmrc is at project's root
export NODE_BINARY="$(command -v node)"

and it's working! 🎉