nodejs 中的 NODE_PATH

在使用 nodejs 开发中我们都免不了要去安装一些第三方模块。

那么你或多或少的遇到过以下一些问题

再继续阅读之前,我们先来弄清楚一个概念。

npm install --global xxx 属于全局安装
npm install xxx 属于本地安装

安装的模块太多项目太臃肿,模块没能复用

你写一个项目 A 需要安装一个 express 模块,又开发一个项目 B 又需要安装一个 express 模块

项目中依赖包太多,文件过多,模块没法复用,各种问题浮现

由于 安装的依赖包过多(而且依赖包嵌套依赖包),如果一个项目依赖多的话,(比如依赖 gulp 系列 或 grunt 系列的项目构模块)那么一个项目可以说轻轻松松上百兆。如果想给想项目更换一个目录,都发现是痴心妄想了。(基本都是1-10KB的小文本文件组成了一个100多MB的项目,那得有多少个文件啊!想想如果像java那样,模块都是以jar包存在的压缩归档文件可能也好一点)。更别提部署了。

其实这里面的代码也就是 几十KB到1兆 是我们自己写的代码。这些文件想实现 复制,移动,部署是很方面的。

给部署带来的困扰

如果你部署过 node 项目到远程服务器,node_modules 目录的上传将是一件恐怖的事情

NODE_PATH 出现,模块复用,最佳实践方案

NODE_PATH 是干什么的呢?

操作系统中都会有一个PATH环境变量,想必大家都知道,当系统调用一个命令的时候,就会在PATH变量中注册的路径中寻找,如果注册的路径中有就调用,否则就提示命令没找到。

-> export PATH=$PATH: # 将 /usr/bin 追加到 PATH 变量中
-> export NODE_PATH="/usr/lib/node_modules;/usr/local/lib/node_modules" #指定 NODE_PATH 变量

那 NODE_PATH 就是NODE中用来寻找模块所提供的路径注册环境变量。我们可以使用上面的方法指定NODE_PATH环境变量。并且用;分割多个不同的目录。

加载时机

关于 node 的包加载机制我就不在这里废话了。NODE_PATH中的路径被遍历是发生在

从项目的根位置递归搜寻 node_modules 目录,直到文件系统根目录的 node_modules,如果还没有查找到指定模块的话,就会去 NODE_PATH中注册的路径中查找

解决问题

基于 nodejs 的包加载路径搜索算法,我们可以 采用全局安装的方式,将我们的包安装到全局。

这样,我们的项目就可以共享全局中的依赖包。

了解全局

npm root -g 查看在你的系统中全局的路径。

我们也可以通过
npm config ls -l | grep prefix (*nix) 系统中

或是
npm config get prefix

来查看全局路径。

是的 prefix 字段就是全局base path

怎么设置全局路径呢?

# in *nix
npm config set prefix /path/to/global # in windows
npm config set prefix C:\\Users\\pc\\global

求同存异,解决模块版本问题

差异性的解决方法

如果 项目A 使用了,express的3.x版本,项目B 使用了 express的4.x版本,那这种情况该怎么办呢?

可以将 NODE_PATH 指定的位置中存放 express的4.x版本,再将 项目B的 node_modules 目录中放置 3.x 版本。

这样就解决了模块版本差异性问题。

所以说,两种安装方式我们并不是只是用其中的一种,他们可以结合使用,根据 nodejs 的包加载机制,我们可以灵活使用。

部署不再是问题

在部署之前,我们可以将我们项目的所有可以全局安装的模块,都以全局的安装方式安装到服务器中。接下来我们就可以轻松,上传我们的项目到服务器中了。这样上传也会变得的很快。

然后配置我们的 NODE_PATH 环境变量。怎么配置上面也谈过,这里就不用多说了。(因为项目的部署方式多种多样,所以具体情况可以自行决定。)

本人是使用 PM2 部署管理Nodejs项目,所以我写在 配置文件中。

带来的问题

是的这种方式也有缺点。因为在使用 --global 参数的时候 --save 或 --save-dev参数是无效的。

这样就带来一个问题。此时 package.json 中的 dependenciesdevDependencies 将无法享受到npm自动更新带来的便利,不使用 dependenciesdevDependencies 字段对我们的项目管理来说是不可接受的。

如何解决

我有一个不是很优雅地解决方法,但是也算是解决了这个问题,希望有更好解决办法的同学给我留言。

我写了一个小工具(npmafter),它的使用方法很简单, 它是跨平台的。兼容(Mac,Windows,Linux)。(我没有发布到github上,因为感觉会有更好的办法)

$ npm install -g http://yinchangsheng-blog.qiniudn.com/blog/nodejs/npmafter.tgz # install
# 然后我们安装任何模块就可以这样
$ npm install express -g | npmafter
$ npm install request q -g | npmafter --save
$ npm install mocha chai -g | npmafter --save-dev

是的 package.json 文件就会得到更新。

好的,如果你不纠结这个问题那么这个问题就算是解决了。

使用 NODE_PATH 可以很好的解决项目开发部署的问题。

