Node.js 模块加载及包的管理
Posted YuLong~W
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Node.js 模块加载及包的管理相关的知识,希望对你有一定的参考价值。
文章目录
JavaScript开发弊端: javascript在使用时存在两大问题, 文件依赖 和 命名冲突
软件中的模块开发:
一个功能就是一个模块,多个模块可以组成完整应用,抽离一个模块不会影响其他功能的运行
Node.js模块系统
- Node.js规定一个 JavaScript文件 就是一个模块,模块内部定义的变量和函数默认情况下在外部无法得到
- 模块内部可以使用exports对象进行成员导出, 使用require方法导入其他模块
Node使用模块的原因:
- 将可重用代码封装在各种模块中,可以提高代码的利用率、可读性,减少程序的代码量
- 模块可以发布到npm仓库中,与他人实现代码的共享
- 根据实际开发的需求对外暴露模块的属性和方法
Node中模块的使用:
文件作用域:模块是独立的,在不同的文件使用必须要重新引用。 在node中没有全局作用域,它是文件模块作用域
- Node.js主要用于服务器端编程,无须考虑非同步加载的方式,选择CommonJS规范。
- 按照CommonJS规范要求,模块必须通过 module.exports对象 导出对外暴露的变量或接口,通过 require()方法 将其他模块的输出加载到当前模块作用域中。
- 在Node.js模块系统中,独立的模块有自己的作用域,其变量、方法等都是对其他文件不可见的。
- 典型的模块可以是一个包含exports对象属性定义的文件,可将 exports 看作是 module.exports 的 简单引用形式。通过在exports对象上指定额外的属性,可以将方法和对象等添加到模块的根部。
模块成员的导出:
// a.js
// 在模块内部定义变量
let version = 1.0;
// 在模块内部定义方法
const sayHi = name => console.log(name);
// 向模块外部导出数据
module.exports.version = version;
module.exports.sayHi = sayHi;
//也可简写:
//exports.version = version;
//exports.sayHi = sayHi;
模块成员的导入:
// b.js
// 在b.js模块中导入模块a
let a = require('./b.js');
// 输出b模块中的version变量
console.log(a.version);
// 调用b模块中的sayHi方法 并输出其返回值
console.log(a.sayHi('zhangsan'));
exports与module.exports的关系:
- exports在模块的文件级别作用域内有效,它在模块被执行前被赋予module.exports的值
- exports只是对module.exports的一个全局引用。
- 最终返回给调用程序,以module.exports为准
- NodeJs开发者建议导出 对象 用module.exports,导出 多个方法和变量 用exports
使用上的区别是:
- 使用 exports 导出的方法返回的是模块函数,可以直接调用
- 由module.exports 导出的方法返回的是一个类,需实例化为对象之后才可以调用
//用exports导出模块
exports.sayHello = function(name) {
console.log('你好!' + name);
};
//导入模块
var hello = require('./hello');
hello.sayHello('小王');
//用module.exports导出模块
function Hello(name) {
this.name = name;
this.sayHello = function() {
console.log('你好!' + this.name);
};
};
module.exports = Hello;
//导出类实例模块
var Hello = require('./hello');
hello = new Hello(); //此处需要实例化类
hello.setName('小张');
hello.sayHello();
核心模块
os 模块
Node.js的os模块提供一些 操作系统 相关的实用方法
const os=require('os');
console.log('操作系统类型:'+os.type());
console.log('操作系统平台:'+os.platform());
console.log('内存是:'+os.totalmem());
console.log('空闲内存是:'+os.freemem());
console.log('CPU:'+os.cpus());
util 模块
util模块主要用于支持Node.js内部API的需求。提供的大部分 实用工具 可用于应用程序与模块开发。
1、util.inspect(object[, options]) :返回对象的字符串表示,主要用于调试。以下代码用于查看util对象的所有属性:
const util = require('util');
console.log(util.inspect(util, { showHidden: true, depth: null }));
2、util.format(format[, …args]):返回一个格式化后的字符串
var str = util.format('%s: %s %d','陕西省','西安市',55);
console.log(str);
path 模块
提供了一些工具方法,用于处理文件与目录的路径
- path模块最大的用处是解决多平台目录路径问题
- path模块默认会根据Node.js应用程序运行的操作系统的不同而变化
- 要想在任何操作系统上处理Windows文件路径时获得一致的结果,可以使用path模块的path.win32属性
- Node.js在Windows系统上遵循单驱动器工作目录的理念。
const path=require('path');
console.log('Windows下的目录分隔符: '+path.delimiter);
console.log('Windows的路径分段分隔符: '+path.sep);
const url='F:\\\\Web前端\\\\class\\\\7.29\\\\demo1\\\\src\\\\input.txt';
console.log('路径的目录名是:'+path.dirname(url));
console.log('路径中最后一部分:'+path.basename(url));
console.log('文件名的后缀:'+path.extname(url));
console.log('完整路径的对象:'+path.parse(url));
var obj=path.parse(url);
console.log('路径对象转换为字符串:'+path.format(obj));
var s1='D:';
var s2='mydir';
var s3='logo.jpg';
console.log('路径的连接:'+path.join(s1,s2,s3));
url 模块
url模块提供了一些实用方法,用于URL处理与解析
url模块的两套API:
1、Node.js特有的API(传统的URL API)主要用于兼容已有应用程序。
- 先导入url模块,然后通过parse方法实现对地址的解析
const url=require('url');
const myUrl=url.parse('http://localhost:8000/index.html?username=张三&password=123456');
console.log(myUrl);
console.log('-------------------');
//将地址转换为字符串格式
str=myUrl.query;
console.log(str);
console.log('-------------------');
//对地址进行字符串切割
var temp=str.split('&');
console.log(temp);
console.log('-------------------');
var t1=temp[0].split('=');
console.log(t1);
url地址中的符号:
- ?:是请求地址与请求参数之间的分隔符
- &:参数之间的分隔符
2、新的应用程序应使用WHATWG API
- 先导入url模块中的URL类,将地址字符串作为参数传递给URL类的构造函数对地址进行解析
const { URL } = require('url');
const myurl = new URL('http://localhost:8080/index.html?username=张三&password=123456');
WHATWG API 的 URL类 提供的方法和属性:
URL类根据WHATWG URL标准实现。首先使用构造方法 new URL(input[, base])创建URL对象,然后使用URL类提供的属性和方法来进行操作。
属性 / 方法 | 解释 |
---|---|
url.protocol | 获取及设置URL的协议(protocol)部分。 |
url.host | 获取及设置URL的主机(host)部分,包括端口。 |
url.hostname | 获取及设置URL的主机名(hostname)部分。 |
url.port | 获取及设置URL的端口(port)部分。 |
url.pathname | 获取及设置URL的路径(path)部分。 |
url.search | 获取及设置URL的序列化查询(query)部分。 |
url.hash# | 获取及设置URL的hash部分。例如http://example.org/foo#bar。 |
url.href | 获取及设置序列化的URL,返回值与url.toString和url.toJSON的返回值相同。 |
url.toString() | 返回序列化的URL。 |
url.toJSON() | 返回序列化的URL,URL对象使用JSON.stringify()序列化时将自动调用该方法。 |
URLSearchParams类:提供解析url地址的字符串处理方法
searchParams是URLSearchParams类的对象,在该类中定义了方法get( ),用来获取查询字符串中的参数
const {URL}=require('url');
const myurl=new URL('http://localhost:8000/index.html?username=张三&password=123456');
console.log(myurl.searchParams.get('username'));
//输出: 张三
querystring 模块
提供一些实用方法用于解析与格式化URL查询字符串
1、querystring.parse(str[, sep[, eq[, options]]]) :将一个URL查询字符串解析成一个键值对的集合(相当于反序列化)
const queryString=require('querystring');
const myurl=new URL('http://localhost:8000/index.html?username=张三&password=123456');
const str=queryString.parse(myurl.search.substring(1,myurl.search.length-1)); //去掉? 截取子串
console.log(str);
2、querystring.stringify(obj[, sep[, eq[, options]]]) :将一个对象转换成URL查询字符串,是querystring.parse的逆运算。参数obj是要 序列化 成URL查询字符串的对象
const queryString=require('querystring');
var obj={
foo:'bar',
abc:['xyz','123']
}
var str=queryString.stringify(obj);
console.log(str);
3、querystring.unescape(str):用于对字符串进行解码,通常提供给querystring.parse()使用
4、querystring.escape(str) :用于对字符串进行URL编码,主要提供给querystring.stringify() 使用
第三方模块
第三方模块有两种存在形式:
- 以 js文件的形式 存在,提供实现项目具体功能的API接口
- 以 命令行工具形式 存在,辅助项目开发
获取第三方模块:
- npmjs.com:第三方模块的存储和分发仓库
- npm (Node Package Manager) :node的第三方模块管理工具,Node.js社区最流行、支持第三方模块最多的包管理器
Node.js包
别人写好的、具有特定功能的、我们能直接使用的模块即 第三方模块,由于第三方模块通常都是由多个文件组成并且被放置在一个文件夹中,所以又名 包 。
npm组成部分:
- Web网站:用来查找包、设置配置文件以及管理npm应用的其他方面,例如,可以为自己的公司设置公共或私有包的访问管理
- 命令行接口:包管理器,大多数开发人员会通过它来使用包
- 注册中心:提供JavaScript软件及其元数据信息的大型公共数据库,也就是官方仓库
理解:
包 是由 package.json文件 描述的一个文件或目录
模块 是由 Node.js的require()方法 加载的任何文件或目录
npm命令
1、升级npm:npm install npm -g
(-g 是安装参数,表示全局安装)
2、安装本地包:npm install 包名
3、确定安装包的版本(安装指定版本的包):npm install 包名@版本号
4、安装全局的包:npm install -g 包名
5、查看安装信息:
npm list
-->查看当前目录下已安装的包npm list -g
-->查看全局安装的包
package.json文件 的功能:
- 列举当前项目所依赖的包
- 指定当前项目所使用的包的版本
- 实现可重用的构建,更易于与其他开发人员分享包
6、创建默认的package.json:npm init --yes
包的使用环境:
7、安装在开发与测试环境下使用的包:npm install 包名 --save-dev
(会在package.json文件中加入"devDependencies"节点)
8、安装在生产环境中使用的包:npm install 包名
(会在package.json文件中加入"dependencies"节点)
9、包的更新(升级):
npm update 包名
-->升级当前目录下指定的包npm update -g 包名
-->升级全局的包
10、包的卸载:
3. npm uninstall 包名
-->卸载"dependencies"节点下的包(生产环境)
4. npm uninstall 包名 --save-dev
-->卸载"devDependencies"节点下的包(开发与测试环境)
5. npm uninstall -g 包名
–>卸载全局的包
11、清空npm的本地缓存: npm cache clean
12、发布自己开发的包:
- 在npm服务器上注册账号
- 使用
npm publish
发布
13、安装淘宝的npm镜像:在安装包时,用cnpm命令行工具代替npm
npm install -g cnpm --registry=https://registry.npm.taobao.org
nodemon 模块
在Node.js中,每次修改文件都要在命令行工具中重新执行该文件,非常繁琐
nodemon是一个命令行工具,用以辅助项目开发
使用步骤:
- 使用
npm install nodemon –g
下载它 - 在命令行工具中用 nodemon 命令替代node命令执行文件
nrm 模块
npm默认的下载地址在国外,国内下载速度慢
nrm ( npm registry manager ):npm 下载地址切换工具
使用步骤:
- 使用
npm install nrm –g
下载它 - 查询可用下载地址列表:
nrm ls
- 切换npm下载地址:
nrm use 下载地址名称
Gulp 模块
基于node平台开发的前端构建工具
将机械化操作编写成任务, 想要执行机械化操作时执行一个命令行命令任务就能自动执行,用机器代替手工,提高开发效率
Gulp模块使用步骤:
- 使用
npm install gulp
下载 gulp库文件 - 在项目根目录下建立 gulpfile.js文件
- 重构项目的文件夹结构,src目录放置源代码文件 ,dist目录放置构建后文件
- 在gulpfile.js文件中编写任务
- 在命令行工具中执行gulp任务
Gulp中提供的方法:
方法 | 解释 |
---|---|
gulp.src() | 获取任务要处理的文件 |
gulp.dest() | 输出文件 |
gulp.task() | 建立gulp任务 |
gulp.watch() | 监控文件的变化 |
Gulp插件:
插件 | 解释 |
---|---|
gulp-htmlmin | html文件压缩 |
gulp-csso | 压缩css |
gulp-babel | JavaScript语法转化 |
gulp-less | less语法转化 |
gulp-uglify | 压缩混淆JavaScript |
gulp-file-include | 公共文件包含 |
browsersync | 浏览器实时同步 |
代码示例:
const gulp = require('gulp');
const htmlmin = require('gulp-htmlmin');
const fileinclude = require('gulp-file-include');
const less = require('gulp-less');
const csso = require('gulp-csso');
const babel = require('gulp-babel');
const uglify = require('gulp-uglify');
// 使用gulp.task建立任务
// 1.任务的名称
// 2.任务的回调函数
gulp.task('first', () => {
console.log('我们人生中的第一个gulp任务执行了');
// 1.使用gulp.src获取要处理的文件
gulp.src('./src/css/base.css')
.pipe(gulp.dest('dist/css'));
});
// html任务
// 1.html文件中代码的压缩操作
// 2.抽取html文件中的公共代码
gulp.task('htmlmin', () => {
gulp.src('./src/*.html')
.pipe(fileinclude())
// 压缩html文件中的代码
.pipe(htmlmin({ collapseWhitespace: true })) //表示压缩空格
.pipe(gulp.dest('dist'));
});
// css任务
// 1.less语法转换
// 2.css代码压缩
gulp.task('cssmin', () => {
// 选择css目录下的所有less文件以及css文件
gulp.src(['./src/css/*.less', './src/css/*.css'])
// 将less语法转换为css语法
.pipe(less())
// 将css代码进行压缩
.pipe(csso())
// 将处理的结果进行输出
.pipe(gulp.dest('dist/css'))
});
// js任务
// 1.es6代码转换
// 2.代码压缩
gulp.task('jsmin', () => {
gulp.src('./src/js/*.js')
.pipe(babel({
// 它可以判断当前代码的运行环境 将代码转换为当前运行环境所支持的代码
presets: ['@babel/env']
}))
.pipe(uglify())
.pipe(gulp.dest('dist/js'))
});
// 复制文件夹
gulp.task('copy', () => {
gulp.src('./src/images/*')
.pipe(gulp.dest('dist/images'));
gulp.src('./src/lib/*')
.pipe(gulp.dest('dist/lib'))
});
// 构建任务
gulp.task('default', ['htmlmin', 'cssmin', 'jsmin', 'copy']);
package.json文件
node_modules文件夹的问题:
- 文件夹以及文件过多过碎,当我们将项目整体拷贝给别人的时候,,传输速度会很慢很慢
- 复杂的模块依赖关系需要被记录,确保模块的版本和当前保持一致,否则会导致当前项目运行报错
package.json文件的作用:
项目描述文件,记录了当前项目信息,例如项目名称、版本、作者、github地址、当前项目依赖了哪些第三方模块等。
使用npm init -y
命令生成
查找package.json文件:
注意: 在传输项目时,因为node_modules文件夹所占内存较大,因此不需要传输node_modules文件夹,接收者可通过package.json文件的记录项使用npm install下载当前项目所依赖的第三方模块。
项目依赖:
在项目的开发阶段和线上运营阶段,都需要依赖的第三方包,称为项目依赖
使用npm install 包名
命令下载的文件会默认被添加到 package.json 文件的 dependencies 字段 中
{
"dependencies": {
"jquery": "^3.3.1“
}
}
开发依赖:
在项目的开发阶段需要依赖,线上运营阶段不需要依赖的第三方包,称为开发依赖
使用npm install 包名 --save-dev
命令将包添加到package.json文件的 devDependencies字段 中
{
"devDependencies": {
"gulp": "^3.9.1“
}
}
package-lock.json文件的作用:
- 锁定包的版本,确保再次下载时不会因为包版本不同而产生问题
- 加快下载速度,因为该文件中已经记录了项目所依赖 第三方包的树状结构和包的下载地址,重新安装时只需下载即可,不需要做额外的工作
模块加载顺序
- 从缓存中加载
- 加载核心模块
- 加载文件模块
- 文件夹作为模块
(1)加载package.json文件指定的文件
(2)加载index.js文件
(3)加载index.node文件 - 从node_modules目录加载
- 从全局目录加载
- 循环加载
模块查找规则:
require('./find');
当模块 拥有路径但没有后缀 时:
- require方法根据模块路径查找模块,如果是完整路径,直接引入模块。
- 如果模块后缀省略,先找同名JS文件再找同名JS文件夹
- 如果找到了同名文件夹,找文件夹中的index.js
- 如果文件夹中没有index.js就会去当前文件夹中的package.json文件中查找main选项中的入口文件
- 如果找指定的入口文件不存在或者没有指定入口文件就会报错,模块没有被找到
require('find');
当模块 没有路径且没有后缀 时:
- Node.js会假设它是系统模块
- Node.js会去node_modules文件夹中
- 首先看是否有该名字的JS文件
- 再看是否有该名字的文件夹
- 如果是文件夹看里面是否有index.js
- 如果没有index.js查看该文件夹中的package.json中的main选项确定模块入口文件
- 否则找不到报错
以上是关于Node.js 模块加载及包的管理的主要内容,如果未能解决你的问题,请参考以下文章