解析Node.js基于模块和包的代码部署方式


Posted in Javascript onFebruary 16, 2016

模块路径解析规则

有经验的 C 程序员在编写一个新程序时首先从 make 文件写起。同样的,使用 NodeJS 编写程序前,为了有个良好的开端,首先需要准备好代码的目录结构和部署方式,就如同修房子要先搭脚手架。本章将介绍与之相关的各种知识。

模块路径解析规则
我们已经知道,require函数支持斜杠(/)或盘符(C:)开头的绝对路径,也支持./开头的相对路径。但这两种路径在模块之间建立了强耦合关系,一旦某个模块文件的存放位置需要变更,使用该模块的其它模块的代码也需要跟着调整,变得牵一发动全身。因此,require函数支持第三种形式的路径,写法类似于foo/bar,并依次按照以下规则解析路径,直到找到模块位置。

内置模块

如果传递给 require 函数的是 NodeJS 内置模块名称,不做路径解析,直接返回内部模块的导出对象,例如 require('fs')。

node_modules 目录

NodeJS 定义了一个特殊的 node_modules 目录用于存放模块。例如某个模块的绝对路径是 /home/user/hello.js,在该模块中使用 require('foo/bar') 方式加载模块时,则 NodeJS 依次尝试使用以下路径。

/home/user/node_modules/foo/bar
 /home/node_modules/foo/bar
 /node_modules/foo/bar

NODE_PATH 环境变量

与 PATH 环境变量类似,NodeJS 允许通过 NODE_PATH 环境变量来指定额外的模块搜索路径。NODE_PATH 环境变量中包含一到多个目录路径,路径之间在 Linux 下使用:分隔,在 Windows 下使用;分隔。例如定义了以下 NODE_PATH 环境变量:

 NODE_PATH=/home/user/lib:/home/lib
当使用 require('foo/bar')的方式加载模块时,则 NodeJS 依次尝试以下路径。

/home/user/lib/foo/bar
 /home/lib/foo/bar

我们已经知道了 JS 模块的基本单位是单个 JS 文件,但复杂些的模块往往由多个子模块组成。为了便于管理和使用,我们可以把由多个子模块组成的大模块称做包,并把所有子模块放在同一个目录里。

在组成一个包的所有子模块中,需要有一个入口模块,入口模块的导出对象被作为包的导出对象。例如有以下目录结构。

- /home/user/lib/
  - cat/
    head.js
    body.js
    main.js

其中 cat 目录定义了一个包,其中包含了 3 个子模块。main.js 作为入口模块,其内容如下:

var head = require('./head');
var body = require('./body');

exports.create = function (name) {
  return {
    name: name,
    head: head.create(),
    body: body.create()
  };
};

在其它模块里使用包的时候,需要加载包的入口模块。接着上例,使用 require('/home/user/lib/cat/main')能达到目的,但是入口模块名称出现在路径里看上去不是个好主意。因此我们需要做点额外的工作,让包使用起来更像是单个模块。

index.js
当模块的文件名是 index.js,加载模块时可以使用模块所在目录的路径代替模块文件路径,因此接着上例,以下两条语句等价。

var cat = require('/home/user/lib/cat');
var cat = require('/home/user/lib/cat/index');

这样处理后,就只需要把包目录路径传递给 require 函数,感觉上整个目录被当作单个模块使用,更有整体感。

package.json
如果想自定义入口模块的文件名和存放位置,就需要在包目录下包含一个 package.json 文件,并在其中指定入口模块的路径。上例中的 cat 模块可以重构如下。

- /home/user/lib/
  - cat/
    + doc/
    - lib/
      head.js
      body.js
      main.js
    + tests/
    package.json

其中package.json内容如下。

{
  "name": "cat",
  "main": "./lib/main.js"
}

如此一来,就同样可以使用 require('/home/user/lib/cat')的方式加载模块。NodeJS 会根据包目录下的 package.json 找到入口模块所在位置。

