解析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 相关文章推荐
JQuery为textarea添加maxlength属性的代码
Apr 07 Javascript
基于jquery打造的百分比动态色彩条插件
Sep 19 Javascript
js动态添加事件并可传参数示例代码
Oct 21 Javascript
JavaScript/Js脚本处理html元素的自定义属性解析(亲测兼容Firefox与IE)
Nov 25 Javascript
javascript实现简单的Map示例介绍
Dec 23 Javascript
Jquery 实现图片轮换
Jan 28 Javascript
JavaScript之数组(Array)详解
Apr 01 Javascript
微信小程序 视图层(xx.xml)和逻辑层(xx.js)详细介绍
Oct 13 Javascript
使用vue.js2.0 + ElementUI开发后台管理系统详细教程(二)
Jan 21 Javascript
bootstrap 下拉多选框进行多选传值问题代码分析
Feb 14 Javascript
JavaScript实现简单的双色球(实例讲解)
Jul 31 Javascript
javascript设计模式 ? 中介者模式原理与用法实例分析
Apr 20 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 采集书并合成txt格式的实现代码
2009/03/01 PHP
PHP分页函数代码(简单实用型)
2010/12/02 PHP
PHP安全性漫谈
2012/06/28 PHP
PHP Switch 语句之学习笔记
2013/09/21 PHP
php弹出对话框实现重定向代码
2014/01/23 PHP
php session的应用详细介绍
2017/03/22 PHP
Yii框架安装简明教程
2020/05/15 PHP
地震发生中逃生十大法则
2008/05/12 Javascript
jquery利用ajax调用后台方法实例
2013/08/23 Javascript
setInterval()和setTimeout()的用法和区别示例介绍
2013/11/17 Javascript
最新最热最实用的15个jQuery插件汇总
2015/07/05 Javascript
js简单网速测试方法完整实例
2015/12/15 Javascript
JS中的eval 为什么加括号
2016/04/13 Javascript
js格式化时间的简单实例
2016/11/27 Javascript
JS简单实现表格排序功能示例
2016/12/20 Javascript
bootstrap中的 form表单属性role="form"的作用详解
2017/01/20 Javascript
JSON 数据详解及实例代码分析
2017/01/20 Javascript
webpack配置文件和常用配置项介绍
2017/04/28 Javascript
Vue中使用webpack别名的方法实例详解
2018/06/19 Javascript
DatePickerDialog 自定义样式及使用全解
2019/07/09 Javascript
详解如何在Javascript中使用Object.freeze()
2020/10/18 Javascript
nuxt.js写项目时增加错误提示页面操作
2020/11/05 Javascript
Python验证码识别处理实例
2015/12/28 Python
python读取.mat文件的数据及实例代码
2019/07/12 Python
python GUI库图形界面开发之PyQt5切换按钮控件QPushButton详细使用方法与实例
2020/02/28 Python
python,Java,JavaScript实现indexOf
2020/09/09 Python
css3高级选择器使用方法
2013/12/02 HTML / CSS
浅谈CSS3 box-sizing 属性 有趣的盒模型
2019/04/02 HTML / CSS
夏威夷灵感服装及配饰:Reyn Spooner
2018/09/18 全球购物
Under Armour瑞典官方网站:美国高端运动科技品牌
2018/11/21 全球购物
法国发饰品牌:Alexandre De Paris
2018/12/04 全球购物
Skyscanner新西兰:全球领先的旅游搜索网站
2019/08/26 全球购物
UDP协议功能
2013/01/06 面试题
服装店营销方案
2014/03/10 职场文书
基层党员四风问题自我剖析材料
2014/09/29 职场文书
青年文明号创建口号大全
2015/12/25 职场文书