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

时间:2013-11-05 17:31:38

标签: node.js module npm gruntjs

首先,我是npm和grunt的新手。我们有一个项目,我们正在使用Grunt来编译和生成输出文件。我正在尝试设置我们的构建服务器以使用Grunt生成输出文件。我们正在使用带有TFS源代码控制的Windows,由于it's 260 character path limit,我们无法将grunt-bower-task模块检查为源代码控制(as it alone uses 230 characters in its installed path)。

当我从项目目录运行 npm install 时,它可以正常工作,并将以下必需的模块安装到项目目录的node_modules文件夹中:

  • 咕噜
  • 咕噜-亭子任务
  • 咕噜-的contrib罗盘
  • 咕噜-的contrib-连接
  • 咕噜-的contrib-jshint
  • 咕噜-的contrib-requirejs
  • 咕噜-的contrib手表

然后当我从项目目录中运行 grunt deploy 时,一切都按预期工作。

虽然我可以简单地运行 npm install 构建过程的一部分,但我不愿意,因为下载所有文件需要几分钟,而我不想要我们的构建依赖于可用的外部Web服务。

我已经看到了you can install modules either locally or globally,所以我希望能够在构建服务器上全局安装模块,这样它们就不需要直接在项目目录中的node_modules文件夹中。运行 grunt deploy 。我为上面列出的每个模块运行了 npm install -g ,以及 npm install -g [module] ,以及 npm install - g grunt-cli

如果我执行 npm prefix -g ,它会告诉我全局模块目录是 C:\ Users [我的用户] \ AppData \ Roaming \ npm ,以及何时我查看该目录的node_modules文件夹,我确实看到了所有模块。但是,当我运行 grunt deploy 时,它抱怨:

  

致命错误:无法找到当地的咕噜声

如果我只包含* node_modules \ grunt *目录,那么我仍然会收到以下错误:

  

找不到本地Npm模块“grunt-contrib-watch”。它安装了吗?

     

找不到本地Npm模块“grunt-contrib-jshint”。它安装了吗?

     

...

我也尝试过使用* grunt deploy --base“C:\ Users [我的用户] \ AppData \ Roaming \ npm”,但它抱怨说它找不到其他文件,例如.jshintrc。

那么有没有办法可以运行 grunt deploy 并让它检查模块的npm全局前缀路径,而不是查看项目目录?

一个黑客的工作是在构建过程中手动将模块复制到本地项目目录,但我想尽可能避免这种情况。

作为参考,这是我的 package.json 文件的样子:

{
  "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"
  }
}

感谢。

5 个答案:

答案 0 :(得分:16)

解决方法:在您自己的package.json中明确列出所有瞬态依赖项。

例如,假设你依赖于module_a,而module_a依赖于module_b。在npm install之后,您将拥有node_modules/module_a/node_modules/module_b/,因为npm会将module_b local安装到module_a。但是,如果在你的 package.json中添加module_b作为直接依赖(并且版本说明符完全匹配),那么npm将只安装module_b一次:在顶层。

这是因为当需要模块时,它们会开始查找最近的node_modules目录并向上遍历,直到找到所需的模块。所以npm只能通过在版本匹配的最低级别安装模块来节省磁盘空间。

所以,修改过的例子。您依赖于module_a@0.1.0,它取决于module_b@0.2.0。如果您还依赖module_b@0.1.0,那么最终会安装module_b两次。 (版本0.1.0将安装在顶层,0.2.0将安装在module_a下。)但是,如果您依赖于v0.2.0(使用package.json中的确切版本字符串作为module_a使用),那么npm会注意到它可以使用相同版本的module_b。所以它只会在顶级安装module_b,而在module_a下只安装

长话短说:将具有深层模块树的瞬态依赖项直接添加到您自己的package.json中,最终会得到一个更浅的node_modules树。

答案 1 :(得分:7)

您应该在模块上使用symbolic links,而不是使用npm的全局选项,以获得类似的结果。

全局npm次安装仅用于方便命令行实用程序,例如jshintgrunt-cli

答案 2 :(得分:4)

我使用fenestrate来解决Windows上的这类问题。 即使它适用于Git,如果你在团队资源管理器中使用Visual Studio中的Git集成,如果你的node_modules文件夹中有长文件路径,它仍会崩溃 - 即使你没有将该文件夹添加到源代码控制中。

通常Grunt和Bower依赖结构导致这种情况。

  1. 我建议首先在你的包裹上运行npm dedupe。这样做的目的是扫描已安装的软件包,看看是否有重复的依赖项。如果在更高级别找到它,它将删除经过深度测试的那些。

  2. 其次,如果重复数据删除无法解决问题,如果您可以找到导致此问题的深度嵌套的依赖项,请尝试直接在解决方案中安装它,然后再次运行重复数据删除。

    < / LI>
  3. 如果有更多的软件包依赖项导致此问题,fenestrate将解决此问题。此外,它非常酷,因为您可以将它挂钩到npm install,并且它将始终在安装新软件包后运行。此外,它是完全可逆的。

  4. 我希望这会有所帮助。

答案 3 :(得分:4)

我知道这个帖子已经过时了,但我终于找到了自己的个人答案,使用的是Mac,但我认为可以用PC来说/完成同样的事情。

跟进bevacqua的回答:

  

您应该在模块上使用符号链接,而不是使用npm的全局选项,以获得类似的结果。

     

全局npm安装仅用于方便命令行实用程序,例如jshint或grunt-cli。

我做了一些挖掘,可能会给出更多的澄清:

我最终在我的用户目录的根目录中创建了一个全局文件夹。在该目录中,我使用npm install添加了我需要的所有软件包。例如,我运行了npm install gruntnpm install grunt-contrib-watchnpm install grunt-contrib-less等。您还可以在同一文件夹中添加package.json文件,然后运行npm install添加他们一下子。现在我的全局目录具有以下结构:

.global_grunt_modules
    node_modules
        grunt
        grunt-contrib-watch
        grunt-contrib-less

然后我去了我需要运行grunt的任何工作项目目录,并在该文件夹的根目录中运行命令:

ln -s ~/.global_grunt_modules/node_modules .

带有ln(符号链接)标志的

-s有两个参数:

[source_file] [target_dir]

因此该命令基本上说,“从我的全局node_modules文件夹创建一个符号链接,并将其链接到我当前的目录”。 .指定当前工作目录。

希望这有帮助,我也遇到了麻烦。然后每当我有一个需要新grunt模块的项目时,我只需通过我的全局目录安装它,然后在创建符号链接的任何地方都可以使用它。

答案 4 :(得分:0)

当npm链接不够好时(网络文件系统,...),您可以使用'requireg'包。这是唯一让它“内置”的干净解决方案。 'requireg'包具有一个全局化函数,这使后续的require调用也可以查看全局。