一、模块
在 Node.js 中,文件和模块是一一对应的(每个文件被视为一个独立的模块)。
模块分为三种:核心模块(node定义的)、第三方模块、自定义模块。可以通过require()加载第三模块。require会将module.exports对象暴露给外部。
模块中的命名空间是独立的,不是全局的。
二、require()
下面的代码是require的假设实现。
1 //自定义一个require() 2 let path=require('path'); 3 const fs=require('fs'); 4 function $require(id){ 5 //拼合文件路径 6 let filename=path.join(__dirname,id); 7 let dirname=path.dirname(filename); 8 //读取要加载的文件的内容 9 let content=fs.readFileSync(filename,'utf8');10 let module={exports:{},id:filename}11 //执行代码12 let exports=module.exports;13 let code=`(function(__filename,module,exports){14 ${content}15 }(filename,module,exports))`; eval(code)16 return module.exports;17 }18 const mymodule=$require("./modele1.js");19 mymodule.say();
三、require的加载机制
文件模块加载
如果按确切的文件名没有找到模块,则 Node.js 会尝试带上 .js
、.json
或 .node
拓展名再加载。
.js
文件会被解析为 JavaScript 文本文件,.json
文件会被解析为 JSON 文本文件。 .node
文件会被解析为通过 dlopen
加载的编译后的插件模块。
以 '/'
为前缀的模块是文件的绝对路径。 例如,require('/home/marco/foo.js')
会加载 /home/marco/foo.js
文件。
以 './'
为前缀的模块是相对于调用 require()
的文件的。 也就是说,circle.js
必须和 foo.js
在同一目录下以便于 require('./circle')
找到它。
当没有以 '/'
、'./'
或 '../'
开头来表示文件时,这个模块必须是一个核心模块或加载自 node_modules
目录。
如果给定的路径不存在,则 require()
会抛出一个 code
属性为 'MODULE_NOT_FOUND'
的 Error
。
目录模块加载
可以把程序和库放到一个单独的目录,然后提供一个单一的入口来指向它。 把目录递给 require()
作为一个参数,有三种方式。
第一种方式是在根目录下创建一个 package.json
文件,并指定一个 main
模块。 例子,package.json
文件类似:
{ "name" : "some-library", "main" : "./lib/some-library.js" }
如果这是在 ./some-library
目录中,则 require('./some-library')
会试图加载 ./some-library/lib/some-library.js
。这就是 Node.js 处理 package.json
文件的方式。
注意:如果 package.json
中 "main"
入口指定的文件不存在,则无法解析,Node.js 会将模块视为不存在,并抛出默认错误:Error: Cannot find module 'some-library'
如果目录里没有 package.json
文件,则 Node.js 就会试图加载目录下的 index.js
或 index.node
文件。 例如,如果上面的例子中没有 package.json
文件,则 require('./some-library')
会试图加载:
./some-library/index.js
./some-library/index.node
加载核心模块和node_module
模块标识符没有以 '/'
、 '../'
或 './'
开头,加载的可能是核心模块,如果传递给 require()
的模块标识符不是一个核心模块,则 Node.js 会从当前模块的父目录开始,尝试从它的 /node_modules
目录里加载模块。
如果还是没有找到,则移动到再上一层父目录,直到文件系统的根目录。
例子,如果在 '/home/ry/projects/foo.js'
文件里调用了 require('bar.js')
,则 Node.js 会按以下顺序查找:
/home/ry/projects/node_modules/bar.js
/home/ry/node_modules/bar.js
/home/node_modules/bar.js
/node_modules/bar.js
这使得程序本地化它们的依赖,避免它们产生冲突。
四、package.json文件
使用package.json文件配置项目所依赖的模块。可以使用npm init初始化一个package.json文件。使用npm install安装项目所依赖的文件。