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]AppDataRoamingnpm, 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_modulesgrunt* 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]AppDataRoamingnpm", 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.


    Instead of using the global option for npm , you should be using symbolic links on your modules, to achieve similar results.

    Global npm installs are intended only as a convenience for command-line utilities such as jshint , or grunt-cli .


    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 module_a@0.1.0 which depends on module_b@0.2.0. If you also depend on module_b@0.1.0, 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.


    I use fenestrate to solve this sort of issues on Windows. Even if it works with Git, if you use Git integration from Visual Studio within Team Explorer it will still crash if long file paths are in your node_modules folder - even if you're not adding that folder to source control.

    Usually Grunt and Bower dependency structure causes this.

  • First thing I would recommend is to run npm dedupe on your packages. What this does, is to scan your already installed packages and see if some dependencies are duplicated. If found on a higher level, it will remove the deeply tested ones.

  • Secondly, if dedupe does not resolve the issue, if you can find the dependency that's so deeply nested that's causing this issue, try and install it in your solution directly, and run dedupe again.

  • If there are more package dependencies that cause this, fenestrate will solve the issue. Plus it's really cool because you can hook it to you npm install and it will always run after a new package is installed. Also, it's fully reversable.

  • I hope this helps.

    链接地址: http://www.djcxy.com/p/65826.html

    上一篇: 如何在node.js上调试“错误:产生ENOENT”?

    下一篇: 如何使Grunt Deploy使用全局NPM模块而不是本地模块