node的模块加载

2019-10-09  本文已影响0人  田成力

Node的模块加载

Node的REPL

R:读
E:eval计算
P:写
L:loop

console

标准流 1

function sun(a,b){
return a+b
}
console.assert(sum(1,2)==3,'报错')

console.dir()
//可以列出对象的的结构
console.trace();
//可以跟踪当前代码的调用栈
//程序执行从上往下执行,栈是先进后出

global全局对象

window里也有全局对象,但是不能直接访问,我们在浏览器里访问global是通过window实现的
1.global的变量是全局变量
2.所有的全局变量都是global的属性
console.log(global)
//chdir:改变目录
//cwd:当前工作目录

回顾 简易版的模块加载


  const fs = require('fs');
  const path = require('path');
  const vm = require('vm')



  class Module {
    constructor(filepath) {
      this.id = filepath;
      this.exports = {};
    }
    load() {
      //读取文件:
      let fileContent = fs.readFileSync(this.id, 'utf8');

      //包装文件
      fileContent = '(function(exports,module,require){' + fileContent + '})';
      let fn = vm.runInThisContext(fileContent);
      fn(this.exports, this, req);
      return this.exports;
    }
  }
  function req(filepath) {

    //文件的路径:
    let absolutepath = path.join(__dirname, filepath);

    let module = new Module(absolutepath);


    //加载模块
    return module.load();

  }

  const a = req('./a.js');
  console.log(a);//hello

升级版

添加对json的处理
添加缓存

    const fs = require('fs');
    const path = require('path');
    const vm = require('vm')

    const ModuleCache = {};
    class Module {
      constructor() {
        this.id = "";
        this.exports = {};
      }


      processFile() {
        return {
          ".js":(filepath)=> {
            let fileContent = fs.readFileSync(filepath, 'utf8');
            fileContent = `(function(module,exports,require,__filename,__dirname){${fileContent}})`;
            let fn = vm.runInThisContext(fileContent);
            fn(this, this.exports, req, filepath, path.dirname(filepath));
          },
          ".json":(filepath)=> {
            let fileContent = fs.readFileSync(filepath, 'utf8');
            this.exports = JSON.parse(fileContent);
          }
        }
      }


      load(filepath) {
        filepath = this.getFileAbsoultePath(filepath);
        this.id = filepath;
        //判断是否缓存过了
        if (ModuleCache[this.id]) {
          //加载过了
          return ModuleCache[this.id].exports;
        }
        let extname = path.extname(filepath);
        this.processFile()[extname](filepath);
        //添加缓存
        ModuleCache[this.id] = this;
        return this.exports;
      }

      getFileAbsoultePath(filepath) {
        //判断是否有后缀名
        //如果有直接使用
        //如果没有 匹配后缀
        if (filepath.indexOf('/') != 0) {
          //传入的是相对路径
          filepath = path.join(__dirname, filepath);
          console.log("filepath===>",filepath);
          
        }
        let extname = path.extname(filepath);
        if (!extname) {
          let canProcessExtnames = Reflect.ownKeys(this.processFile());
          for (let index = 0; index < canProcessExtnames.length; index++) {
            const currentExtname = canProcessExtnames[index];
            filepath += currentExtname;
            if (fs.existsSync(filepath)) {
              //找到文件了
              break;
            } else {
              filepath = null;
            }
          }
        } else {
          //自带了后缀名
          if (!fs.existsSync(filepath)) {
            throw new Error("not find file");
          }
        }
        if (filepath) {
          return filepath;
        }
        throw new Error('not find file')

      }
    }

    function req(filepath) {
      let module = new Module();
      return module.load(filepath);
    }

    const a = req("./a");
    console.log(a);//hello

exports 和 module.exports的关系


console.log(exports===module.exports);//true

// 实际上的形参 和实参 是这样的
let fn=function(module,exports,require,__filename,__dirname){xxxx}

fn(module,module.exports,require,xx,xx);

//可以看到 exports就是module的属性

//但问题是 为什么不能写成
//a.js文件

exports 'hello'

//根据关系我们可以模拟出下面的代码
var obj={arr:[1,2,3]}
var arr=obj.arr;
arr=[4,5,6]

// 这时候的arr和obj.arr还相同吗
// 我们用obj.arr能用到[4,5,6]吗

模块的加载顺序

文件模块

  1. 通过文件的路径找对应的文件 如果文件存在,则加载文件
  2. 如果文件不存在,则找同名文件夹/index.js文件

第三方模块

  1. 通过名称在自己的目录的node_modules中找对应的文件夹
  2. 找到该文件夹下的package.json文件中的main字段对应的文件加载文件
  3. 如果没有package.json 或是没有main字段,则会默认找文件夹下的index.js或index.json文件并加载
  4. 如果还找不到,则再向上一层查找node_modules文件夹

内置模块

  1. 通过名称引用 优先引用
上一篇 下一篇

猜你喜欢

热点阅读