CommonJs、Node.js 自定义模块、NPM 以及 package.json

CommonJs、Node.js 自定义模块、NPM 以及 package.json

十月 09, 2018

一、什么是 CommonJs?

JavaScript 有很多快速高效的解释器。然而,JavaScript 标准定义的 API 是为了构建基于浏览器的应用程序,并没有制定一个用于更广泛的应用程序的标准库。CommonJS 规范的提出主要是为了弥补当前 JavaScript 没有标准的缺陷。它的终极目标是提供一个类似于 Python、Ruby 和 Java 语言的标准库,而不只是停留在小脚本程序的阶段。用 CommonJS API 编写出的应用,不仅可以利用 JavaScript 开发客户端应用, 而且还可以编写以下应用:

  • 服务器端 Node.js 应用程序。
  • 命令行工具。
  • 桌面图形界面应用程序。
    CommonJS 就是模块化的标准,Node.js 就是 CommonJS 模块化的实现。Node 应用由模块组成,采用 CommonJS 模块规范。

二、Node.js 中的模块化

1. 在 Node 中,模块分为两类:

一类是 Node 提供的模块,称为核心模块;另一类是用户编写的模块,称为文件模块。

  • 核心模块部分在 Node 源代码的编译过程中编译进了二进制执行文件。在 Node 进程启动时,部分核心模块就被直接加载进了内存中,所以这部分核心模块引入时,文件定位和编译执行这两个步骤可以省略掉,并且在路径分析中优先判断,所以它的加载速度是最快的。比如 HTTP 模块、URL 模块、fs 模块都是 Node.js 内置的核心模块,可以直接引入使用。
  • 文件模块则是在运行时动态加载,需要完整的路径分析、文件定位、编译执行过程,速度相比核心模块稍微慢一些,但是用的非常多。些模块需要我们自己定义。

2. CommonJS (Node.js) 中自定义模块的规定:

  • 我们可以把公共的功能抽离成为一个单独的 js 文件作为一个模块,默认情况下这个模块里面的方法或者属性外面是没法访问的。如果要让外部可以访问模块里面的方法或者属性,就必须在模块里面通过 exports 或者 module.exports 暴露该属性或者方法。
  • 在需要使用这些模块的文件中,通过 require 的方式引入这个模块。这个时候就可以使用模块里面暴露的属性和方法。

3. 模块的定义与使用

比如定义一个 tools.js 的模块,如果这个模块不在当前目录里面,node会默认从node_modules文件夹里面寻找。
1

1
2
3
4
5
6
7
8
9
10
11
12
13
//模块定义
var tools = {
sayHello: function(){
return 'hello Node';
},
add: function(x,y){
return x + y;
}
};
// 模块接口的暴露
// module.exports = tools;
exports.sayHello = tools.sayHello;
exports.add = tools.add;
1
2
3
4
5
// 引入自定义的 tools.js 模块
var tools = require('./tools');

console.log(tools.sayHello()); //使用模块
console.log(tools.add(1,2));

三、包与NPM

1. 包

Node.js 中除了它自己提供的核心模块外,我们可以自定义模块,也可以使用第三方的模块。Nodejs 中第三方模块由包组成,可以通过包来对一组具有相互依赖关系的模块进行统一管理。完全符合 CommonJS 规范的包的目录一般包含如下这些文件:

  • package.json:包描述文件。
  • bin:用于存放可执行二进制文件的目录。
  • lib:用于存放 JavaScript 代码的目录。
  • doc:用于存放文档的目录。
    2

2. NPM介绍

npm 是世界上最大的开放源代码的生态系统。我们可以通过 npm 下载各种各样的包,这些源代码(包)我们可以在 https://www.npmjs.com 找到。npm 是随同 Node.js 一起安装的包管理工具,能解决 Node.js 代码部署上的很多问题,常见的使用场景有:

  • 允许用户从 NPM 服务器下载别人编写的第三方包到本地使用。
  • 允许用户从 NPM 服务器下载并安装别人编写的命令行程序(工具)到本地使用。(比如 supervisor)
  • 允许用户将自己编写的包或命令行程序上传到 NPM 服务器供别人使用。

3. NPM命令

1
2
3
4
5
6
npm -v  //查看 npm 版本
npm install ModuleName //使用 npm 命令安装模块
npm uninstall ModuleName //卸载模块
npm list //查看当前目录下已安装的包
npm info ModuleName //查看模块的版本
npm install jquery@1.8.0 //指定版本安装

四、package.json

每个项目的根目录下面,一般都有一个package.json文件,定义了这个项目所需要的各种模块,以及项目的配置信息(比如名称、版本、许可证等元数据)。在把项目发给别人时是不发 node_modules 文件夹的,但是可以通过 npm install 命令根据这个配置文件自动下载所需的模块,也就是配置项目所需的运行和开发环境。

我们每次使用 npm install xxx 都会把内容记录到 package.json 文件中,包都会发生变化,为了系统的稳定性考虑,每次执行完 npm install 之后会对应生成 package-lock 文件,该文件记录了上一次安装的具体的版本号。
当你执行 npm install 的时候,node 会先从 package.json 文件中读取所有 dependencies 信息,然后与 node_modules 中的模块进行对比,没有的直接下载,node 是从 package.json 文件读取模块名称,从 package-lock.json 文件中获取版本号,然后进行下载或者更新。

如果 package.json 与 package-lock.json 都不存在,执行 npm install 时 node 会重新生成 package-lock.json 文件,然后把 node_modules 中的模块信息全部记入 package-lock.json 文件,但不会生成 package.json 文件。我们可以通过 npm init –yes 来生成 package.json 文件。为了将模块写入 package.json,在安装模块时我们需要这么写:

1
2
npm install 模块 --save  //写入dependencies
npm install 模块 --save-dev //写入devDependencies

dependencies 与 devDependencies 的区别?

dependencie 配置当前程序所依赖的其他包。
devDependencie 配置当前程序所依赖的其他包,只会下载模块,而不下载这些模块的测试和文档框架
“dependencies”: {
“ejs”: “^2.3.4”,
“express”: “^4.13.3”,
“formidable”: “^1.0.17”
}
^表示第一位版本号不变,后面两位取最新的
~表示前两位不变,最后一个取最新
*表示全部取最新