首先,我是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文件夹中:
-
咕噜声
-
grunt-bower-task
-
grunt-contrib-compass
-
grunt-contrib-connect
-
grunt-contrib-jshint
-
grunt-contrib-requirejs
-
grunt-contrib-watch
然后当我从我的项目目录运行grunt deploy时,一切都按预期工作 .
虽然我可以简单地运行npm install部分构建过程,但我不愿意,因为下载所有文件需要几分钟,而且我不希望我们的构建依赖于可用的外部Web服务 .
我已经看到you can install modules either locally or globally,所以我希望能够在构建服务器上全局安装模块,这样在运行grunt deploy之前,它们不需要直接位于项目目录内的node_modules文件夹中 . 我为上面列出的每个模块运行了npm install -g,以及npm install -g [module],以及npm install -g grunt-cli .
如果我执行npm前缀-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全局前缀路径,而不是查看项目目录?
一个hacky的工作是在构建过程中手动将模块复制到本地项目目录,但我想尽可能避免这种情况 .
作为参考,这是我的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 回答
您应该在模块上使用symbolic links,而不是使用
npm
的全局选项,以获得类似的结果 .全局
npm
安装仅用于方便命令行实用程序,例如jshint
或grunt-cli
.解决方法:在您自己的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
树 .我使用fenestrate来解决Windows上的这类问题 . 即使它适用于Git,如果你在团队资源管理器中使用Visual Studio中的Git集成,如果你的node_modules文件夹中存在长文件路径,它仍然会崩溃 - 即使你没有添加文件夹到源代码控制 .
通常Grunt和Bower依赖结构导致这种情况 .
我建议首先在你的包裹上运行
npm dedupe
. 这样做的目的是扫描已安装的软件包,看看是否有重复的依赖项 . 如果在更高级别找到它,它将删除经过深度测试的那些 .其次,如果重复数据删除无法解决问题,如果您可以找到导致此问题的深度嵌套的依赖项,请尝试直接在解决方案中安装它,然后再次运行重复数据删除 .
如果有更多的包依赖项导致此问题,fenestrate将解决该问题 . 再加上'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'完全可以逆转 .
我希望这有帮助 .
我知道这个帖子已经老了,但我终于找到了自己的个人答案,使用的是Mac,但我认为可以用PC来表达/完成 .
跟进bevacqua的回答:
我做了一些挖掘,可能会给出更多的澄清:
我最终在我的用户目录的根目录中创建了一个全局文件夹 . 在该目录中,我使用
npm install
添加了我需要的所有软件包 . 所以例如我运行npm install grunt
,npm install grunt-contrib-watch
,npm install grunt-contrib-less
等 . 你也可以在同一个文件夹中添加一个package.json
文件,然后运行npm install
一次添加它们 . 现在我的全局目录具有以下结构:然后我去了我需要运行grunt的任何工作项目目录,并在该文件夹的根目录中运行命令:
ln -s ~/.global_grunt_modules/node_modules .
ln
与-s
(符号链接)标志有两个参数:[source_file] [target_dir]
所以命令基本上说,"create a symbolic link from my global node_modules folder, and link that to my current directory" .
.
指定当前工作目录 .希望这有帮助,我也遇到了麻烦 . 然后每当我有一个需要新grunt模块的项目时,我只需通过我的全局目录安装它,然后在创建符号链接的任何地方都可以使用它 .
当npm链接不够好时(网络文件系统,...),您可以使用'requireg'包 . 这是唯一一个以某种方式使它成为'built-in'的干净解决方案 . 'requireg'包具有一个全局化函数,使后续的require调用也在全局查找 .