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
中的 dependencies
, devDependencies
将无法享受到npm自动更新带来的便利,不使用 dependencies
, devDependencies
字段对我们的项目管理来说是不可接受的。
如何解决
我有一个不是很优雅地解决方法,但是也算是解决了这个问题,希望有更好解决办法的同学给我留言。
我写了一个小工具(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
可以很好的解决项目开发部署的问题。
nodejs 中的 NODE_PATH的更多相关文章
- nodejs中的require,exports使用说明
模块是一门语言编写大项目的基石,因此,了解如何组织.编写.编译.加载模块很重要.这里主要谈谈Node中的模块加载. 1.Node中的模块,主要使用require来加载模块,文件 require(&qu ...
- nodejs中获取时间戳、时间差
Nodejs中获取时间戳的方法有很多种,例如: new Date().getTime() Date.now() process.uptime() process.hrtime() 平时想获取一个时间戳 ...
- 在Nodejs中如何调用C#的代码
最近需要在Nodejs中用到C#的代码,从网上了解到可以采用Edgejs来实现Nodejs与C#的代码交互, 直接复制网上的代码运行总是出各种错,填了不少坑,现在把自己的案例代码大致整理一下,方便以后 ...
- nodejs 中自定义事件
经常看到 req.on('error', function(){...}); 这种代码. 在nodejs中,可以使用 EventEmitter来实现. 具体的关键词有如下几个: var reqEven ...
- NodeJS中的异步I/O、事件驱动
nodejs的主要特点是单线程.异步I/O.事件驱动.让我们先大概了解一下这些名词的意思. 单线程 单线程是任务按照顺序执行的,并且每次只执行一个任务,只有前面的任务执行完成以后,后面的任务才执行.在 ...
- nodejs中Stream的理解
在nodejs中可以通过fs模块读写文件,我们来看下fs模块提供的接口: fs.readFile(filename, callback) 异步读取文件. filename是读取文件的文件名,如果是相对 ...
- Nodejs中的this
以下内容都是关于在nodejs中的this而非javascript中的this,nodejs中的this和在浏览器中javascript中的this是不一样的. 在全局中的this console.l ...
- 探讨Nodejs中的作用域问题。
在JS中有全局作用域和函数作用域,而在Nodejs中也自己的作用域,分为全局作用域(global)和模块作用域. js作用域: 以前学js的时候我们的全局对象是window,如: var a = 10 ...
- nodejs中exports与module.exports的实践
只要是在nodejs中写自己的文件模块就少不了会遇到module.exports和exports的使用,看别人的代码大多都会使用“module.exports=exports=<对象/函数等&g ...
随机推荐
- python 获取探针页面,自动查询公司出口
在一些渗透当中,我们需要批量探针出口来达到我们的目的. 所以就有了这个丑陋简洁的小脚本. #!/usr/bin/env python #-*- coding:utf- -*- import sys i ...
- Javascript -- 示例:多选下拉选框
1. 示例:多选下拉选框 <html> <head> <meta http-equiv="Content-Type" content="te ...
- Minimum Window Substring, 包含子串的最小窗口,双指针
问题描述:给定字符串S,子串T,求S中包含T的最小窗口 Given a string S and a string T, find the minimum window in S which will ...
- spring3: Bean的作用域
3.4 Bean的作用域 什么是作用域呢?即“scope”,在面向对象程序设计中一般指对象或变量之间的可见范围.而在Spring容器中是指其创建的Bean对象相对于其他Bean对象的请求可见范围. ...
- WPF 通过 CommandParameter 传递当前窗体到 ViewModel
在应用 Command 模式中,需要在View上点击 一个按钮,需要将当前窗体作为参数传递为 command 两种方式传递当前窗体1.通过窗体名称(假设窗体名称为 ThisWindow) < ...
- Light oj 1074 spfa
https://vjudge.net/problem/LightOJ-1074 首先吐槽一个单词,directional是有方向的,undirectional是无向的,这个unidirectional ...
- LeetCode OJ:Valid Anagram(有效字谜问题)
Given two strings s and t, write a function to determine if t is an anagram of s. For example,s = &q ...
- Siemens
Sr.EE-Complete the electronics and mechanical designs from design concepts to mass production for RU ...
- SWF文件加密、混淆
简单说下SWF文件的混淆原理,(已经明白的请跳过本段):我们的AS源代码被编译完成后,SWF内部会形成一个字符串映射表,包含源码里出现的所有字符串(类名,包名,成员变量名,常量等).一个数字(相当于地 ...
- mysql的5.6版本支持分区吗?
转载请注明出处:http://blog.csdn.net/dongdong9223/article/details/72291698 本文出自[我是干勾鱼的博客] 我们知道,查看mysql是否支持分区 ...