gradle-node-plugin icon indicating copy to clipboard operation
gradle-node-plugin copied to clipboard

Add easy way to use gradle-managed node / npm binaries outside the gradle build.

Open dougborg opened this issue 10 years ago • 12 comments

First of all, thanks so much for this plugin. It has helped me greatly in the past week.

One thing that seems to be a bit of a pain for developers used to using node / npm tasks directly is that it is hard to invoke the same versions of node / npm used in the gradle build outside of gradle.

There are probably a few different ways to solve this, but I thought these two were worth consideration:

  1. Have the nodeSetup task create some links / shell scripts in the root of the project that can tie back to the appropriate node binaries in ~/.gradle/nodejs (or where ever they have that configured in the node {} closure).
  2. Delegate the management of node binaries to a tool that already does that well (https://github.com/creationix/nvm)

dougborg avatar Sep 26 '14 22:09 dougborg

I have also found that it's a pain when using multiple node version both inside and outside of gradle. Maybe the plugin could have some configuration that points to node binaries managed by NVM (as you suggest in 2)).

Will look into this and see what would be the better solution.

Thanks.

srs avatar Sep 27 '14 22:09 srs

My first thought about solving this problem was option 1 as it seemed pretty easy, but I really think option 2 has more potential. I could see adding an optional useNVM property (which would default to false to maintain backwards compatibility) to the node closure that would ensure NVM was set up on the machine and then delegate to NVM to set up the node version specified.

dougborg avatar Sep 29 '14 16:09 dougborg

I took a really quick and dirty first shot at a simple "node wrapper" script to use the node environment set up by Gradle. I still like idea 2 better, but this was pretty easy to set up. I am using it to work around the issue "for now" and provide a bit of convenience while we figure out a better long-term solution. I put the following in a script named nodew at the root of the project alongside gradlew:

#!/usr/bin/env bash

platform=$(uname -s | tr '[:upper:]' '[:lower:]')
#arch=$(uname -m | tr '[:upper:]' '[:lower:]') # ignoring this for now and using a wildcard expansion

# All of these may be overridden by the calling environment if needed.
NODE_VERSION=${NODE_VERSION:-0.10.32}
NODE_HOME=${NODE_HOME:-${HOME}/.gradle/nodejs/node-v${NODE_VERSION}-${platform}*}
NPM_HOME=${NODE_HOME:-${NODE_HOME}/lib/node_modules/npm/bin/}
NODE_MODULES_HOME=${NODE_MODULES_HOME:-./node_modules/.bin}

PATH="${NODE_MODULES_HOME}:${NPM_HOME}:${NODE_HOME}:${PATH}"

"${@}"

Now I can do stuff like:

douglas.borg@machine:project$ ./nodew npm --version
1.4.28
douglas.borg@machine:project$ ./nodew node --version
v0.10.32
douglas.borg@machine:project$ ./nodew grunt --version
grunt-cli v0.1.13
grunt v0.4.5

The next step to make this idea a little better would be to auto-generate this wrapper script similar to gradlew and update / substitute the variables from settings within the gradle build. Maybe call the task something like nodeWrapper. It may not be worth it to pursue this route further in favor of using something like NVM, however.

dougborg avatar Sep 30 '14 17:09 dougborg

Looks great. A nodeWrapper task would be cool. But, need to support windows too. But, happy to apply a pull request from you if you have something that can be used by others.

// srs

Den 30. sep. 2014 kl. 19.52 skrev Doug Borg [email protected]:

I took a really quick and dirty first shot at a simple "node wrapper" script to use the node environment set up by Gradle. I still like idea 2 better, but this was pretty easy to set up. I am using it to work around the issue "for now" and provide a bit of convenience while we figure out a better long-term solution. I put the following in a script named nodew at the root of the project alongside build.gradle:

#!/usr/bin/env bash

platform=$(uname -s | tr '[:upper:]' '[:lower:]') #arch=$(uname -m | tr '[:upper:]' '[:lower:]')

NODE_VERSION=${NODE_VERSION:-0.10.32} NODE_HOME=${NODE_HOME:-${HOME}/.gradle/nodejs/node-v${NODE_VERSION}-${platform}*} NPM_HOME=${NODE_HOME:-${NODE_HOME}/lib/node_modules/npm/bin/} NODE_MODULES_HOME="./node_modules/.bin"

PATH="${NODE_MODULES_HOME}:${NPM_HOME}:${NODE_HOME}:${PATH}"

"${@}" Now I can do stuff like:

douglas.borg@machine:project$ ./nodew npm --version 1.4.28 douglas.borg@machine:project$ ./nodew node --version v0.10.32 douglas.borg@machine:project$ ./nodew grunt --version grunt-cli v0.1.13 grunt v0.4.5 ``

The next step to make this idea a little better would be to auto-generate this wrapper script similar to gradlew and update / substitute the variables from settings within the gradle build. Maybe call the task something like nodeWrapper. It may not be worth it to pursue this route further in favor of using something like NVM, however. — Reply to this email directly or view it on GitHub.

srs avatar Sep 30 '14 18:09 srs

Yep, a nodew.bat script which does something similar would be pretty easy. The more I think about it, the nodeWrapper is probably worth doing. Adding support for NVM-managed node installations could still be added later as a separate issue.

dougborg avatar Sep 30 '14 18:09 dougborg

:+1: Yes, both options can exist and the NVM stuff can follow later.

srs avatar Sep 30 '14 20:09 srs

Just a heads up, I'll be looking at implementing this pretty soon.

dougborg avatar Nov 10 '14 22:11 dougborg

Nice. I think I will release a new version soon (tomorrow), but I will release often so it's no rush. I'm really glad someone has the time to do this stuff :-)

