解析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 相关文章推荐
写了一个layout,拖动条连贯,内容区可为iframe
Aug 19 Javascript
JavaScript前端图片加载管理器imagepool使用详解
Dec 29 Javascript
JS实现新浪博客左侧的Blog管理菜单效果代码
Oct 22 Javascript
jQuery+ajax简单实现文件上传的方法
Jun 03 Javascript
原生js获取iframe中dom元素--父子页面相互获取对方dom元素的方法
Aug 05 Javascript
jquery对象与DOM对象转化
Feb 08 Javascript
基于bootstrap按钮式下拉菜单组件的搜索建议插件
Mar 25 Javascript
ES6学习教程之对象的扩展详解
May 02 Javascript
angular.js中解决跨域问题的三种方式
Jul 12 Javascript
element-ui中的select下拉列表设置默认值方法
Aug 24 Javascript
angular4强制刷新视图的方法
Oct 09 Javascript
JSON的parse()方法介绍
Jan 31 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
咖啡的传说和历史
2021/03/03 新手入门
PHP脚本的10个技巧(8)
2006/10/09 PHP
PHP5 字符串处理函数大全
2010/03/23 PHP
深入解读php中关于抽象(abstract)类和抽象方法的问题分析
2014/01/03 PHP
PHP数字和字符串ID互转函数(类似优酷ID)
2014/06/30 PHP
PHP多进程编程总结(推荐)
2016/07/18 PHP
laravel框架实现后台登录、退出功能示例
2019/10/31 PHP
javascript 用记忆函数快速计算递归函数
2010/03/15 Javascript
jQuery实现点击标题输入详细信息
2013/04/16 Javascript
在线一元二次方程计算器实例(方程计算器在线计算)
2013/12/22 Javascript
解决jquery中动态新增的元素节点无法触发事件问题的两种方法
2015/10/30 Javascript
JavaScript小技巧整理
2015/12/30 Javascript
javascript简单进制转换实现方法
2016/11/24 Javascript
如何正确理解javascript的模块化
2017/03/02 Javascript
nodejs服务搭建教程 nodejs访问本地站点文件
2017/04/07 NodeJs
基于jQuery实现的单行公告活动轮播效果
2017/08/23 jQuery
详解Angular结合zTree异步加载节点数据
2018/01/20 Javascript
js中this的指向问题归纳总结
2018/11/28 Javascript
Vue 组件注册实例详解
2019/02/23 Javascript
JS解惑之Object中的key是有序的么
2019/05/06 Javascript
解决layer弹出层自适应页面大小的问题
2019/09/16 Javascript
vue学习笔记之slot插槽基本用法实例分析
2020/02/01 Javascript
[51:28]EG vs Mineski 2018国际邀请赛小组赛BO2 第一场 8.16
2018/08/16 DOTA
初学Python函数的笔记整理
2015/04/07 Python
Python实现的单向循环链表功能示例
2017/11/10 Python
对Pycharm创建py文件时自定义头部模板的方法详解
2019/02/12 Python
Jogun Shop中文官网:韩国知名时尚男装网站
2016/10/12 全球购物
eBay法国购物网站:eBay.fr
2017/10/21 全球购物
物理专业本科生自荐信
2014/01/30 职场文书
机电专业大学生职业规划书范文
2014/02/25 职场文书
小学竞选班长演讲稿
2014/09/09 职场文书
幼儿园小班个人总结
2015/02/12 职场文书
2015年物资管理工作总结
2015/05/20 职场文书
Redis如何一键部署脚本
2021/04/12 Redis
Python自动化爬取天眼查数据的实现
2021/06/15 Python
详解NumPy中的线性关系与数据修剪压缩
2022/05/25 Python