NODE_PATH浅谈

最近在试图加载npm全局下的express模块的时候,出现Error: Cannot find module ‘express’的报错,按理说我已经将express安装到了全局的node_modules目录,为什么还会加载不到这个模块呢?
本文将以该问题作为切入点,记录一下node下的module加载机制,算是自我学习一些吧。

NPM

NPM(node package manager)是NODE下的一款包管理工具,它的主要功能就是管理node包,包括:安装、卸载、更新、查看、搜索、发布等。它将开发者从繁琐的包管理工作中解放出来,极大的便利了我们的开发。

NPM有两种安装方式:

  • npm install –global xxx 属于全局安装(示例:npm install -g express)
  • npm install xxx 属于本地安装

全局安装是把包安装到了(npm config get prefix)lib/node_modules 这个全局目录下
本地安装则是把包安装到了当前目录下的./node_modules 目录下。

NODE_PATH

NODE_PATH是NODE中用来寻找模块所提供的路径注册环境变量,像操作系统中都会有一个PATH环境变量,当系统调用一个命令的时候,就会在PATH变量中注册的路径中寻找,如果注册的路径中有就调用,否则就提示命令没找到,NODE_PATH类似如此。

export PATH=$PATH: # 将 /usr/bin 追加到 PATH 变量中
export NODE_PATH="/usr/lib/node_modules:/usr/local/lib/node_modules" #指定 NODE_PATH 变量,并用:分隔了多个不同的目录

通过上面的方法指定NODE_PATH环境变量后,文章开始遇到的问题就迎刃而解了,哦,原来是没有设置NODE_PATH环境变量的缘故(在Windows中,NODE_PATH用分号而不是冒号分隔)。

在unix系统下,可以通过如下方式添加NODE_PATH环境变量

vi ~/.bash_profile

如果在用户目录下没有.bash_profile文件,则新建一个,然后填写如下内容

export NODE_PATH="/usr/lib/node_modules:/usr/local/lib/node_modules"

最后,通过 $ source .bash_profile 命令使其立即生效。

模块加载

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

在Node.js中,对于每一个被加载的文件模块,创建这个模块对象的时候,这个模块便会有一个paths属性,其值根据当前文件的路径计算得到。我们创建modulepath.js这样一个文件,其内容为:

console.log(module.paths);

执行 node modulepath.js, 将得到如下输出结果:

[ '/Users/sobird/node_modules',
'/Users/node_modules',
'/node_modules' ]

如上,Node.js的模块加载正式按照上面给出的目录集合按照顺序进行加载。

动态更改NODE_PATH

明白了上面module.paths的作用,我们在代码编写的时候,就可以随意指定模块加载路径,比如,现在有模块a.js 和 b.js,他们在磁盘中的路径分别是 /path/a/a.js, /path/b/b.js。

如果我们想在a模块中加载b模块的依赖c,可以通过下面的写法实现:

// 加载模块绝对路径
var b = require('/path/b/node_modules/c.js');

那么,如果通过相对路径的方式如何加载?

// 在a模块中这方式是加载不到b模块的
// 修改module.paths的目录集合,将b模块的node_modules目录push进来
module.paths = module.paths.push('/path/b/node_modules');
var b = require('c.js');

如上,这样就可以加载到b模块的依赖c模块了~

参考
深入浅出Node.js(三):深入Node.js的模块机制

这篇文章目前没有评论

Leave a Reply

(必填项)

(必填项)

(可选)