srs avatar Nov 11 '14 21:11 srs

Some updates to the nodew wrapper script (thanks @dougborg):

#!/usr/bin/env bash
# https://github.com/srs/gradle-node-plugin/issues/24

DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
# This should match the "workDir" setting in build.gradle
NODEJS=$DIR/build/gradle/nodejs

platform=$(uname -s | tr '[:upper:]' '[:lower:]')

typeset -A arches=([x86_64]=x64 [x86]=x86) # not sure about the x86
arch=$(uname -m | tr '[:upper:]' '[:lower:]')
nodearch=${arches[$arch]}

# All of these may be overridden by the calling environment if needed.
NODE_VERSION=${NODE_VERSION:-0.12.2}
NODE_HOME="${NODE_HOME:-$NODEJS/node-v${NODE_VERSION}-${platform}-${nodearch}}"
NPM_HOME="${NPM_HOME:-${NODE_HOME}/lib/node_modules/npm}"
NODE_MODULES_HOME="${NODE_MODULES_HOME:-$DIR/node_modules}"

PATH="${NODE_MODULES_HOME}/.bin:${NPM_HOME}/bin:${NODE_HOME}/bin:${PATH}"

exec "${@}"

Modifications:

  • added an associative array lookup for the platform (the wildcard wasn't working for me)
  • modified NODE_HOME to point to the project directory by figuring out the directory of the nodew script
  • fixed NPM_HOME which was always pointing to NODE_HOME
  • fixed PATH to include the bin directory of NODE_HOME
  • made NODE_MODULES_HOME absolute
  • added quoting in case the project directory contains spaces (not tested)
  • added an exec so that the called program replaces the nodew script process rather than creating a child process of the script
  • made the home dirs consistent (always point to the directory above bin or .bin)

rocketraman avatar Apr 04 '15 17:04 rocketraman

I managed to get @rocketraman's script working on my machine with some minor tweaks. Here's my take on this script:

#!/usr/bin/env bash
# https://github.com/srs/gradle-node-plugin/issues/24

GRADLE_USER_HOME="${GRADLE_USER_HOME:-${HOME}/.gradle}"
DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
# This should match the "workDir" setting in build.gradle
NODEJS=$GRADLE_USER_HOME/nodejs

platform=$(uname -s | tr '[:upper:]' '[:lower:]')

arch=$(uname -m | tr '[:upper:]' '[:lower:]')
case $arch in
x86_64)
    nodearch=x64
    ;;
