模块的查找
- 绝对路径
根据绝对路径直接加载模块,各种路径最终都会转换为绝对路径 - 相对路径 ./ 或 …/
- 相对于当前模块,会转换为当前路径加载模块
- 相对路径有一定的检查顺序
a. 检查是否是内置模块,如:fs、path等
b. 检查当前目录中的node_modules
c. 检查上级目录中的node_modules
d. 转换为绝对路径
e. 加载模块
- 关于后缀名
- 如果不提供后缀名,自动补全
- 顺序:js ->json ->node -> mjs
- 关于文件名
- 如果仅提供目录,不提供文件名,则自动寻找该目录中的index.js文件,顺序为:目录名.js ?->目录名.json ?-> 目录名.node ?-> 目录名.mjs ?-> 目录名/index.js
- package.json中的main字段
a. 表示包的默认入口,不会影响项目中的默认导入
b. 导入或执行包时若仅提供目录,则使用main补全入口
c. 默认值为index.js
module对象
记录当前模块的信息
<ref *1> Module {
//模块编号,以绝对路径作为id,如果是入口模块,id为'.'
id: 'C:\\Users\\lzh\\Desktop\\我的文件\\我的练习\\node\\node_modules\\abc\\index.js',
//输出模块的目录
path: 'C:\\Users\\lzh\\Desktop\\我的文件\\我的练习\\node\\node_modules\\abc',
exports: {},
//哪个模块在使用它
parent: Module {
//入口模块,id为'.'
id: '.',
path: 'C:\\Users\\lzh\\Desktop\\我的文件\\我的练习\\node',
exports: {},
parent: null,
//模块路径,绝对路径
filename: 'C:\\Users\\lzh\\Desktop\\我的文件\\我的练习\\node\\index.js',
//是否加载完成(打印的时候还在运行,所以为false)
loaded: false,
//子模块,Circular表示递归,循环引用
children: [ [Circular *1] ],
//如何去查找第三方库
paths: [
'C:\\Users\\lzh\\Desktop\\我的文件\\我的练习\\node\\node_modules',
'C:\\Users\\lzh\\Desktop\\我的文件\\我的练习\\node_modules',
'C:\\Users\\lzh\\Desktop\\我的文件\\node_modules',
'C:\\Users\\lzh\\Desktop\\node_modules',
'C:\\Users\\lzh\\node_modules',
'C:\\Users\\node_modules',
'C:\\node_modules'
]
},
filename: 'C:\\Users\\lzh\\Desktop\\我的文件\\我的练习\\node\\node_modules\\abc\\index.js',
loaded: false,
children: [],
paths: [
'C:\\Users\\lzh\\Desktop\\我的文件\\我的练习\\node\\node_modules\\abc\\node_modules',
'C:\\Users\\lzh\\Desktop\\我的文件\\我的练习\\node\\node_modules',
'C:\\Users\\lzh\\Desktop\\我的文件\\我的练习\\node_modules',
'C:\\Users\\lzh\\Desktop\\我的文件\\node_modules',
'C:\\Users\\lzh\\Desktop\\node_modules',
'C:\\Users\\lzh\\node_modules',
'C:\\Users\\node_modules',
'C:\\node_modules'
]
}
require函数
一般可能会用resolve方法,其他不太会用
[Function: require] {
//函数,可以将任意路径转换为绝对路径
resolve: [Function: resolve] { paths: [Function: paths] },
//主模块,入口起点所用模块
main: Module {
id: '.',
path: 'C:\\Users\\lzh\\Desktop\\我的文件\\我的练习\\node',
exports: {},
parent: null,
filename: 'C:\\Users\\lzh\\Desktop\\我的文件\\我的练习\\node\\index.js',
loaded: false,
children: [],
paths: [
'C:\\Users\\lzh\\Desktop\\我的文件\\我的练习\\node\\node_modules',
'C:\\Users\\lzh\\Desktop\\我的文件\\我的练习\\node_modules',
'C:\\Users\\lzh\\Desktop\\我的文件\\node_modules',
'C:\\Users\\lzh\\Desktop\\node_modules',
'C:\\Users\\lzh\\node_modules',
'C:\\Users\\node_modules',
'C:\\node_modules'
]
},
//扩展名的处理函数,没有会自动补全
extensions: [Object: null prototype] {
'.js': [Function (anonymous)],
'.json': [Function (anonymous)],
'.node': [Function (anonymous)]
},
//目前已经缓存的模块
cache: [Object: null prototype] {
'C:\\Users\\lzh\\Desktop\\我的文件\\我的练习\\node\\index.js': Module {
id: '.',
path: 'C:\\Users\\lzh\\Desktop\\我的文件\\我的练习\\node',
exports: {},
parent: null,
filename: 'C:\\Users\\lzh\\Desktop\\我的文件\\我的练习\\node\\index.js',
loaded: false,
children: [],
paths: [Array]
}
}
}
当执行一个模块或使用require时,会将模块放置在一个函数环境中
示例:
有一个文件,myModule.js文件,内容为
console.log("当前模块路径:", __dirname);
console.log("当前模块文件:", __filename);
exports.c = 3;
module.exports = {
a: 1,
b: 2
};
this.m = 5;
console.log(this === exports);
被require引入后,会将模块放置在一个函数环境中
//以下为伪代码示例
function require(modulePath){
//1. 将路径转换为绝对路径
//2. 判断是否有cache缓存
//3. 读取文件内容
//4. 将文件内容放置在一个函数中
//5. 创建module对象
}
function require(modulePath) {
//1. 将modulePath转换为绝对路径:D:\repository\NodeJS\源码\myModule.js
//2. 判断是否该模块已有缓存
if(require.cache["D:\\repository\\NodeJS\\源码\\myModule.js"]){
return require.cache["D:\\repository\\NodeJS\\源码\\myModule.js"].result;
}
//3. 读取文件内容
//4. 包裹到一个函数中
function __temp(module, exports, require, __dirname, __filename) {
console.log("当前模块路径:", __dirname);
console.log("当前模块文件:", __filename);
exports.c = 3;
module.exports = {
a: 1,
b: 2
};
this.m = 5;
}
//6. 创建module对象
module.exports = {};
const exports = module.exports;
__temp.call(module.exports, module, exports, require, module.path, module.filename)
return module.exports;
}