nodejs 模块分类
- 核心模块|内置模块: fs buffer require("fs")
- 第三方模块 ejs commander 需要安装 require('ejs')
- 文件模块 必须要有./或绝对路径 自己写的 require(./../../xx)
如何调试nodejs代码
- 用vscode自带的功能
- node --inspect-brk 3.module.js 浏览器chrome://inspect 辅助调试
fs的模块 总有同步和异步
- fs.accessSync(//绝对路径) //判断文件是否存在
读写文件的操作一律使用绝对路径
- ______dirname 当前文件的工作目录
__filename 当前工作目录下的文件名 - path.resolve('a','a.js') // /users/xx/xxx/xxxx/a/a.js 项目目录拼接a/a.js 会解析出绝对路径
path.join('a','a.js') // a/a.js直接拼接如果参数有'/'不要用resolve
path.dirname() //取父路径
path.extname('a.js') // .js 返回文件后缀
手动实现一个require函数
- 加载模块 Module._load(文件名)
- 看一下当前这个模块有没有缓存过 有直接使用 无go on
- Module._resolveFilename 解析参数 把相对路径转化为一个绝对路径
- 通过路径创建一个模块 1) 文件名 ; 2) exports对象
- 将模块放到缓存中
- 加载模块 根据后缀名调用对应的方法 Module._extensions
- 读取文件
- 添加闭包
- 运行在沙箱环境中
const path = require('path')
const fs = require('fs')
const vm = require('vm')
function req(filepath) {
return Module.load(filepath)
}
Module.load = function (filepath) {
// 获得文件绝对路径
let finalPath = Module.resolveName(filepath)
if (finalPath) {
// 有缓存则返回缓存的exports
if (Module._cache[finalPath]) return Module._cache[finalPath].exports
// 新建一个模块
let module = new Module(finalPath)
Module._cache[finalPath] = module // 把模块放入缓存中
return module.load()
}
}
// 模块缓存
Module._cache = {}
function Module(id) {
this.id = id
this.exports = {}
}
Module.prototype.load = function () {
const extname = path.extname(this.id)
// 根据后缀名调用对应的文件加载方法
Module.extensions[extname](this) // 传入当前模块
return this.exports // 返回exports对象
}
Module.wrapper = ["(function(exports,module,require,__dirname,__filename){","\n})"]
Module.extensions = {
'.js'(module) {
let content = fs.readFileSync(module.id, 'utf-8') // 读取文件内容
console.log('content', content)
let scriptStr = Module.wrapper[0] + content + Module.wrapper[1] //放在自执行函数内
let fn = vm.runInThisContext(scriptStr) // 通过node虚拟机 在沙箱中 将函数字符串转化为真正可执行的函数
// console.log(fnStr.toString())
fn.call(module.exports,module.exports,module,req) // 传入实例,给实例this上的属性赋值
},
'.json'(module) {
const fileContent = fs.readFileSync(module.id,'utf-8')
console.log('content', fileContent)
module.exports = JSON.parse(fileContent) // 直接导出
}
}
Module.resolveName = function (pathname) {
const absPath = path.resolve(__dirname, pathname)
// console.log(absPath)
let finalPath = absPath
if (!path.extname(absPath)) {
// 当没有设置后缀的时候,从Module.extensions里去取来拼接
let has = Object.keys(Module.extensions).find(ele => {
finalPath = absPath + ele
// console.log('final', finalPath)
try {
fs.accessSync(finalPath)
return true
} catch (error) {
console.error(`不是${ele}的文件额`)
}
})
// 拼接完以后,没有找到
if (!has) {
finalPath = ''
throw new Error('文件不存在')
}
} else {
try {
fs.accessSync(finalPath)
} catch (error) {
final = ''
console.error(`文件不存在`)
}
}
return finalPath
}
let result = req('./useAtest')
console.log(result)