x86)
    nodearch=x86
    ;;
esac

# All of these may be overridden by the calling environment if needed.
NODE_VERSION=${NODE_VERSION:-0.12.2}
NODE_HOME="${NODE_HOME:-$NODEJS/node-v${NODE_VERSION}-${platform}-${nodearch}}"
NPM_HOME="${NPM_HOME:-${NODE_HOME}/lib/node_modules/npm}"
NODE_MODULES_HOME="${NODE_MODULES_HOME:-$DIR/node_modules}"

PATH="${NODE_MODULES_HOME}/.bin:${NPM_HOME}/bin:${NODE_HOME}/bin:${PATH}"

exec "${@}"

Modifications:

  • Now computes NODEJS from GRADLE_USER_HOME (which is ~/.gradle by default) instead of DIR. I don't know why my machine is different, but $DIR/build/gradle/nodejs didn't exist for me.
  • Replaced the arches variable with a case statement. The typeset -A switch appears to be an addition in Bash 4.x and breaks on Bash 3.x. Unfortunately Bash 3.x is the default version for OSX Mavericks and Yosemite so -A will break the script for a lot of users
    • not sure what the default version of Bash is on El Capitan, but knowing Apple I wouldn't be surprised if they haven't updated it.

Bash scripting isn't my forte, so apologies if I did anything weird/uncouth. Thanks all for putting this together!

bkputnam avatar Oct 13 '15 23:10 bkputnam

I was looking for windows wrapper scripts here and I can't find anything.

If somebody needs also windows wrapper. Try my scripts (easy but working):

nodew.cmd (windows)

@echo off
setlocal
set NODE_EXE=""
for /r %%x in (*node.exe) do set NODE_EXE=%%x
set NODE_HOME=%NODE_EXE:node.exe=%
set PATH=%NODE_HOME%;%PATH%
if not exist %NODE_EXE% (
  echo Node not found! Run gradle build first!
) else (
  %NODE_EXE% %*
)
@echo on

yarn.cmd (windows)

@echo off
setlocal
set YARN_SCRIPT=%~dp0build\yarn\node_modules\yarn\bin\yarn.js
if not exist %YARN_SCRIPT% (
  echo Node not found! Run gradle build first!
) else (
  nodew.cmd %YARN_SCRIPT% %*
)
@echo on

nodew (linux)

@echo off
setlocal
set YARN_SCRIPT=%~dp0build\yarn\node_modules\yarn\bin\yarn.js
if not exist %YARN_SCRIPT% (
  echo Node not found! Run gradle build first!
) else (
  nodew.cmd %YARN_SCRIPT% %*
)
@echo on

yarnw (linux)

#!/usr/bin/env bash

YARN_SCRIPT="./build/yarn/node_modules/yarn/bin/yarn.js"

if [ ! -f $YARN_SCRIPT ]; then
    echo "Yarn not found! Run gradle build first!"
else
    ./nodew $YARN_SCRIPT "$@"
fi

kucharzyk avatar Jan 09 '17 18:01 kucharzyk

Instead of having to determine the arch and using it to get the path to node, here's a script that uses this plugin to get the node path:

#!/usr/bin/env bash
# https://github.com/srs/gradle-node-plugin/issues/24
set -Eeuo pipefail

DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
GRADLEW="$DIR/gradlew"
# This should match the "workDir" setting in build.gradle
PROJECTDIR="${DIR}/"

NODE_HOME="$("$GRADLEW" -q -p "$PROJECTDIR" nodeDir | tail -n1)/bin"
PATH="${NODE_HOME}:${PATH}"
exec "${NODE_HOME}/node" "$@"

A prerequisite for this script is to add this task to build.gradle:

task nodeDir {
	dependsOn nodeSetup
	println nodeSetup.nodeDir.get()
}

candrews avatar Oct 27 '22 14:10 candrews