本文同步自我的个人博客:http://www.52cik.com/2015/12/11/learn-node-modules-path.html

用了这么久的 require,但却没有系统的学习过 node 的模块系统,今天就翻官方文档系统的学习下。

循环引用

node 对模块循环引用做了相应的处理,防止无尽的循环。

官方例子:

a.js:

console.log('a starting');
exports.done = false;
var b = require('./b.js');
console.log('in a, b.done = %j', b.done);
exports.done = true;
console.log('a done');

b.js:

console.log('b starting');
exports.done = false;
var a = require('./a.js');
console.log('in b, a.done = %j', a.done);
exports.done = true;
console.log('b done');

main.js:

console.log('main starting');
var a = require('./a.js');
var b = require('./b.js');
console.log('in main, a.done=%j, b.done=%j', a.done, b.done);

执行结果:

$ node main.js
main starting
a starting
b starting
in b, a.done = false
b done
in a, b.done = true
a done
in main, a.done=true, b.done=true

在结果中可以看到,b 里引用 a 的时候结果是 a.done = false,这就算文档里说的 unfinished copy,这样就避免了程序的死循环。

核心模块

其实就是被编译到 node 内部的一些模块,在源码的 lib 目录下可以找到。例如 require('http') 的时候不论是否有其他同名模块,都直接返回 node 的核心模块,也就算最高优先级。

这些模块就是 node 官网文档目录列表里的那些模块。

文件模块

这个花样就多了,慢慢说吧。

模块后缀

node 默认支持 .js .json .node 后缀的模块,也就是说 require 的时候不需要写后缀名。例如 require('./a'),node 会先尝试当前目录下的 a.js 文件,如果有,就载入否则继续尝试 a.json, a.node 这些文件,如果都不存在,就会抛出模块未找到的错误。

当然这些模块后缀都是可以自己定义拓展的,比如 ejs 就拓展了个 .ejs 的后缀,支持直接 require 就得到了编译好的模块引擎了。

模块路径

以 '/', './' 或 '../' 开头的,都是指定路径加载。

模块以 '/' 为前缀,则表示绝对路径。例如,require('/home/marco/foo.js') 加载的是 /home/marco/foo.js 这个文件。

模块以 './' 为前缀,则路径是相对于当前文件的。也就是说,circle.js 必须和 foo.js 在同一目录下,require('./circle') 才能找到。

其实还一个特殊路径的模块加载,就是 node_modules 文件夹,这个要单独说了。

从 node_modules 目录中加载

如果模块不是以 '/', './' 或 '../' 开头的,那么 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

如果都找不到,会去全局模块路径找,还找不到就会抛出模块未找到的错误。

目录模块

当一个模块功能多代码多的时候,不合适写到一个文件里,那这个时候就可以用目录当作模块使用了。有两种方法可以让一个目录作为 require 方式引入。官网说三种,其实吧 .js .node 看做两种了。

index.js 入口

例如在 some-library 目录里有 index.js 或者 index.node 文件,那么 require('./some-library') 就将尝试加载下面的文件:

  • ./some-library/index.js
  • ./some-library/index.node

非常简单方便。

package.json

还有一种方式可以指定入口文件,就是通过 package.json,下面是一个 package.json 文件的示例。

{
"name" : "some-library",
"main" : "./src/some-library.js"
}

那么 require('./some-library') 就将会去加载 ./some-library/src/some-library.js。

全局模块

当以上方法找不到模块时,node 会去全局配置下寻找全局模块:

  • $HOME/.node_modules
  • $HOME/.node_libraries
  • $PREFIX/lib/node

以及

  • /usr/lib/node_modules

或者

  • /usr/local/lib/node_modules

这些都没测试,我只知道我本地的全局模块路径是 /usr/local/lib/node_modules,是我本机 npm 安装的全局模块路径。

官网里还有一些奇葩的全局目录,我都没见过,算了不研究了。

