4.2——Node.js的npm和包
创始人
2024-01-31 13:59:40
0

目录

  • 初识node.js
    • node.js的安装和查看版本
    • 使用node命令对js文件运行
    • 窗口的快捷键
  • fs 文件系统模块
    • fs.readFile() 方法
    • 写入文件fs.writeFile()
    • 案例——考试成绩整理
    • 路径问题
  • path 路径模块
    • 路径拼接path.join()
    • 获取路径中的文件名path.basename()
    • 获取路径中的文件扩展名path.extname()
    • 案例——时钟
  • http模块
    • 什么是 http 模块
    • 服务器相关的概念
    • 创建最基本的 web 服务器
    • req 请求对象和res 响应对象
    • 解决中文乱码问题
    • 根据不同的 url 响应不同的 html 内容
    • 案例——实现 clock 时钟的 web 服务器
  • 模块化
    • Node.js 中的模块作用域
    • 如何共享作用域成员
      • module.exports 对象
      • 共享成员时的注意点
      • exports 对象(重要理解)
    • exports 和 module.exports 的使用误区
    • Node.js 中的模块化规范
  • npm与包
    • 从哪里下载包
      • 格式化时间的传统做法
      • 格式化时间的高级做法
    • 在项目中安装包的命令
    • 包管理配置文件
    • 如何记录项目中安装了哪些包
    • dependencies 节点
    • 一次性安装所有的包npm install
    • 卸载包
    • devDependencies 节点
    • 解决下包速度慢的问题
    • nrm
    • 包的分类
    • 全局包
    • i5ting_toc
    • 规范的包结构
    • 自定义itheima包
    • 发布包
  • 模块的加载机制

资源链接写在前面:国外有一家 IT 公司,叫做 npm, Inc. 这家公司旗下有一个非常著名的网站: https://www.npmjs.com/ ,它是全球最大的包共享平台,你可以从这个网站上搜索到任何你需要的包,npm, Inc. 公司提供了一个地址为 https://registry.npmjs.org/ 的服务器,可以从这个服务器上下载自己所需要的包。

初识node.js

node.js的安装和查看版本

打开终端,在终端输入命令 node –v 后,按下回车键,即可查看已安装的 Node.js 的版本号。安装

使用node命令对js文件运行

node的运行,进入运行文件夹,右键+sheift点击“在此处打开Powershell窗口”,或者使用cmd进入到所需要运行的文件后使用命令 node test.js进行运行js。

窗口的快捷键

在 Windows 的 powershell 或 cmd 终端中,我们可以通过如下快捷键,来提高终端的操作效率:
① 使用 ↑ 键,可以快速定位到上一次执行的命令
② 使用 tab 键,能够快速补全路径
③ 使用 esc 键,能够快速清空当前已输入的命令
④ 输入 cls 命令,可以清空终端

fs 文件系统模块

fs 模块是 Node.js 官方提供的、用来操作文件的模块。它提供了一系列的方法和属性,用来满足用户对文件的操作需求。
例如:
⚫ fs.readFile() 方法,用来读取指定文件中的内容
⚫ fs.writeFile() 方法,用来向指定的文件中写入内容

fs.readFile() 方法

使用 fs.readFile() 方法,可以读取指定文件中的内容,语法格式如下:
在这里插入图片描述

参数解读:
⚫ 参数1:必选参数,字符串,表示文件的路径。
⚫ 参数2:可选参数,表示以什么编码格式来读取文件。
⚫ 参数3:必选参数,文件读取完成后,通过回调函数拿到读取的结果

  • fs读取示例JS代码:以 utf8 的编码格式,读取指定文件的内容,并打印 err 和 dataStr 的值
//导入fs模块,来操作文件
const fs = require('fs')
//2.调用fs.readFile()方法读取文件
//参数1:读取文件的存放路径
//参数2:读取文件时候采用的编码格式,一般默认指定 utf8
//参数3:回调函数,拿到读取失败和成功的结果 err dataStr
fs.readFile('../files/11.txt', 'utf8', function(err, dataStr){console.log(err)console.log('=====================')console.log(dataStr)
})

在这里插入图片描述

写入文件fs.writeFile()

使用 fs.writeFile() 方法,可以向指定的文件中写入内容,语法格式如下
在这里插入图片描述
参数解读:
⚫ 参数1:必选参数,需要指定一个文件路径的字符串,表示文件的存放路径。
⚫ 参数2:必选参数,表示要写入的内容。
⚫ 参数3:可选参数,表示以什么格式写入文件内容,默认值是 utf8。 ⚫ 参数4:必选参数,文件写入完成后的回调函数

  • fs文件系统写入例子
