-
模块化的好处
1.1什么是模块化?
模块化是指解决一个复杂问题时,自定向下逐层把系统划分成若干模块的过程。对于整个系统来说,模块是可组合、分解和更换的单元。
编程领域的模块化思想:
编程领域中的模块化,就是遵守固定的规则,把一个大文件拆成独立并相互依赖的多个小模块
把代码进行模块化拆分的好处:
- 提高了代码复用性
- 提高了代码的可维护性
- 可以实现按需加载
1.2模块化的规范
模块化规范就是对代码进行模块化拆分与组合事,需要遵守的那些规则
列如:
- 使用什么样的语法格式来引用模块
- 在模块中使用什么样的语法格斯向外暴露成员
模块化规范的好处:大家都遵守同样的莫夸化规范你写代码,降低了沟通的成本,极大方便了各模块之间的相互调用。
-
Node.js中模块的三大分类
Node.js中根据模块的来源不同,将模块分为了三大类,分别是:
- 内置模块(由node.js官方提供的,例如fspath、http等)
- 自定义模块(用户创建的.js的文件)
- 第三方模块(由第三方开发出来的模块,并非官方提供的内置模块,也不是用户创建的自定义模块,使用时需要提前下载)
2.1加载模块
使用require()方法,可以加载需要的内置模块、用户自定义模块、第三方模块进行调用。
// 1.加载内置的fs模块 const fs = require( 'fs ') // 2.加载用户的自定义模块 const custom = require( './ custom.js ') // 3.加载第三方模块 const moment = require( ' moment ' )
注:
- 使用require()方法加载其他模块时,会执行被加载模块中的代码。
- 在使用require()方法,可以不加后缀名
2.2模块作用域
和函数作用域类似,在自定义模块中定义的变量、方法等成员,只能在当前模块内被访问,这种模块级别的访问限制,叫做模块作用域
好处:
- 防止全局变量的污染
2.3向外共享模块作用域中成员
-
module.exports对象
const newObj ={ name:"lisi", getName:function(){ console.log("lisi") } } module.exports= newObj;
注意:
- 使用require()方法导入模块时,导入的结果,以最后module.exports指向的对象为准
3.exports对象
由于module.exports单词写起来比较复杂,为了简化向外共享成员的代码,Node 提供了exports对象。默认情况下,exports和module.exports指向的是同一个对象。最终共享的结果,还是以module.exports最后指向的对象为准。
module.exports.name = "zhangsan";
exports = {
age:18,
name:'lisi'
}
// 输出结果:{ name: 'zhangsan' }
注意:
-
为了防止混乱,建议大家不要在同一个模块中同时使用exports和module.exports
-
时刻记住,使用require()模块时,导入的永远是module.exporsts指向的对象
2.4Node.js中的模块化规范
Node.js遵循了CommonJS模块化规范,CommonJS规定了模块的特性和各模块之间如何相互依赖
-
CommonJS规定的内容
CommonJS规定:
- 每个模块内部,module变量代表当前模块。
- module变量是一个对象,它的exports属性(即module.exports)是对外的接口
- 加载某个模块,其实是加载该模块的module.exports属性。require()方法用于加载模块
-
npm与包
-
什么是包?
Node.js中的第三方模块又叫做包。不同于Node.js中的内置模块与自定义模块,包是由第三方个人或团队开发出来的,免费供所有人使用
Tip:
Node.js中的包都是免费且开源的,不需要付费即可下载使用 -
为什么需要包?
由于Node.js的内置模块仅提供了一些底层的API,导致在基于内置模块进行项目开发时的效率很低,包是基于内置模块封装出来的,提供了更高级、更方便的API,极大地提高了开发效率。包和内置模块之前的关系,类似于JQuery和浏览器内置API之间的关系
-
哪里下载包?
npm,lnc.公司旗下的包共享平台,它还提供了一个地址为https://registry.npmjs.org/的服务器,来共享所有的包,我们可以从这个服务器下载自己所需要的包
tips:
- 从https://www.npmjs.com/网站搜索自己所需要的包
- 从https://registry.npmjs.org/下载自己的包
-
如何下载包?
npm,lnc.公司提供了一个包管理工具,我们可以使用这个包管理工具,从https://registry.npmjs.org/服务器把需要的包下载到本地使用。
这个包管理工具的名字叫做Node Package Manager (简称npm包管理工具),这个包管理工具随着Node,js的安装包一起被安装到了用户的电脑上。
-
在项目中安装包的命令
npm install 完整的包名称
初次装包完成后,在项目文件夹下多一个叫做node_modules 的文件夹和package-lock.json 的配置文件。
node_modules 文件夹用来存放所有已安装到项目中的包。require()导入第三方包时,就是从这个目录中查找并加载包。
package-lockjson配置文件用来记录node modules目录下的每一个包的下载信息,例如包的名字、版本号、下载地址等。
默认情况下,使用npm install 命令安装包的时候,会自动安装最新的版本的包。如果需要安装指定版本的包,可以在包名之后,通过@符号指定具体版本
npm install moment @2.29.2
注:
不要手动修改node_modules或package-lock.json 文件中的代码,npm包管理工具跟自动维护它们 -
包管理配置文件
npm规定,在根目录中,必须提供一个叫做pakage.json的包管理配置文件。用来记录与项目有关的一些配置文件信息。
例如:
- 包的名称、版本号、描述等
- 项目中用到了那些包
- 哪些包只在开发期间会用到
- 哪些包在开发和部署时都会用到
-
多人协助开发问题
第三方包的体积过大,不方便团队成员之间共享项目源代码,只需要上传源代码。
在项目根目录中,创建一个叫做package.json 的配置文件,即可用来记录项目中安装了哪些包。从而方便剔除node_modules目录之后,在团队成员之间共享项目的源代码。
注意:
今后在项目开发中,一定要把 node_modules文件夹,添加到.gitignore忽略文件中。新建项目文件夹之后,快速创建package.json:
npm包管理工具提供了一个快捷命令,可以在执行命令是所处的目录中,快速创建package.json这个包管理配置文件
npm init -y
注意:
- 上述命令只能在英文的目录下成功运行!所以,项目文件的名称一定要用英文命名,不要使用中文,不能出现空格
- 运行npm install 命令安装包的时候,npm包管理工具会自动把包的名称和版本号,记录到package.json中
一次性安装剔除了node_module中的所有包:
npm install
执行npm install 命令时,npm包管理工具会先读取package.json中的devDependencies结点,读取到记录的所有依赖包名称和版本号之后,npm包管理工具会把这些包一次性下载到项目中
-
devDependencies结点与dependencies结点
package.json中,有一个dependencies结点,专门用来记录您使用的npm install 命令安装了哪些包
如果某些包旨在项目开发接单才会用到,项目上线之后不会用到,则建议吧这些包记录到devDependencies节点中。
与之对应的额,如果某些包在开发和项目上线之后都需要用到,则建议把这些包记录到dependencies结点
//安装指定的包,并记录到devDependencies结点中 npm i/install 包名 -D //等价于下面完整写法: npm install 包名 --save-dev
-
解决下载包速度慢的问题
淘宝npm镜像服务器:淘宝在国内搭建了一个服务器,专门把国外官方服务器上的包同步到国内的服务器,然后在国内提供下包的服务。从而极大的提高了下包的速度。
切换npm的下包镜像源:
#查看当前的下包镜像源 npm config get registry #将下包的镜像源切换为淘宝镜像源 npm config set registry=https://registry.npm.taobao.org/ #检查镜像源是否下载成功 npm config get registry
nrm工具:为了更方便的切换下包的镜像源,我们可以安装nrm这个小工具,利用nrm提供的终端命令,可以快速查看和切换下包的镜像源
如何安装nrm工具:
#通过npm 包管理器,将nrm安装为全局可用的工具 npm install nrm -g #查看所有可用的镜像源 nrm ls #将下包的镜像源切换为taobao镜像 nrm use taobao
-
卸载包
npm uninstall 包名
注:
npm uninstall 命令执行成功后,会把卸载的包,自动从package.json中的dependencies中移除
-
-
规范的包结构
开发自己的包
-
初始化package.json
{ "name": "module-tools", "version": "1.0.0", "main": "index.js", "description": "提供了格式化时间,HTMLEscape相关的功能", "keywords": [ "module-tools", "dateFormat", "escape" ], "license": "ISC" }
-
在index.js中定义自己的方法
// 这是包的入口文件 function dateFormat(dateStr) { const dt = new Date(dateStr); const y = dt.getFullYear(); const m = FixZero(dt.getMonth() + 1); const d = FixZero(dt.getDate()); const hh = FixZero(dt.getHours()); const mm = FixZero(dt.getMinutes()); const ss = FixZero(dt.getSeconds()); return `${y}-${m}-${d} ${hh}:${mm}:${ss}` } // 补零函数 function FixZero(n) { return n > 9 ? n : '0' + n; } // 向外暴露需要的成员 module.exports = { dateFormat }
-
将不同的功能进行模块化拆分
// 这是包的入口文件 const dateFormat = require("../module_tools/src/dateFormat") const escape = require("../module_tools/src/htmlEscape") // 向外暴露需要的成员 module.exports = { ...dateFormat,...escape }
-
编辑包的说明文档
包根目录中的README.md文件,是包的使用说明文档。通过它,我们可以事先把包的使用说明,以markdown的格式写出来,方便用户参考。
README文件中具体写什么内容,没有强制性的要求;只要能够清晰地把包的作用、用法、注意事项等描述清楚即可。例如上述例子包涵:
- 安装方式
- 导入方式
- 格式化时间//函数的使用方式
- 转义HTML中的特殊字符
- 还原HTML中的特殊字符
- 开源协议
-
发布包
1.注册npm账号
①访问https://www.npmjs.com/网站,点击 sign up按钮,进入注册用户界面 ②填写账号相关的信息:Full Name、Public Email、Username、Password
③点击Create an Account按钮,注册账号
④登录邮箱,点击验证链接,进行账号的验证
2.登录到本地npm
npm login
3.把包发布到npm 上
npm publish
将终端切换到包的根目录之后,运行npm publish 命令,即可将包发布到npm上(注:包名不能雷同)
4.删除已发布的包
npm unpublish 包名 --force
运行npm unpublish 包名 --force命令,即可从npm删除已发布的包
注:
- npm unpublish 命令只能删除72小时以内发布的包
- 通过npm unpublish 删除的包,在24小时以内不允许再重复发布
- 发布包的时候要慎重,尽量不要往npm上发布没有意义的包
-
-
模块的加载机制
6.1优先从缓存中加载
模块第一次加载后,会被缓存。因此多次调用require()不会导致模块的代码被执行多次。
tip:
无论是内置模块、用户自定义模块或是第三方模块,它们都会优先从缓存中加载,从而提高模块的加载效率。6.2内置模块的加载机制
内置模块是由Node.js官方提供给的模块,内置模块的加载优先级最高
6.3自定义模块的加载机制
使用require()加载自定义模块时,必须指定以**./或者…/开头的路径标识符。在加载自定义模块时,如果没有指定./或者…/这样的路径标识符,则Node会把它当做内置模块或第三方模块**进行加载。
同时在使用require()导入自定义模块时,如果省略了文件的拓展名,则Nod.js会按照顺序分别尝试加载以下类型的文件:
- 按照确切的文件名进行加载
- 补全.js 扩展名进行加载
- 补全.json扩展名进行加载
- 补全.node扩展名进行
- 加载加载失败,终端报错
6.4第三方模块的加载机制
如果传递给require()的模块的标识符不是一个内置模块,也没有以“./”或“…/”开头,则Node.js会从当前模块的父目录开始尝试,从/node_modules文件夹加载第三方模块
如果没有找到对应的第三方模块,则一定到再上一层父目录中,进行查找,直至找到文件系统的根目录。
6.5目录(文件夹)作为模块
当把目录(文件夹)作为模块标识符,传递给require()进行加载的时候,有三种加载方式:
①在被加载的目录下查找一个叫做package.json 的文件,并寻找main 属性,作为require(加载的入口
②如果目录里没有package.json文件,或者main入口不存在或无法解析,则Node.js将会试图加载目录下的index.js文件。
加载加载失败,终端报错
6.4第三方模块的加载机制
如果传递给require()的模块的标识符不是一个内置模块,也没有以“./”或“…/”开头,则Node.js会从当前模块的父目录开始尝试,从/node_modules文件夹加载第三方模块
如果没有找到对应的第三方模块,则一定到再上一层父目录中,进行查找,直至找到文件系统的根目录。
6.5目录(文件夹)作为模块
当把目录(文件夹)作为模块标识符,传递给require()进行加载的时候,有三种加载方式:
①在被加载的目录下查找一个叫做package.json 的文件,并寻找main 属性,作为require(加载的入口
②如果目录里没有package.json文件,或者main入口不存在或无法解析,则Node.js将会试图加载目录下的index.js文件。
③如果以上两步都失败了,则 Node.js 会在终端打印错误消息,报告模块的缺失: Error: Cannot find module ‘XXX’