node 学习笔记 - Modules 模块加载系统 (1)的更多相关文章

  1. node 学习笔记 - Modules 模块加载系统 (2)

    本文同步自我的个人博客:http://www.52cik.com/2015/12/14/learn-node-modules-module.html 上一篇讲了模块是如何被寻找到然后加载进来的,这篇则 ...

  2. thinkphp学习笔记9—自动加载

    原文:thinkphp学习笔记9-自动加载 1.命名空间自动加载 在3.2版本中不需要手动加载类库文件,可以很方便的完成自动加载. 系统可以根据类的命名空间自动定位到类库文件,例如定义了一个类Org\ ...

  3. abp vnext2.0之核心组件模块加载系统源码解析与简单应用

    abp vnext是abp官方在abp的基础之上构建的微服务架构,说实话,看完核心组件源码的时候,很兴奋,整个框架将组件化的细想运用的很好,真的超级解耦.老版整个框架依赖Castle的问题,vnext ...

  4. 第三章:模块加载系统(requirejs)

    任何一门语言在大规模应用阶段,必然要经历拆分模块的过程.便于维护与团队协作,与java走的最近的dojo率先引入加载器,早期的加载器都是同步的,使用document.write与同步Ajax请求实现. ...

  5. Openstack本学习笔记——Neutron-server服务加载和启动源代码分析(三)

    本文是在学习Openstack过程中整理和总结.因为时间和个人能力有限.错误之处在所难免,欢迎指正! 在Neutron-server服务载入与启动源代码分析(二)中搞定模块功能的扩展和载入.我们就回到 ...

  6. Node学习笔记之模块实现

    一.模块分类 由Node提供的模块,称为核心模块:部分核心模块在Node源代码的编译过程中,编译进了二进制执行文件.在node进程启动时,该部分就直接加载进内存,文件定位和编译执行的步骤可以省略掉,并 ...

  7. JS框架设计之加载器所在路径的探知一模块加载系统

    1.要加载一个模块,我们需要一个URL作为加载地址,一个script作为加载媒介,但用户在require是都用ID,我们需要一个将ID转换为URL的方法,思路很简单,强加个约定,URL的合成规则是为: ...

  8. JS框架设计之模块加载系统

    任何语言一到大规模应用阶段,必然要拆封模块,有利于维护和团队协作,与Java走得最近的dojo率先引进了加载器,使用document.write与同步Ajax请求实现,后台dojo以JSONP的方法来 ...

  9. YUI笔记 1 模块加载

    我们通常开发js程序就是使用<script>标签把脚本引入到页面中进行开发,如果是简单的逻辑还好,但是如果是比较庞大的大规模js开发,可能会出现下面的问题: 1.  <script& ...

随机推荐

  1. Access字段类型“查阅向导”

    1.显示控件有:“列表框”和“组合框”两种 2.组合框:第一个字段为“填充字段” 3.通过查阅向导建立的会自动添加“关系”(外键),因此在删除或修改字段时需要先删除二者关系,最好不通过“查阅向导”建立 ...

  2. vs2013外接程序”VMDebugger”加载异常处理

    cmd → regedit HKEY_LOCAL_MACHINE → OFTWARE → Wow6432Node → Microsoft  → VisualStudio → 12.0 → AddIns ...

  3. js中页面跳转几种方法

    <script> function toLogin(){ //第一种 //self.location="/zhld/toTestLogin"; //第二种 top.lo ...

  4. x01.os.11: IPC 路线图

    学习的最好方法就是看代码,所以我们不妨跟着 IPC 的调用路线图,来学习学习 IPC. 从 x01.Lab.Download 下载代码后,首先进入 main.c 文件,在 TestA 中,有这么一句: ...

  5. nodeJS Express 删除 x-powered-by

    在使用Express4 Header头部会输出,在晚上搜索几种方案也没有产生效果,就看了一下官方文档 Property Type               Value Default     x-p ...

  6. Linux学习书籍推荐

    入门书: <鸟哥的私房菜(基础篇)> <鸟哥的私房菜(服务篇)> <Linux命令行与Shell脚本编程大全(第2版)> <UNIX/Linux 系统管理技术 ...

  7. 使用TCMalloc的堆栈检查

    在前一篇译文<TCMalloc:线程缓冲的Malloc>详细讲解了TCMalloc的工作原理和特点,今天翻译<heap-checking using tcmalloc>,了解T ...

  8. DPM检测模型 训练自己的数据集 读取接口修改

    (转载请注明作者和出处 楼燚(yì)航的blog :http://www.cnblogs.com/louyihang-loves-baiyan/ 未经允许请勿用于商业用途) 本文主要是针对上一篇基于D ...

  9. 为opencv贡献代码

    本文记录本人从发现bug,提交bug,到修复bug的过程.下面enjoy: 1.发现bug 由于项目需要,开发了一个视频检测demo,类似于扫一扫二维码的程序,不过不是这个程序不是扫二维码.具体实现参 ...

  10. 【原创Android游戏】NinOne V2.3.1 --加载模式的学习,界面的重新设计

    上次更新后又发现了一些bug,而且是非常明显的bug,一一加以改正了过来. 猜数字游戏的功能已基本实现,不过我觉得一个应用单做一个游戏有点不太过瘾,略显单调,于是我打算基于这个,写一个n合1的游戏集成 ...