Node使用CommonJS模块系统。Node有一个简单的模块装载系统,在Node中,文件和模块是一一对应的。下面的例子展示了foo.js文件如何在相同的目录中加载circle.js模块。
foo.js的内容为:
1 | var circle = require('./circle.js'); |
circle.js的内容为:
1 | var PI = Math.PI; |
circle.js模块输出了area()和circumference()两个函数,为了以对象的形式输出,需将要输出的函数加入到一个特殊的exports对像中。
模块的本地变量是私有的。在上面的例子中,变量PI就是circle.js私有的。
###Core Modules 核心模块###
Node有一些编译成二进制的模块。
核心模块在node源代码中的lib文件夹下。
核心模块总是被优先加载,如果它们的标识符被require()调用。例如,require(‘http’)将总是返回内建的HTTP模块,即便又一个同名文件存在。
###File Modules 文件模块###
如果没有找到确切的文件名,node将尝试以追加扩展名.js后的文件名读取文件,如果还是没有找到则尝试追加扩展名.node。.js文件被解释为JavaScript格式的纯文本文件,.node文件被解释为编译后的addon(插件)模块,并使用dlopen来加载。
以’/‘为前缀的模块是一个指向文件的绝对路径,例如require(‘/home/marco/foo.js’)将加载文件/home/marco/foo.js。
如果标明一个文件时没有 ‘/‘ 或 ‘./‘前缀,该模块或是”核心模块”,或者位于 node_modules目录中。
###Loading from ‘node_modules’ Folders 从 ‘node_modules’ 目录中加载###
如果传递到 require()的模块标识符不是一个核心模块,并且不是以’/‘,’../‘或’./‘开头,node将从当前模块的父目录开始,在其/node_modules子目录中加载该模块。
如果在那里没有找到,就转移到上一级目录,依此类推,直到找到该模块或到达目录树的根结点。
例如,如果在文件 ‘/home/ry/projects/foo.js’中调用 `require(‘bar.js’),node将会依次查找以下位置:
- /home/ry/projects/node_modules/bar.js
- /home/ry/node_modules/bar.js
- /home/node_modules/bar.js
- /node_modules/bar.js
这允许程序本地化他们的依赖关系,避免发生冲突。
###Optimizations to the ‘node_modules’ Lookup Process 优化 ‘node_modules’ 的查找过程###
如果有很多级的嵌套信赖,文件树会变得相当的长,下面是对这一过程的一些优化。
首先, /node_modules不要添加到以 /node_modules结尾的目录上。
其次,如果调用require()的文件已经位于一个node_modules层次中,最上级的node_modules目录将被作为搜索的根。
例如,如果文件’/home/ry/projects/foo/node_modules/bar/node_modules/baz/quux.js’调用require(‘asdf.js’),node会在下面的位置进行搜索:
- /home/ry/projects/foo/node_modules/bar/node_modules/baz/node_modules/asdf.js
- /home/ry/projects/foo/node_modules/bar/node_modules/asdf.js
- /home/ry/projects/foo/node_modules/asdf.js
###Folders as Modules 目录作为模块###
很方便将程序或库组织成自包含的目录,并提供一个单独的入口指向那个库。有三种方式可以将一个子目录作为参数传递给 require()
第一种方法是在目录的根下创建一个名为package.json的文件,它指定了一个main 模块。一个package.jso文件的例子如下面所示:1
2{ "name" : "some-library",
"main" : "./lib/some-library.js" }
如果此文件位于./some-library目录中,require(‘./some-library’)将试图加载文件./some-library/lib/some-library.js。
这是Node感知package.json文件的范围。
如果在目录中没有package.json文件,node将试图在该目录中加载index.js 或 index.node文件。例如,在上面的例子中没有 package.json文件,require(‘./some-library’)将试图加载:
- ./some-library/index.js
- ./some-library/index.node
###Caching 缓存###
模块在第一次加载后将被缓存。这意味着(类似其他缓存)每次调用require(‘foo’)如果解析到相同的文件,那么将返回同一个对象。