// 1. 导入 fs 文件系统模块
const fs = require('fs')// 2. 调用 fs.writeFile() 方法,写入文件的内容
//    参数1:表示文件的存放路径
//    参数2:表示要写入的内容
//    参数3:回调函数
fs.writeFile('../files/1.txt', 'okwrite', function(err) {// 2.1 如果文件写入成功,则 err 的值等于 null// 2.2 如果文件写入失败,则 err 的值等于一个 错误对象// console.log(err)if (err) {return console.log('文件写入失败!' + err.message)}console.log('文件写入成功!')
})

案例——考试成绩整理

如下面所示,读取成绩由横向重新写入另一个文件变成纵向且冒号分开

在这里插入图片描述
在这里插入图片描述

const fs = require('fs')fs.readFile('../files/score.txt','utf-8',function(err, dataStr){if(err){console.log('打开文件失败!')}console.log('打开文件成功!',dataStr)//把数据按照空格划分dataOld = dataStr.split(' ')newArr = []dataOld.forEach(item => {newArr.push(item.replace('=',':')) //把每一项的等于换成冒号})console.log(newArr)//把新的数据const newStr = newArr.join('\r\n') //表示数组每个元素按照换行进行分隔console.log(newStr)//存入文件fs.writeFile('../files/score_2.txt',newStr,function(err){if(err){console.log('存入数据失败'+err.message)}console.log('存入数据成功!')})})

在这里插入图片描述

路径问题

在使用 fs 模块操作文件时,如果提供的操作路径是以 ./ 或 …/ 开头的相对路径时,很容易出现路径动态拼接错误的问题。
原因:代码在运行的时候,会以执行 node 命令时所处的目录,动态拼接出被操作文件的完整路径。
解决方案:在使用 fs 模块操作文件时,直接提供完整的路径,不要提供 ./ 或 …/ 开头的相对路径,从而防止路径动态拼接的问题。

使用双下划线dirname表当前文件所在目录

console.log(__dirname + ‘/filename/score.txt’)

path 路径模块

path 模块是 Node.js 官方提供的、用来处理路径的模块。它提供了一系列的方法和属性,用来满足用户对路径的处理
需求。
例如:
⚫ path.join() 方法,用来将多个路径片段拼接成一个完整的路径字符串
⚫ path.basename() 方法,用来从路径字符串中,将文件名解析出来
如果要在 JavaScript 代码中,使用 path 模块来处理路径,则需要使用如下的方式先导入它:
在这里插入图片描述

路径拼接path.join()

使用 path.join() 方法,可以把多个路径片段拼接为完整的路径字符串
注意:今后凡是涉及到路径拼接的操作,都要使用 path.join() 方法进行处理。不要直接使用 + 进行字符串的拼接。
之前:fs.readFile(__dirname + ‘files/1.txt’)
在这里插入图片描述

获取路径中的文件名path.basename()

可以只获取到一长串路径的文件名以及除去后缀的文件名

//引入path模块
const path = require('path')const fpath = '/a/b/c/index.html'var filename = path.basename(fpath)
console.log(filename) //输出index.htmlvar nameWithoutExt = path.basename(fpath, '.html')
console.log(nameWithoutExt) //输出index

获取路径中的文件扩展名path.extname()

使用 path.extname() 方法,可以获取路径中的扩展名部分,语法格式如下:
在这里插入图片描述
参数解读:
⚫ path 必选参数,表示一个路径的字符串
⚫ 返回: 返回得到的扩展名字符串

//引入path模块
const path = require('path')
const fpath = '/a/b/c/index.html'
const fext = path.extname(fpath)
console.log(fext)  //输出 .html

案例——时钟

分离html中的css和js和html(其中html进行引用),最后index.html分成了index2.html引用index.css和index.js,并且index2.html能够正常运行。(可以使用任意的html文件,只要包含样式和JS做分离即可)

① 创建两个正则表达式,分别用来匹配 < style> 和 < script> 标签
② 使用 fs 模块,读取需要被处理的 HTML 文件
③ 自定义 resolveCSS 方法,来写入 index.css 样式文件
④ 自定义 resolveJS 方法,来写入 index.js 脚本文件
⑤ 自定义 resolveHTML 方法,来写入 index.html 文件

案例的两个注意点:

① fs.writeFile() 方法只能用来创建文件,不能用来创建路径(文件夹),也就是文件可以没有但是文件夹必须有
② 重复调用 fs.writeFile() 写入同一个文件,新写入的内容会覆盖之前的旧内容

//1.1导入fs模块
const fs = require('fs')//1.2导入path模块
const path = require('path')//1.3定义正则表达式,分别匹配标签const r1 = regStyle.exec(htmlStr) //正则式.exec(匹配字符串)//将提取出来的字符串去掉styleconst newCSS = r1[0].replace('','')//写进文件index.cssfs.writeFile(path.join(__dirname, '../sample_code/clock/index.css'),newCSS,function(err){if(err){console.log('写入失败!'+err.message)}console.log('写入css样式成功!')})
}function resolveJS(htmlStr){//使用正则提取页面中的标签const r2 = regScript.exec(htmlStr) //正则式.exec(匹配字符串)//将提取出来的字符串去掉styleconst newJS = r2[0].replace('','')//写进文件index.cssfs.writeFile(path.join(__dirname, '../sample_code/clock/index.js'),newJS,function(err){if(err){console.log('写入失败!'+err.message)}console.log('写入JS样式成功!')})
}//提取纯粹的html结构,不包含样式和脚本
function resolveHTML(htmlStr){//使用正则替换掉标签const newHTML = htmlStr.replace(regStyle,'').replace(regScript,'')//替换掉的html存入新的html文件fs.writeFile(path.join(__dirname,'../sample_code/clock/index2.html'),newHTML,err => {if(err) return console.log("存入html失败!",err.message)console.log("存入html成功!")})
}

http模块

什么是 http 模块

回顾:什么是客户端、什么是服务器?
在网络节点中,负责消费资源的电脑,叫做客户端;负责对外提供网络资源的电脑,叫做服务器。
http 模块是 Node.js 官方提供的、用来创建 web 服务器的模块。通过 http 模块提供的 http.createServer() 方法,就
能方便的把一台普通的电脑,变成一台 Web 服务器,从而对外提供 Web 资源服务。
如果要希望使用 http 模块创建 Web 服务器,则需要先导入它:
在这里插入图片描述
服务器和普通电脑的区别在于,服务器上安装了 web 服务器软件,例如:IIS、Apache 等。通过安装这些服务器软件,就能把一台普通的电脑变成一台 web 服务器。在 Node.js 中,我们不需要使用 IIS、Apache 等这些第三方 web 服务器软件。因为我们可以基于 Node.js 提供的http 模块,通过几行简单的代码,就能轻松的手写一个服务器软件,从而对外提供 web 服务。

服务器相关的概念

  • 域名和域名服务器
    尽管 IP 地址能够唯一地标记网络上的计算机,但IP地址是一长串数字,不直观,而且不便于记忆,于是人们又发明了另一套字符型的地址方案,即所谓的域名(Domain Name)地址。IP地址和域名是一一对应的关系,这份对应关系存放在一种叫做域名服务器(DNS,Domain name server)的电脑中。使用者只需通过好记的域名访问对应的服务器即可,对应的转换工作由域名服务器实现。因此,域名服务器就是提供 IP 地址和域名之间的转换服务的服务器。
    ① 单纯使用 IP 地址,互联网中的电脑也能够正常工作。但是有了域名的加持,能让互联网的世界变得更加方便。
    ② 在开发测试期间, 127.0.0.1 对应的域名是 localhost,它们都代表我们自己的这台电脑,在使用效果上没有任何区别

  • 端口号

计算机中的端口号,就好像是现实生活中的门牌号一样。通过门牌号,外卖小哥可以在整栋大楼众多的房间中,准确把外卖送到你的手中。① 每个端口号不能同时被多个 web 服务占用。② 在实际应用中,URL 中的 80 端口可以被省略。
默认是80端口,不是后面加上:端口号
在这里插入图片描述

创建最基本的 web 服务器

① 导入 http 模块
② 创建 web 服务器实例
③ 为服务器实例绑定 request 事件,监听客户端的请求
④ 启动服务器

//1.导入http模块
const http = require('http')//2.创建web服务器实例
const server = http.createServer()//3.为服务器实例绑定request事件,监听客户端的请求
server.on('request', function(req, res){console.log("Some one visit our web server!")
})//4.启动服务器
server.listen(8080, function(){console.log("server running at http://127.0.0.1:8080")//如果是80则可以省略:80
})

req 请求对象和res 响应对象

只要服务器接收到了客户端的请求,就会调用通过 server.on() 为服务器绑定的 request 事件处理函数。

req包含url和method,req.url是客户端请求的url地址;req.method是客户端请求的method类型;

res.end()方法:向客户端发生指定的内容,并结束这次请求的处理过程

//1.导入http模块
const http = require('http')//2.创建web服务器实例
const server = http.createServer()server.on('request', function(req, res){//req.url是客户端请求的url地址const url = req.url//req.method是客户端请求的method类型const method = req.methodconsole.log(`You request url is ${url},and request method is ${method}`)//端口号后面的地址//res.end()方法:向客户端发生指定的内容,并结束这次请求的处理过程str = `Your request url is ${url},and request method is ${method}`res.end(str)
})
server.listen(8080,function(){console.log("server is running at http://127.0.0.1:8080")
})

解决中文乱码问题

当调用 res.end() 方法,向客户端发送中文内容的时候,会出现乱码问题,此时,需要手动设置内容的编码格式:

server.on('request',(req, res) => {//发送的内容包含中文const str =`您请求的url 地址是 ${req.url},请求的method 类型是${req.method}`//l为了防止中文显示乱码的问题,需要设置响应头Content-Type 的值为 text/html;charset=utf-8res.setHeader('Content-Type', 'text/html; charset=utf-8 ')//把包含中文的内容,响应给客户端res.end(str)
})

根据不同的 url 响应不同的 html 内容

核心实现步骤
① 获取请求的 url 地址
② 设置默认的响应内容为 404 Not found
③ 判断用户请求的是否为 / 或 /index.html 首页
④ 判断用户请求的是否为 /about.html 关于页面
⑤ 设置 Content-Type 响应头,防止中文乱码
⑥ 使用 res.end() 把内容响应给客户端

const http = require('http')const server = http.createServer()server.on('request', function(req, res){// 1. 获取请求的 url 地址const url = req.url// 2. 设置默认的响应内容为 404 Not foundlet content = '

404 not found

'// 3. 判断用户请求的是否为 / 或 /index.html 首页if(url === '/' || url === '/index.html'){content = '

首页

'}// 4. 判断用户请求的是否为 /about.html 关于页面if(url === '/about.html'){content = '

关于页面

'}// 5. 设置 Content-Type 响应头,防止中文乱码res.setHeader('Content-Type','text/html; charset=utf-8')// 6. 使用 res.end() 把内容响应给客户端res.end(content) })server.listen(80, () => {console.log('server is runnig at http://127.0.0.1') })

案例——实现 clock 时钟的 web 服务器

//1.1导入http模块
const http = require('http')//1.2导入fs模块
const fs = require('fs')//1.3导入path模块
const path = require('path')//2.1创建 web 服务器
const server = http.createServer()//2.2监听web服务器的request事件
server.on('request', (req, res) => {//3.1获取到客户端请求的 url 地址//  /sample_code/clock/index.html//  /sample_code/clock/index.css//  /sample_code/clock/index.jsconst url = req.url//3.2把请求的 url 地址映射为具体文件的存放路径const fpath = path.join(__dirname, url)//4.1根据映射过来的文件路径读取文件的内容fs.readFile(fpath,'utf8',function(err, dataStr){//4.2读取失败,向客户端响应固定的"错误消息"if(err) return res.end('404 not found')//4.3读取成功,将读取成功的内容响应给客户端res.end(dataStr)})
})
//2.3启动服务器
server.listen(80, () => {console.log('server is running at http://127.0.0.1')
})

优化路径(使路径省略中间的),也就是帮用户的路径进行拼接

	//把3.2换了,重新拼接路径,减少中间let fpath = ''if(url === '/'){fpath = path.join(__dirname, './sample_code/clock/index.html')}else{//index.html,index.css, index.jsfpath = path.join(__dirname, '/sample_code/clock', url)}

模块化

模块化是指解决一个复杂问题时,自顶向下逐层把系统划分成若干模块的过程。对于整个系统来说,模块是可组
合、分解和更换的单元。

Node.js 中根据模块来源的不同,将模块分为了 3 大类,分别是:
⚫ 内置模块(内置模块是由 Node.js 官方提供的,例如 fs、path、http 等)
⚫ 自定义模块(用户创建的每个 .js 文件,都是自定义模块)
⚫ 第三方模块(由第三方开发出来的模块,并非官方提供的内置模块,也不是用户创建的自定义模块,使用前需要先下载)
使用强大的 require() 方法,可以加载需要的内置模块、用户自定义模块、第三方模块进行使用
在这里插入图片描述

注意:使用 require() 方法加载其它模块时,会执行被加载模块中的代码。只有用户自定义模块需要写的是路径,内部模块和第三方模块的都是差不多的写法。

在使用require加载用户自定义模块期间,可以省略.js的后缀名

Node.js 中的模块作用域

和函数作用域类似,在自定义模块中定义的变量、方法等成员,只能在当前模块内被访问,这种模块级别的访问限制,叫做模块作用域,防止了全局变量污染的问题
在这里插入图片描述
只会打印{},而非username
在这里插入图片描述

如何共享作用域成员

在每个 .js 自定义模块中都有一个 module 对象,它里面存储了和当前模块有关的信息,
在这里插入图片描述

module.exports 对象

1.在自定义模块中,可以使用 module.exports 对象,将模块内的成员共享出去,供外界使用。
2.外界用 require() 方法导入自定义模块时,得到的就是 module.exports 所指向的对象
在这里插入图片描述
结果如下,可以打印出来了

在这里插入图片描述

共享成员时的注意点

使用 require() 方法导入模块时,导入的结果,永远以 module.exports 指向的对象为准。
在这里插入图片描述

exports 对象(重要理解)

由于 module.exports 单词写起来比较复杂,为了简化向外共享成员的代码,Node 提供了 exports 对象。默认情况下,exports 和 module.exports 指向同一个对象。最终共享的结果,还是以 module.exports 指向的对象为准。(也就是上面的export可以代替module.export并且所指向的都一个对象)

  • exports 和 module.exports 指向同一个对象
    对于都是往{}里面添加,所以下面的exports换成module.exports写法都是一样的,输出会有三个
//向module.exorts对象上挂载username属性
exports.username = '张三'
//向module.exports对象上挂载sayHello方法
module.exports.sayHello = function(){console.log("Hello")
}
const age = 20
module.exports.age = age
  • 但是但是,注意区分,第一个最初module.exports和exports都指向了同一个对象{}里面添加了username属性,但是后来module.exports重新指定了一个对象,所以最终共享的结果,还是以 module.exports 指向的对象为准,也就是{ gender: ‘男’, age: 22 }
exports.username = 'zs' 
module.exports = {gender: '男',age: 22
}

exports 和 module.exports 的使用误区

时刻谨记,require() 模块时,得到的永远是 module.exports 指向的对象(可以画图,初始module.exports和exports都指向同一个对象,后面看有无新的对象{…}赋值)
在这里插入图片描述
为了防止混乱,建议大家不要在同一个模块中同时使用 exports 和 module.exports

Node.js 中的模块化规范

Node.js 遵循了 CommonJS 模块化规范,CommonJS 规定了模块的特性和各模块之间如何相互依赖。(其实前面已经用过了)
CommonJS 规定:
① 每个模块内部,module 变量代表当前模块。
② module 变量是一个对象,它的 exports 属性(即 module.exports)是对外的接口。 ③ 加载某个模块,其实是加载该模块的 module.exports 属性。require() 方法用于加载模块。

npm与包

Node.js 中的第三方模块又叫做包。Node.js 中的包都是免费且开源的,不需要付费即可免费下载使用。

从哪里下载包

国外有一家 IT 公司,叫做 npm, Inc. 这家公司旗下有一个非常著名的网站: https://www.npmjs.com/ ,它是全球最大的包共享平台,你可以从这个网站上搜索到任何你需要的包。他也提供了一个地址为 https://registry.npmjs.org/ 的服务器,来对外共享所有的包,我们可以从这个服务器上下载自己所需要的包。

也就是从第一个网站搜索自己所需要的包,从第二个服务器上下载自己所需要的包。

格式化时间的传统做法

//1.定义格式化时间的方法
function dataFormat(dataStr){const dt = new Date(dataStr)const y = dt.getFullYear()const m = padZero(dt.getMonth()+1)const d = padZero(dt.getDate())const hh = padZero(dt.getHours())const mm = padZero(dt.getMinutes())const ss = padZero(dt.getSeconds())return `${y}-${m}-${d} ${hh}:${mm}:${ss}`}//补零函数
function padZero(n){return n > 9 ? n : '0'+n
}//暴露的对象里面是一个函数
module.exports = {dataFormat
}
const TIME = require('./11dataFormat')const thisData = new Date()console.log(thisData)
console.log(TIME.dataFormat(thisData))//注意TIME是一个对象,dataFormat只是里面的一个方法,//2022-11-17T09:34:02.008Z
//2022-11-17 17:34:02

格式化时间的高级做法

① 使用 npm 包管理工具,在项目中安装格式化时间的包 moment
② 使用 require() 导入格式化时间的包
③ 参考 moment 的官方 API 文档对时间进行格式化

// 1.导入moment包
const moment = require('moment')
// 2.参考moment官方API文档,调用对应的方法,对时间进行格式化1/ 2.1调用moment()方法,得到当前的时间
// 2.2针对当前的时间,调用format()方法,按照指定的格式进行时间的格式化
const dt = moment().format('YYYY-MM-DD HH:mm:ss')
console.log(dt) //输出2020-01-12 17:23:48

进入网站https://www.npmjs.com/搜索包名找到精确匹配的一个进去后查看文档documentationhttps://momentjs.com/docs/,然后往下翻,可以看到告诉的安装和使用方法
在这里插入图片描述

在这里插入图片描述

一个M不补0,两个MM补零,其余同理
在这里插入图片描述

在项目中安装包的命令

下面两种方式都可以,第二种简写

npm install 包的名称
npm i 包的名称

初次装包完成后,在项目文件夹下多一个叫做 node_modules 的文件夹和package-lock.json 的配置文件。其中:
node_modules 文件夹用来存放所有已安装到项目中的包。require() 导入第三方包时,就是从这个目录中查找并加载包。
package-lock.json 配置文件用来记录 node_modules 目录下的每一个包的下载信息,例如包的名字、版本号、下载地址等。
注意:程序员不要手动修改 node_modules 或 package-lock.json 文件中的任何代码,npm 包管理工具会自动维护它们。

  • 安装指定版本的包
  • 默认情况下,使用 npm install 命令安装包的时候,会自动安装最新版本的包。如果需要安装指定版本的包,可以在包
    名之后,通过 @ 符号指定具体的版本,例如

npm i 包名@版本
npm i moment@2.22.2

包管理配置文件

npm 规定,在项目根目录中,必须提供一个叫做 package.json 的包管理配置文件。用来记录与项目有关的一些配置
信息。例如:
⚫ 项目的名称、版本号、描述等
⚫ 项目中都用到了哪些包
⚫ 哪些包只在开发期间会用到
⚫ 那些包在开发和部署时都需要用到

如何记录项目中安装了哪些包

在项目根目录中,创建一个叫做 package.json 的配置文件,即可用来记录项目中安装了哪些包。从而方便剔除node_modules 目录之后,在团队成员之间共享项目的源代码。注意:今后在项目开发中,一定要把 node_modules 文件夹,添加到 .gitignore 忽略文件中。

npm 包管理工具提供了一个快捷命令,可以在执行命令时所处的目录中,快速创建 package.json 这个包管理
配置文件:
在这里插入图片描述

① 上述命令只能在英文的目录下成功运行!所以,项目文件夹的名称一定要使用英文命名,不要使用中文,不能出现空格。
② 运行 npm install 命令安装包的时候,npm 包管理工具会自动把包的名称和版本号,记录到 package.json 中。

dependencies 节点

安装多个包的时候,可以使用空格来分隔

package.json 文件中,有一个 dependencies 节点,专门用来记录您使用 npm install 命令安装了哪些包(多个之间按照空格分隔)

一次性安装所有的包npm install

当我们拿到一个剔除了 node_modules 的项目之后,需要先把所有的包下载到项目中,才能将项目运行起来。只要package.json还在,里面有dependencies可以进行下载。可以运行 npm install 命令(或 npm i)一次性安装所有的依赖包:
在这里插入图片描述

否则无包会报类似于下面的错误:
在这里插入图片描述

卸载包

可以运行 npm uninstall 命令,来卸载指定的包。注意:npm uninstall 命令执行成功后,会把卸载的包,自动从 package.json 的 dependencies 中移除掉。

devDependencies 节点

如果某些包只在项目开发阶段会用到,在项目上线之后不会用到,则建议把这些包记录到 devDependencies 节点中。与之对应的,如果某些包在开发和项目上线之后都需要用到,则建议把这些包记录到 dependencies 节点中。
您可以使用如下的命令,将包记录到 devDependencies 节点中:
在这里插入图片描述

解决下包速度慢的问题

在使用 npm 下包的时候,默认从国外的 https://registry.npmjs.org/服务器进行下载,此时,网络数据的传输需要经
过漫长的海底光缆,因此下包速度会很慢。
在这里插入图片描述
默认是官方服务器npm config get registry
在这里插入图片描述
切换到淘宝的
npm config set registry=https://registry.npm.taobao.org/

nrm

为了更方便的切换下包的镜像源,我们可以安装 nrm 这个小工具,利用 nrm 提供的终端命令,可以快速查看和切换下
包的镜像源。
-g表示全局可用
在这里插入图片描述

包的分类

使用 npm 包管理工具下载的包,共分为两大类,分别是:
⚫ 项目包
⚫ 全局包

那些被安装到项目的 node_modules 目录中的包,都是项目包。
项目包又分为两类,分别是:
⚫ 开发依赖包(被记录到 devDependencies 节点中的包,只在开发期间会用到)
⚫ 核心依赖包(被记录到 dependencies 节点中的包,在开发期间和项目上线之后都会用到)

在这里插入图片描述

全局包

在执行 npm install 命令时,如果提供了 -g 参数,则会把包安装为全局包。
全局包会被安装到 C:\Users\用户目录\AppData\Roaming\npm\node_modules 目录下。
在这里插入图片描述
在这里插入图片描述

① 只有工具性质的包,才有全局安装的必要性。因为它们提供了好用的终端命令。
② 判断某个包是否需要全局安装后才能使用,可以参考官方提供的使用说明即可

i5ting_toc

i5ting_toc 是一个可以把 md 文档转为 html 页面的小工具,使用步骤如下
在这里插入图片描述

规范的包结构

在清楚了包的概念、以及如何下载和使用包之后,接下来,我们深入了解一下包的内部结构。
一个规范的包,它的组成结构,必须符合以下 3 点要求:
① 包必须以单独的目录而存在
② 包的顶级目录下要必须包含 package.json 这个包管理配置文件
③ package.json 中必须包含 name,version,main 这三个属性,分别代表包的名字、版本号、包的入口。
注意:以上 3 点要求是一个规范的包结构必须遵守的格式,关于更多的约束,可以参考如下网址:
https://yarnpkg.com/zh-Hans/docs/package-json

自定义itheima包

1.首先需要三个文件,index.js,package.json,README.md

① 新建 itheima-tools 文件夹,作为包的根目录
② 在 itheima-tools 文件夹中,新建如下三个文件:
⚫ package.json (包管理配置文件)
⚫ index.js (包的入口文件)
⚫ README.md (包的说明文档)
在这里插入图片描述

关于更多 license 许可协议相关的内容,可参考 https://www.jianshu.com/p/86251523e898

  • 在package.json中
{"name": "itheima-tools","version": "1.0.0","main": "index.js","description": "提供了格式化时间、HTMLEscape相关的功能","keywords": ["tiheima","dataFormat","escape"],"license": "ISC"
}
  • 在index.js中
//1.定义格式化时间的方法
function dataFormat(dataStr){const dt = new Date(dataStr)const y = dt.getFullYear()const m = padZero(dt.getMonth()+1)const d = padZero(dt.getDate())const hh = padZero(dt.getHours())const mm = padZero(dt.getMinutes())const ss = padZero(dt.getSeconds())return `${y}-${m}-${d} ${hh}:${mm}:${ss}`}//补零函数
function padZero(n){return n > 9 ? n : '0'+n
}//htmlEscap
function htmlEscape(htmlStr) {//正则表达式表示小于符号,大于符号,双引号,&符号,其中是或的关系,以及全局匹配greturn htmlStr.replace(/<|>|"|&/g,(match) => {switch(match){case '<':return '<'case '>':return '>'case '"':return '"'case '&':return '&'}})
}
//定义还原html字符串的函数
function htmlUnEscape(str){return str.replace(/<|>|"|&/g, (match) => {switch(match){case '<':return '<'case '>':return '>'case '"':return '"'case '&':return '&'}})}//暴露的对象里面是一个函数
module.exports = {data,escape,
}
  • 在测试js中
//测试包
const itheima = require('./itheima-tools/index')//测试时间格式
const thisData = new Date()
console.log(thisData)
console.log(itheima.dataFormat(thisData))//注意TIME是一个对象,dataFormat只是里面的一个方法,//转移html字符串,防止用户提交的时候变成一个干扰的
const htmlStr = '

这是h1标签123 

' htmlEscap = itheima.htmlEscape(htmlStr) console.log(htmlEscap)//还原html字符串 console.log(itheima.htmlUnEscap(htmlEscap))

在这里插入图片描述

  • 接着对上面的两个js进行封装进src文件中

在这里插入图片描述
js中除了对应的函数外还要暴露

module.exports = {htmlEscape,htmlUnEscape
}
module.exports = {dataFormat
}

使得index.js只包含引用和exports

const data = require('./src/dataFormat')
const escape = require('./src/htmlEscape')//暴露的对象里面是一个函数
module.exports = {...data,...escape,
}

测试的代码是没有变的

//和11传统的一样,测试包const itheima = require('./itheima-tools/index')//要不要index都一样//测试时间格式
const thisData = new Date()
console.log(thisData)
console.log(itheima.dataFormat(thisData))//注意TIME是一个对象,dataFormat只是里面的一个方法,
console.log('========================')//封装成src画个斜线区分,//转移html字符串,防止用户提交的时候变成一个干扰的
const htmlStr = '

这是h1标签123 

' htmlEscap = itheima.htmlEscape(htmlStr) console.log(htmlEscap) console.log('========================')//还原html字符串 // console.log(itheima.htmlUnEscap(htmlEscap)) // console.log('========================')

在这里插入图片描述

  • 最后编写README.md包的说明文档
    包根目录中的 README.md 文件,是包的使用说明文档。通过它,我们可以事先把包的使用说明,以 markdown 的格式写出来,方便用户参考。
    README 文件中具体写什么内容,没有强制性的要求;只要能够清晰地把包的作用、用法、注意事项等描述清楚即可。
    我们所创建的这个包的 README.md 文档中,会包含以下 6 项内容:安装方式、导入方式、格式化时间、转义 HTML 中的特殊字符、还原 HTML 中的特殊字符、开源协议
    在这里插入图片描述

发布包

  1. 注册 npm 账号
    ① 访问 https://www.npmjs.com/ 网站,点击 sign up 按钮,进入注册用户界面
    ② 填写账号相关的信息:Full Name、Public Email、Username、Password
    ③ 点击 Create an Account 按钮,注册账号
    ④ 登录邮箱,点击验证链接,进行账号的验证

  2. 登录 npm 账号
    npm 账号注册完成后,可以在终端中执行 npm login 命令,依次输入用户名、密码、邮箱后,即可登录成功。注意:在运行 npm login 命令之前,必须先把下包的服务器地址切换为 npm 的官方服务器。否则会导致发布包失败!(nrm npm即可切换到官网 ,查看是nrm ls)
    在这里插入图片描述

  3. 把包发布到 npm 上
    将终端切换到包的根目录之后,运行 npm publish 命令,即可将包发布到 npm 上(注意:包名不能雷同)。

在这里插入图片描述
4. 删除已发布的包
运行 npm unpublish 包名 --force 命令,即可从 npm 删除已发布的包。
在这里插入图片描述

注意:
① npm unpublish 命令只能删除 72 小时以内发布的包
② npm unpublish 删除的包,在 24 小时内不允许重复发布
③ 发布包的时候要慎重,尽量不要往 npm 上发布没有意义的包!

模块的加载机制

  1. 优先从缓存中加载
    模块在第一次加载后会被缓存。 这也意味着多次调用 require() 不会导致模块的代码被执行多次。注意:不论是内置模块、用户自定义模块、还是第三方模块,它们都会优先从缓存中加载,从而提高模块的加载效率。

  2. 内置模块的加载机制

内置模块是由 Node.js 官方提供的模块,内置模块的加载优先级最高。
例如,require(‘fs’) 始终返回内置的 fs 模块,即使在 node_modules 目录下有名字相同的包也叫做 fs。

  1. 自定义模块的加载机制

使用 require() 加载自定义模块时,必须指定以 ./ 或 ../ 开头的路径标识符。在加载自定义模块时,如果没有指定 ./ 或 …/ 这样的路径标识符,则 node 会把它当作内置模块或第三方模块进行加载。同时,在使用 require() 导入自定义模块时,如果省略了文件的扩展名,则 Node.js 会按顺序分别尝试加载以下的文件:
① 按照确切的文件名的文件进行加载
② 补全 .js 扩展名进行加载
③ 补全 .json 扩展名进行加载
④ 补全 .node 扩展名进行加载
⑤ 加载失败,终端报错

  1. 第三方模块的加载机制

如果传递给 require() 的模块标识符不是一个内置模块,也没有以 ‘./’ 或 ‘../’ 开头,则 Node.js 会从当前模块的父目录开始,尝试从 /node_modules 文件夹中加载第三方模块。如果没有找到对应的第三方模块,则移动到再上一层父目录中,进行加载,直到文件系统的根目录。
例如,假设在 ‘C:\Users\itheima\project\foo.js’ 文件里调用了 require(‘tools’),则 Node.js 会按以下顺序查找:
① C:\Users\itheima\project\node_modules\tools
② C:\Users\itheima\node_modules\tools
③ C:\Users\node_modules\tools
④ C:\node_modules\tools

  1. 目录作为模块

把目录作为模块标识符,传递给 require() 进行加载的时候,有三种加载方式(结合上面包不难理解,包的三个文件package.json和index.js,前者的main指向的一般是index.js但也可能不是):
① 在被加载的目录下查找一个叫做 package.json 的文件,并寻找 main 属性,作为 require() 加载的入口
② 如果目录里没有 package.json 文件,或者 main 入口不存在或无法解析,则 Node.js 将会试图加载目录下的 index.js 文件。 ③ 如果以上两步都失败了,则 Node.js 会在终端打印错误消息,报告模块的缺失:Error: Cannot find module ‘xxx’

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
一帆风顺二龙腾飞三阳开泰祝福语... 本篇文章极速百科给大家谈谈一帆风顺二龙腾飞三阳开泰祝福语,以及一帆风顺二龙腾飞三阳开泰祝福语结婚对应...
美团联名卡审核成功待激活(美团... 今天百科达人给各位分享美团联名卡审核成功待激活的知识,其中也会对美团联名卡审核未通过进行解释,如果能...