NODE_PATH的疑难杂症(转)的更多相关文章

  1. Carousel 旋转画廊特效的疑难杂症

    疑难杂症 该画廊特效的特点就是前后元素有层级关系. 我想很多人应该看过或者用过这个插件carousel.js,网上也有相关的教程.不知道这个插件的原型是哪个,有知道的朋友可以告诉我. 该插件相对完美, ...

  2. TCP协议疑难杂症全景解析

    说明: 1).本文以TCP的发展历程解析容易引起混淆,误会的方方面面2).本文不会贴大量的源码,大多数是以文字形式描述,我相信文字看起来是要比代码更轻松的3).针对对象:对TCP已经有了全面了解的人. ...

  3. [Swift] 疑难杂症

    [Swift] 疑难杂症 1.class  .... has no initializers -->  class 的每一个元素都需要初始化,否则会报错,除了可空元素

  4. nodejs 80端口监听失败及NODE_PATH不起作用的问题

    nodejs做web服务器,打开80时报错:Error: listen EACCES 0.0.0.0:80 80端口监听失败,是因为1024以下的端口需要root权限,需要sudo或su之后执行.但这 ...

  5. 十个Flex/Air疑难杂症及解决方案简略

    十个Flex/Air疑难杂症及解决方案简略 转自http://blog.sban.us/40.html 最近去一家台企,对方给我出了十道“难道”:在TileList中如果選擇檔過多,會出現捲軸,當拖動 ...

  6. C# (事件触发)回调函数,完美处理各类疑难杂症!

    每次写博客,第一句话都是这样的:程序员很苦逼,除了会写程序,还得会写博客! 废话说多了...... 嘿嘿:本篇标题为:C#  (事件触发)回调函数,完美处理各类疑难杂症.个人理解如下:事件触发也就是触 ...

  7. 使用truss、strace或ltrace诊断软件的“疑难杂症”

    简介 进程无法启动,软件运行速度突然变慢,程序的"Segment Fault"等等都是让每个Unix系统用户头痛的问题,本文通过三个实际案例演示如何使用truss.strace和l ...

  8. 【转载】TCP协议疑难杂症全景解析

    说明: 1).本文以TCP的发展历程解析容易引起混淆,误会的方方面面2).本文不会贴大量的源码,大多数是以文字形式描述,我相信文字看起来是要比代码更轻松的3).针对对象:对TCP已经有了全面了解的人. ...

  9. IE-“无法浏览网页” 教你十招解决疑难杂症

    “无法浏览网页” 教你十招解决疑难杂症 相信大家也有遇到过像IE不能上网浏览的问题.下面就来给大家介绍一下常见原因和解决方法: 一.网络设置的问题 这种原因比较多出现在需要手动指定IP.网关.DNS服 ...

随机推荐

  1. log4j的NDC/MDC区别与应用

    MDC与NDC除了存储方式(MDC采用MapNDC采用堆栈结构)有区别,其他都一样的 关键点 A -//引入log4j MDC类org.apache.log4j.MDC -//设置值 -MDC.put ...

  2. 解决 无法将文件" "复制到“bin\*.*”。对路径“bin\*.*”的访问被拒绝。

    关于这个问题今天碰到了, 我的解决办法很简单: 删除bin目录下的所有文件,然后重新生成,就不报错了.

  3. python学习笔记013——模块中的私有属性

    1 私有属性的使用方式 在python中,没有类似private之类的关键字来声明私有方法或属性.若要声明其私有属性,语法规则为: 属性前加双下划线,属性后不加(双)下划线,如将属性name私有化,则 ...

  4. Web - TCP与UDP的差别

    是否面向连接:TCP面向连接.UDP面向非连接. 传输可靠性:TCP可靠.UDP不可靠. 应用场合:TCP经常使用于传输大量数据,UDP经常使用于传输少量数据. 速度:TCP传输速度较慢,而UDP速度 ...

  5. 开启Win7多用户登录远程桌面

    原文链接: http://blog.sina.com.cn/s/blog_7e5da5b101014fc4.html 多用户登陆破解:(支持win7 x86 & win7x64)在 Windo ...

  6. Python 字典 pop() 方法

    描述 Python 字典 pop() 方法删除给定键所对应的键/值对,并返回被删除的值.给定键如果不在字典中,则必须设置一个default值,否则会报错,此时返回的就是default值. 语法 pop ...

  7. debian系在线安装软件apt-get命令族

    一.背景 apt-get install/remove在线安装/卸载文件真是方便极了. 但是有时候安装/卸载文件不清楚文件在服务器上的实际命名,例如想安装sndfile.应该执行下面哪个命令呢? ap ...

  8. vue组件值传递之父组件向子组件传递(props)

    <template> <div class="hello"> <h1>{{ msg }}</h1> <ul> <l ...

  9. Java web中listener、 filter、servlet 加载顺序

    真正的加载顺序为:context-param -> listener -> filter -> servlet 加载顺序与它们在 web.xml 文件中的先后顺序无关.即不会因为 f ...

  10. python 中安装pandas

    由于计算arima模型需要用到pandas,费尽千辛万苦找到了一个下载地址:http://www.lfd.uci.edu/~gohlke/pythonlibs/,在这里能下载到很多我们要用的模块.找到 ...