node系列:2、模块化

image

1、写在前面

为了统一 Javascript 在浏览器以外的实现,CommonJS 诞生了,CommonJS 试图定义一套普通应用程序使用的 API,从而填补 JavaScript 标准库过于简单的不足。 CommonJS 规范包括了模块、包、系统、控制台、文件系统、单元测试等部分。javascript

Node.js 是目前 CommonJS 规范最热门的一个实现,随着 CommonJS 规范的更新,Node.js 也在不断跟进 ,但 Node.js 并不彻底遵循 CommonJS 规范。这是全部规范制定者都会遇到的尴尬局面,由于规范的制定老是滞后于技术的发展。html

2、node模块化

模块(Module)和包(Package)是 Node.js 最重要的支柱,开发一个具备必定规模的程序不可能只用一个文件,一般须要把各个功能拆分、封装,而后组合起来,模块正是为了实现这种方式而诞生。

在浏览器 JavaScript 中,脚本模块的拆分和组合一般使用 HTML 的 script 标签来实现。Node.js 提供了 require 函数来调用其余模块,并且模块都是基于文件的,换句话说就是每一个文件都是一个模块,机制十分简单。java

模块类型

nodejs的模块能够分为两类,一类是核心模块,另外一类是文件模块。node

核心模块是 nodejs 官方提供的,node 进程启动时,部分核心模块就被直接加载进内存中, 因此这部分核心模块咱们就能够直接经过require 进行引入。好比 http 模块、url 模块、fs 模块等。git

const http = require('http'); // 内置模块直接引用
const host = '127.0.0.1';
const port = 3000;

const server = http.createServer((req,res) => {
    res.statusCode = 200;
    res.end('test1');
})

server.listen(port, host, () => {
    console.log(`服务器运行在 http://${host}:${port}/`)
})

文件模块是在运行时动态加载,须要完整的路径分析、文件定位、编译执行过程、速度相比核心模块稍微慢一些, 可是用的很是多。文件模块的加载方式有两种,一种是按路径加载,另外一种是查找node_modules文件夹。github

按路径加载模式express

// custom_module文件夹下的tools文件
function calculate(num) {
   return num*2
}
function getUrl(domain) {
    return `${domain}/wanwan0306`
}
module.exports = {
    calculate,
    getUrl
}

// app.js
const http = require('http');
const { calculate, getUrl } = require('./custom_module/tools');  // 按路径引入
const host = '127.0.0.1';
const port = 3100;

const server = http.createServer((req,res) => {
    const num = calculate(20);
    const url = getUrl('https');
    res.statusCode = 200;
    res.end(`${num}-${url}-test2`);
})

server.listen(port, host, () => {
    console.log(`服务器运行在 http://${host}:${port}/`)
})

node_modules文件夹加载模式npm

// node_modules文件夹下的tools文件
function calculate(num) {
   return num*2
}
function getUrl(domain) {
    return `${domain}/wanwan0306`
}
module.exports = {
    calculate,
    getUrl
}

// app.js
const http = require('http');
const { calculate, getUrl } = require('tools');  // node_modules
const host = '127.0.0.1';
const port = 3200;

const server = http.createServer((req,res) => {
    const num = calculate(20);
    const url = getUrl('https');
    res.statusCode = 200;
    res.end(`${num}-${url}-test3`);
})

server.listen(port, host, () => {
    console.log(`服务器运行在 http://${host}:${port}/`)
})

加载规则

1.若是 require 参数字符串以“/”开头,则表示加载的是一个位于绝对路径的模块文件, 好比,require('/future/Demo/NodeJs/2.模块化/custom_module/tools.js')将加载/future/Demo/NodeJs/2.模块化/custom_module/tools.jsjson

2.若是 require 参数以“ ./ ”或“ ../ ”开头,那么则以相对路径的方式来查找模块,这种方式在应用中是最多见的, 例如前面的例子中咱们用了require('./custom_module/tools')来加载;浏览器

