gradle-node-plugin
gradle-node-plugin copied to clipboard
Add easy way to use gradle-managed node / npm binaries outside the gradle build.
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:
- 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 thenode {}
closure). - Delegate the management of node binaries to a tool that already does that well (https://github.com/creationix/nvm)
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.
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.
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.
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 likenodeWrapper
. 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.
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.
:+1: Yes, both options can exist and the NVM stuff can follow later.
Just a heads up, I'll be looking at implementing this pretty soon.
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 :-)
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 thenodew
script - fixed
NPM_HOME
which was always pointing toNODE_HOME
- fixed
PATH
to include thebin
directory ofNODE_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
)
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
fromGRADLE_USER_HOME
(which is~/.gradle
by default) instead ofDIR
. 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. Thetypeset -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!
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
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()
}