Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make Grunt Deploy use global NPM modules instead of local ones

First off, I'm very new to npm and grunt. We have a project that we are using Grunt to compile and produce the output files for. I am trying to setup our build server to use Grunt to produce the output files. We are using Windows with TFS source control, and due to it's 260 character path limit, we are not able to check the grunt-bower-task module into source control (as it alone uses 230 characters in its installed path).

When I run npm install from my project directory it works fine and installs the following required modules into the node_modules folder in my project directory:

  • grunt
  • grunt-bower-task
  • grunt-contrib-compass
  • grunt-contrib-connect
  • grunt-contrib-jshint
  • grunt-contrib-requirejs
  • grunt-contrib-watch

And then when I run grunt deploy from my project directory everything works as expected.

While I could simply make running npm install part of the build process, I prefer not to, as it takes a few minutes to download all of the files, and I don't want our builds to depend on an external web service being available.

I've seen that you can install modules either locally or globally, so I'm hoping to just be able to install the modules globally on the build server so that they do not need to be in the node_modules folder directly inside the project directory before running grunt deploy. I've ran npm install -g, as well as npm install -g [module] for each of the modules listed above, as well as npm install -g grunt-cli.

If I do npm prefix -g it shows me that the global module directory is C:\Users[My User]\AppData\Roaming\npm, and when I look in that directory's node_modules folder I do see all of the modules. However, when I run grunt deploy it complains with:

Fatal error: Unable to find local grunt

If I include just the *node_modules\grunt* directory, then I still get these errors:

Local Npm module "grunt-contrib-watch" not found. Is it installed?

Local Npm module "grunt-contrib-jshint" not found. Is it installed?

...

I've also tried using *grunt deploy --base "C:\Users[My User]\AppData\Roaming\npm", but it complains that it then cannot find other files, such as .jshintrc.

So is there a way that I can run grunt deploy and have it check the npm global prefix path for the modules, rather than looking in the project directory?

A hacky work around is to copy the modules manually during the build process to the local project directory, but I would like to avoid this if possible.

For reference, this is what my package.json file looks like:

{   "name": "MyProject",   "version": "0.0.1",   "scripts": {     "preinstall": "npm i -g grunt-cli bower"   },   "devDependencies": {     "grunt": "~0.4.1",     "grunt-contrib-compass": "~0.2.0",     "grunt-contrib-watch": "~0.4.4",     "grunt-contrib-jshint": "~0.6.0",     "grunt-contrib-requirejs": "~0.4.1",     "grunt-contrib-connect": "~0.3.0",     "grunt-bower-task": "~0.2.3"   } } 

Thanks.

like image 300
deadlydog Avatar asked Nov 05 '13 17:11

deadlydog


People also ask

How do I create a global npm package?

NPM installs global packages into /<User>/local/lib/node_modules folder. Apply -g in the install command to install package globally.

How do I install grunt locally to my project?

Installing grunt-cli locally js method to get started with a project ( npm install && npm test ) then install grunt-cli locally with npm install grunt-cli --save-dev. Then add a script to your package. json to run the associated grunt command: "scripts": { "test": "grunt test" } .

How do I install a specific version of grunt command line?

Installing a specific version If you need a specific version of Grunt or a Grunt plugin, run npm install grunt@VERSION --save-dev where VERSION is the version you need. This will install the specified version, adding it to your package.


1 Answers

Workaround: Explicitly list all transient dependencies in your own package.json.

Say, for example, that you depend on module_a, and that module_a depends on module_b. After npm install you'll have node_modules/module_a/node_modules/module_b/ because npm will install module_b local to module_a. However, if you add module_b as a direct dependency in your package.json (and the version specifiers match exactly), then npm will only install module_b once: at the top level.

This is because when modules are required, they start looking in the nearest node_modules directory and traverse upwards until the required module is found. So npm is able to save disk space by only installing the module at the lowest level at which the versions match.

So, revised example. You depend on [email protected] which depends on [email protected]. If you also depend on [email protected], you'll end up with module_b installed twice. (Version 0.1.0 will be installed at the top level, and 0.2.0 will be installed under module_a.) However, if you depend on v0.2.0 (using the exact version string in your package.json as module_a uses), then npm will notice it can use the same version of module_b. So it will only install module_b at the top level, and not under module_a.

Long story short: add whichever transient dependencies you have that have deep module trees directly to your own package.json and you'll end up with a more shallow node_modules tree.

like image 113
jasonkarns Avatar answered Sep 23 '22 17:09

jasonkarns