目录
Node.js 模块化
介绍
模块暴露数据
导入模块
导入模块的基本流程
CommonJS 规范
包管理工具
介绍
npm
cnpm
yarn
nvm的使用
我们上一篇文章介绍了Node.js中的http模块,这篇文章主要介绍Node.js的模块化,包管理工具以及nvm的使用。
在Node.js中模块化的概念是非常重要的,我们将一个复杂的程序文件拆分成多个文件的过程就是模块化,拆出来的每一个文件就是一个模块。模块的特点是它内部的数据是私有的,但是它可以通过向外面暴露数据来让其他的模块使用。一个项目在编码的过程中如果使用这种方式来进行那这个项目就是模块化项目。
模块化的好处可以让我们减少命名冲突的问题,当我们的程序都写在同一个文件中时,声明变量很容易造成命名冲突的问题,因此使用模块化可以在一定的程度上减少这种问题。其次是模块化具有高复用性,假设我们设计一个功能,然后在多个地方需要使用到它,我们就可以让该功能模块单独地放在一个文件中,直接进行调用即可,而不需要重复地编写相应的功能。最后就是高维护性,模块化也让后期的维护更加的容易轻松。
模块暴露数据的方式有两种:第一种是:module.exports = value 。第二种是使用:exports.name = value的方式。module.exports 可以暴露任意数据,比如对象,字符串或者数字等。
//me.js
function study(){
console.log('今天学习Node.js');
}
function play(){
console.log('今天摆烂');
}
//暴露数据方式一
module.exports={
study,
play
};
//暴露数据方式二
exports.study=study;
exports.play=play;
//index.js
//导入模块
const plan=require('./me.js');
plan.study();
plan.play();
以上为两个方式的暴露形式,需要注意的是不能使用 exports = value 的形式暴露数据。因为 exports = module.exports = {} ,require 返回的是目标模块中 module.exports 的值。因此假设我们直接编写exports=study,那么module.exports的值还是{},因此requir返回的值就是{}。若我们使用exports.study=study的方式进行暴露,此时,就会向{}中添加一个为study的属性,而module.exports与exports是执行的同一个地址,因此module.exports中就存在study,因此就可以成功进行暴露数据。
在模块中我们使用 require 传入文件路径即可引入文件。上面的代码我们也有进行导入的编写了。但是导入需要注意以下的一些事项:
1️⃣对于自己创建的模块,导入时路径建议写相对路径,且不能省略./和../。
2️⃣js和json文件导入时可以不写后缀,c/c++编写的node扩展文件也可以不写后缀,但是一般用不到。
3️⃣如果导入其他类型的文件,会以js文件进行处理。
4️⃣如果导入的路径是个文件夹,则会首先检测该文件夹下package.json文件中main属性对应的文件,如果存在则导入,反之如果文件不存在会报错。如果main属性不存在,或者package.json不存在,则会尝试导入文件夹下的index.js和index.json,如果还是没有找到,就会报错。
//创建一个path文件夹,文件夹里面创建一个package.json以及main.js文件。
//package.json
{
"main":"./main.js"
}
//main.js
module.exports='我是main文件';
//index.js
//导入模块
const plan=require('./page');
console.log(plan);//我是main文件
5️⃣导入node.js内置模块时,直接require模块的名字即可,无需加./和../。
Node.js导入模块的基本流程如下:首先它会对我们传入的文件路径转为绝对路径,定位目标文件。接着会进行缓存的检测,它会检测导入的文件是否之前有导入过,若该模块有相应的缓存,那它会直接返回对应的文件数据。若在缓存中检测不到对应的文件,它会对目标文件进行读取。接着执行一个函数,获取module.exports 的值。最后缓存模块,并将module.exports 的值返回。
function require(file){
//1.将相对路径转为绝对路径,定位目标文件
let absolutePath=path.resolve(__dirname,file);
//2.缓存检测
if(caches[absolutePath]){
return caches[absolutePath];
}
//3.读取文件的代码
let code=fs.readFileSync(absolutePath).toString();
//4.包裹为一个函数,然后执行
let module={};
let exports=module.exports={};
(function(exports,require,module,__filename,__dirname){
const test={
name:'N-A'
}
module.exports=test;
//输出
console.log(arguments.callee.toString());
})(exports,require,module,__filename,__dirname)
//5.缓存结果
caches[absolutePath]=module.exports;
}
const m=require('./me.js');
至于上面中间执行的函数如果查看呢?我们可以使用arguments.callee.toString() 查看自执行函数。
//show.js
const test={
name:'N-A'
}
module.exports=test;
console.log(arguments.callee.toString())
//输出结果
function (exports, require, module, __filename, __dirname) {
const test={
name:'N-A'
}
module.exports=test;
console.log(arguments.callee.toString())
}
最后介绍一下CommonJS规范,我们只需要知道:module.exports 、 exports 以及 require 这些都是 CommonJS 模块化规范中的内容。而 Node.js 是实现了 CommonJS 模块化规范,二者关系有点像 JavaScript 与 ECMAScript。
在介绍包管理工具之前,我们需要知道什么是包,包是代表一组特定功能的源码集合。简单理解就是包有很多的功能,我们如果需要实现什么功能我们可以使用对应的包。当我们使用包时,我们就需要使用到包管理工具,比如:npm、cnpm或者yarn。这些包管理工具可以对包进行下载安装、更新、删除以及上传等操作。它能够提高我们的开发效率。
npm 全称 Node Package Manager,它是 node.js 官方内置的包管理工具。在我们安装Node.js时,npm已经自动安装了npm,我们只需要在命令窗口通过npm -v查看相应的版本号即可,若有显示版本号即表示npm已经安装。
使用npm首先我们需要在将文件夹初始化为一个包,后续才能够正常地安装以及下载包。有两种方式可以进行初始化,第一种是直接输入npm init,然后进行交互式地进行创建。它会一步一步地引导你进行输入,若直接按回车它会使用默认的值。每个配置项的具体含义如下:
{
"name": "1-npm", #包的名字
"version": "1.0.0", #包的版本
"description": "", #包的描述
"main": "index.js", #包的入口文件
"scripts": { #脚本配置
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "", #作者
"license": "ISC" #开源证书
}
当我们完成操作时,文件夹下面会出现一个package.json文件,该文件为包的配置文件,每个包都必须要有package.json。第二种方式可以使用 npm init -y 或者 npm init --yes 极速创建 package.json。就不需要一步一步地按里面的问题来创建了。
但是在初始化的过程中还需要注意以下的一些事项:
1️⃣package name ( 包名 ) 不能使用中文、大写,默认值是 文件夹的名称 ,所以文件夹名称也不能使用中文和大写。
2️⃣version ( 版本号 )要求 x.x.x 的形式定义, x 必须是数字,默认值是 1.0.0。
3️⃣ISC 证书与 MIT 证书功能上是相同的,关于开源证书扩展阅读http://www.ruanyifeng.com/blog/2011/05/how_to_choose_free_software_licenses.html
4️⃣package.json 可以手动创建与修改。
那我们如果去寻找这些包呢?我们可以访问对应的网站去查找我们需要的包,并通过它的介绍去安装以及使用对应的包。
下载包我们可以通过 npm install 和 npm i 命令安装包。假设我们需要安装uniq(数组去重)这个包,我们就可以使用npm i uniq来进行安装。安装成功之后我们可以在文件夹下看到新增的两个资源,node_modules 文件夹:主要用于存放下载的包,以及package-lock.json为包的锁文件,用于锁定包的版本。
安装 uniq 之后, uniq 就是当前这个包的一个 依赖包 ,有时会简称为依赖。比如我们创建一个包名字为 A,A 中安装了包名字是 B,我们就说 B 是 A 的一个依赖包 ,也会说 A 依赖 B。
//我们编写一个index.js文件用于导入uniq包进行使用:
//导入包
const req=require('uniq');
let arr=[1,2,34,2,1,2,1]
console.log(req(arr));//[1,2,34]
require 导入 npm 包基本流程主要是:在当前文件夹下 node_modules 中寻找同名的文件夹。若找不到则在上级目录中下的node_modules中寻找同名的文件夹,直至找到磁盘根目录。
同时,在npm安装包时我们可以设置相应的依赖类型,主要有两个选项:生产依赖以及开发依赖。主要的命令形式如下表。当我们没有特意设置时都会默认地安装生产依赖。
类型 | 命令 | 补充 |
生产依赖 |
npm i -S uniq
npm i --save uniq
|
-S 等效于 --save , -S 是默认选项
包信息保存在 package.json 中 dependencies 属性
|
开发依赖 |
npm i -D less
npm i --save-dev less
|
-D 等效于 --save-dev
包信息保存在 package.json 中 devDependencies 属性
|
那我们如何判断安装的包应该属于生产依赖还是开发依赖呢?我们可以到相应的包安装文档里面进行查找,会有对应提示。或者自己进行判断,生产依赖是开发阶段以及后续的上线运行阶段都需要使用到的依赖包。而开发依赖只在开发阶段使用的依赖包。可以通过自己的需求来进行相应地设置。
同时在安装包的时候我们可以指定包相应的版本号,通过npm i <包名@版本号>。来选择相应的包版本号。当我们安装的包不需要时,我们可以使用npm r 包名或者npm remove 包名来进行包的删除。
上述我们提到的包安装都是局部的安装,除了局部安装我们还可以进行全局安装,使用npm i -g 包名即可进行全局地安装。进行全局安装的包可以在任意的位置进行访问运行,它不受工作目录的影响。我们以npm i -g nodemon为例,但我们全局安装了nodemon之后,我们就可以使用它来自动重启node应用程序了。在原本我们使用node index.js来运行文件当文件有修改的时候,需要重启,但是若使用nodemon index.js则可以自动地帮助我们重启服务。
但是我们直接输入会报错,我们需要修改一些配置。有两种方式:第一是是将我们终端的默认配置文件修改为Command Prompt。第二种是以管理员的身份打开powershell命令行,输入命令set-ExecutionPolicy remoteSigned并输入A,回车同样能够生效。
当我们在项目开发的阶段,我们需要将代码发送给队友时,我们不可能直接将我们整个项目给队友,因为我们下载了包,因此node_modules文件夹会特别地大。一般发送给队友之前我们都会将node_modules删除。之后队友拿到我们的代码时,它可以通过npm i这个命令来进行安装包依赖的下载。该命令会根据package.json以及package-lock.json的依赖声明安装依赖。
我们还可以配置 package.json 中的 scripts 属性来配置命令别名,让我们可以更简单的执行命令。配置完成之后,可以使用别名执行命令。例如:
{
.
.
.
"scripts": {
"server": "node server.js",
"start": "node index.js",
},
.
.
}
配置完成之后,可以使用别名执行命令。直接使用npm run server以及npm (run) start来进行运行。npm start一般用来启动项目。npm run 有自动向上级目录查找的特性,跟 require 函数也一样对于陌生的项目,我们可以通过查看 scripts 属性来参考项目的一些操作 。
当我们在使用npm下载包时,一般速度都会很慢,此时我们可以配置淘宝镜像来提高其下载的速度。可以直接使用npm config set registry https://registry.npmmirror.com/进行配置。或者使用nrm工具来进行配置,使用nrm来进行配置主要是可以更加简便地进行配置,不需要记住对应的配置地址,同时还可以进行切换。首先需要npm i -g nrm进行安装nrm,然后修改镜像nrm use taobao。最后通过npm config list命令来检查配置即可,若出现为https://registry.npmmirror.com/则表示配置成功。若想要切换为官网,直接使用nrm use npm即可。
我们还可以将自己开发的工具包发布到 npm 服务上,方便自己和其他开发者使用,操作步骤如下:1. 创建文件夹,并创建文件index.js, 在文件中声明函数,使用 module.exports 暴露。2. npm 初始化工具包,package.json 填写包的信息 。3. 注册账号 https://www.npmjs.com/signup 并 登录账号 。4. 若此时你的npm使用的是淘宝的镜像,需要修改为官方的官方镜像 (命令行中运行 nrm use npm ) 5. 命令行下 npm login 填写相关用户信息 。6. 命令行下 npm publish 提交包。包的下载以及使用步骤与其他的包一样。发布之后若想要对包进行更新,需要修改package.json文件中的版本号,使用npm publish发布更新。若你想要删除包我们可以使用:npm unpublish --foce来进行删除。
cnpm也是一个包管理工具,它的操作步骤与npm大体相同。cnpm 服务部署在国内阿里云服务器上, 因此相比于npm,cnpm包的下载速度更快。我们通过npm install -g cnpm --registry=https://registry.npmmirror.com来进行安装cnpm。它的操作命令都与npm相似,只是npm变成cnpm,其他的保持不变。
yarn 是由 Facebook 在 2016 年推出的新的 Javascript 包管理工具,官方网址。yarn的特点是速度快,安全性高以及可靠。但是在安装全局的依赖时,需要设置对应的path环境变量才能够进行使用。我们使用npm i -g yarn来进行安装yarn。它相应的命令如下表:
功能 | 命令 |
初始化 | yarn init / yarn init -y |
安装包 |
yarn add uniq 生产依赖
yarn add less --dev 开发依赖
yarn global add nodemon 全局安装
|
删除包 |
yarn remove uniq 删除项目依赖包
yarn global remove nodemon 全局删除包
|
安装项目依赖 | yarn |
运行命令别名 | yarn <别名> 不需要添加 run |
但是我们想要改变node.js的版本时,原本我们会先将自己安装的版本先卸载掉,然后再下载对应自己想要的版本。但是如果使用nvm,我们可以轻松地进行版本的安装、卸载以及切换。首先先下载 nvm 。找到 nvm-setup.exe 下载即可。此时需要确保先将电脑原本的Node.js先卸载掉,在安装nvm,不然后续无法进行版本的切换。
命令 |
说明
|
nvm list available | 显示所有可以下载的 Node.js 版本 |
nvm list |
显示已安装的版本
|
nvm install x.x.x | 安装 x.x.x 版本的 Node.js |
nvm install latest | 安装最新版的 Node.js |
nvm uninstall x.x.x | 删除某个版本的 Node.js |
nvm use x.x.x |
切换到 x.x.x 的 Node.js
|
好啦,本文就这里结束了!