3.若是require参数不以“ ./ ”或“ ../ ”开头,而该模块又不是核心模块,那么就要经过查找 node_modules 来加载模块了(使用npm获取的包一般就是以这种方式加载的);

举例来讲:脚本/future/Demo/NodeJs/2.模块化/app3.js执行了require('tools.js')命令,Node会依次搜索如下文件。

/usr/local/lib/node/tools.js
/future/Demo/NodeJs/2.模块化/node_modules/tools.js
/future/Demo/NodeJs/node_modules/tools.js
/future/node_modules/tools.js
/node_modules/tools.js

4.若是指定的模块文件没有后缀,Node 会尝试为文件名添加.js、.json、.node后,再去搜索。 .js 件会以文本格式的JavaScript 脚本文件解析,.json 文件会以 JSON 格式的文本文件解析,.node 文件会以编译后的二进制文件解析;

注意:核心模块拥有最高的加载优先级,换言之若是有模块与其命名冲突,Node.js 老是会加载核心模块。

加载缓存

Node.js 模块不会被重复加载,这是由于 Node.js 经过文件名缓存全部加载过的文件模块,因此之后再访问到时就不会从新加载了,注意,Node.js 是根据实际文件名缓存的,而不是 require() 提供的参数缓存的,也就是说即便你分别经过require('tools')require('./node_modules/tools') 加载两次,也不会重复加载,由于尽管两次参数不一样,解析到的文件倒是同一个。

包管理器:npm

npm官网https://www.npmjs.cn/

npm 是随同 NodeJS 一块儿安装的包管理工具,能解决 NodeJS 代码部署上的不少问题,常见的使用场景有如下几种:

  1. 容许用户从 npm 服务器下载别人编写的第三方包到本地使用。
  2. 容许用户从 npm 服务器下载并安装别人编写的命令行程序到本地使用。
  3. 容许用户将本身编写的包或命令行程序上传到NPM服务器供别人使用。

使用 npm 命令安装模块,使用使用语法以下

npm install express      // 本地安装
npm install express -g   // 全局安装

本地安装

  1. 将安装包放在 ./node_modules 下(运行 npm 命令时所在的目录),若是没有 node_modules 目录,会在当前执行 npm 命令的目录下生成 node_modules 目录。
  2. 能够经过 require() 来引入本地安装的包。

全局安装

  1. 将安装包放在 /usr/local 下或者你 node 的安装目录。
  2. 能够直接在命令行里使用。

package.json用于定义包的属性,接下来咱们来建立下:

$ npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.

See `npm help json` for definitive documentation on these fields
and exactly what they do.

Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
package name: (2.模块化) test  //模块名
version: (1.0.0) 
description: nodejs模块化demo  //项目描述
entry point: (app1.js) 
test command: 
git repository: 
keywords: 
author: wanwan
license: (ISC) 
About to write to /xx/package.json:

{
  "name": "test",
  "version": "1.0.0",
  "description": "nodejs模块化demo",
  "main": "app1.js",
  "dependencies": {
    "express": "^4.17.1"
  },
  "devDependencies": {},
  "scripts": {
    "test": "echo "Error: no test specified" && exit 1"
  },
  "author": "wanwan",
  "license": "ISC"
}


Is this OK? (yes) yes

npm经常使用指令

npm version 查看模块版本
npm help 查看某条命令的详细帮助
npm install 安装模块
npm uninstall 卸载模块
npm update 更新模块
npm outdated 检查模块是否已通过时
npm ls 查看安装的模块
npm init 在项目中引导建立一个package.json文件

4、参考资料

  1. Nodejs开发指南.pdf
  2. Node学习指南.pdf
  3. CommonJS规范 -- JavaScript 标准参考教程(alpha)

完整示例代码:https://github.com/wanwan0306/future/tree/master/Demo/NodeJs/2.模块化

相关文章
相关标签/搜索