Javascript 相关文章推荐
JavaScript插件化开发教程 (一)
Jan 27 Javascript
javascript模拟map输出与去除重复项的方法
Feb 09 Javascript
setTimeout内不支持jquery的选择器的解决方案
Apr 28 Javascript
JavaScript之创意时钟项目(实例讲解)
Oct 23 Javascript
基于openlayers4实现点的扩散效果
Aug 17 Javascript
React+Webpack快速上手指南(小结)
Aug 15 Javascript
Vue中的v-for指令不起效果的解决方法
Sep 27 Javascript
最简单的JS实现json转csv的方法
Jan 10 Javascript
解决layer 动态加载select 失效的问题
Sep 18 Javascript
React学习之受控组件与数据共享实例分析
Jan 06 Javascript
基于JS判断对象是否是数组
Jan 10 Javascript
JavaScript forEach中return失效问题解决方案
Jun 01 Javascript
javascript每日必学之基础入门
Feb 16 #Javascript
快速掌握Node.js环境的安装与运行方法
Feb 16 #Javascript
js实现异步循环实现代码
Feb 16 #Javascript
JavaScript实现跑马灯抽奖活动实例代码解析与优化(二)
Feb 16 #Javascript
JavaScript实现跑马灯抽奖活动实例代码解析与优化(一)
Feb 16 #Javascript
javascript HTML+CSS实现经典橙色导航菜单
Feb 16 #Javascript
JavaScript中使用数组方法汇总
Feb 16 #Javascript
You might like
php error_log 函数的使用
2009/04/13 PHP
php设计模式 Prototype (原型模式)代码
2011/06/26 PHP
跨浏览器PHP下载文件名中的中文乱码问题解决方法
2015/03/05 PHP
YII Framework框架教程之使用YIIC快速创建YII应用详解
2016/03/15 PHP
Yii 2.0实现联表查询加搜索分页的方法示例
2017/08/02 PHP
Laravel数据库读写分离配置的方法
2019/10/13 PHP
JS下高效拼装字符串的几种方法比较与测试代码
2010/04/15 Javascript
extjs中grid中嵌入动态combobox的应用
2011/01/01 Javascript
Javascript中定义方法的另类写法(批量定义js对象的方法)
2011/02/25 Javascript
js获取IFRAME当前的URL的方法
2013/11/13 Javascript
使用jQuery实现input数值增量和减量的方法
2015/01/24 Javascript
浅谈js中变量初始化
2015/02/03 Javascript
Javascript中的作用域和上下文深入理解
2015/07/03 Javascript
Form表单按回车自动提交表单的实现方法
2016/11/18 Javascript
AngularJS中$http使用的简单介绍
2017/03/17 Javascript
详解基于 axios 的 Vue 项目 http 请求优化
2017/09/04 Javascript
JS禁止浏览器右键查看元素或按F12审查元素自动关闭页面示例代码
2017/09/07 Javascript
Vue DevTools调试工具的使用
2017/12/05 Javascript
JS实现的将html转为pdf功能【基于浏览器端插件jsPDF】
2018/02/06 Javascript
[00:16]热血竞技场
2019/03/06 DOTA
[55:56]NB vs Infamous 2019国际邀请赛淘汰赛 败者组 BO3 第二场 8.22
2019/09/05 DOTA
Python字典的核心底层原理讲解
2019/01/24 Python
python创造虚拟环境方法总结
2019/03/04 Python
Python Pandas对缺失值的处理方法
2019/09/27 Python
python+pygame实现坦克大战小游戏的示例代码(可以自定义子弹速度)
2020/08/11 Python
浅谈Python 钉钉报警必备知识系统讲解
2020/08/17 Python
Python django框架 web端视频加密的实例详解
2020/11/20 Python
HTML5实现预览本地图片
2016/02/17 HTML / CSS
英国网上购买门:Direct Doors
2018/06/07 全球购物
意大利火车票和铁路通行证专家:ItaliaRail
2019/01/22 全球购物
高中生期末评语大全
2014/01/28 职场文书
2015秋季运动会通讯稿
2015/07/18 职场文书
导游词之南京汤山温泉
2019/11/26 职场文书
JS监听Esc 键触发事键
2021/04/14 Javascript
解析Java中的static关键字
2021/06/14 Java/Android
WCG2010 星际争霸决赛 Flash vs Goojila 1 星际经典比赛回顾
2022/04/01 星际争霸