2.开源脚手架lerna源码分析

开源脚手架lerna源码分析

学习目标

  • Lerna源码结构和执行流程分析
  • import-local源码深度精读

学习收获

  • 如何将源码分析的收获写进简历

  • 学习明星项目的架构设计

  • 获得脚手架执行流程的一种思路

  • 脚手架调试本地源码的另外一种方法

  • Nodejs加载node_modules模块的流程(罕见)

  • 各种文件操作算法和最佳实践

    学习建议:需要具备一定的Node基础

源码学习

1.准备源码

源码阅读准备完成的标准(重点):

  • 找到入口文件

  • 能够本地调试

    • 调试按钮:

      • Step Over 一行行向下执行

      • Step Into 进入到函数里面去执行

      • Step Out 跳出函数去执行

2.源码分析
  1. import-local库分析

    作用:当我们本地node_modules存在一个脚手架命令,同时全局在node_modules中也存在这个脚手架命令的时候,优先选用本地node_modules中的版本

last、知识点
  1. require(".")是什么意思?

    require("."),其实.就等同于./,代表当前目录,../就代表上一个目录,如果只有.,没有后面的文件,则默认文件是index.js

    所以,这里的require(",")就是require("./index.js")

  2. require是同步还是异步,require是编译执行还是运行时执行,import呢?

    require是编译时加载

  3. "@lerna/global-options":"file:../global-options"——package.json中存在这种依赖是什么意思?(重点,本地调试推荐使用)

    "dependencies": {
       @lerna/global-options":"file:../global-options"
    }
    

    这种写法代表加载的是本地的依赖,依赖的相对路径为../global-options这个包

    这种本地调试的方法,非常方便,不需要npm link****,但是需要install

    这种方法在本地调试可以使用,发布后,无法找到,lerna框架专门写了一个解析本地路径成远程库连接的方法来解决

  4. 如果一个函数的参数,使用的是反引号,那么可以不写括号,比如

    const dedent = require("dedent")
    console.log(dedent`   111
    111`)
    /*
        这里就相当于dedent(`   111
        111`)
    */
    
  5. require("process")可以不写require,两者等价

  6. constructor.name是什么?

    • 就是这个类的名称
    class Command{
        constructor(){
            console.log(this.constructor.name) // 
        }
    }
    new Command() // 这时候this.constructor.name就是"Command"
    
    class Command{
        constructor(){
            console.log(this.constructor.name)
        }
    }
    
    class ListCommand extends Command{
        
    }
    new ListCommand() // 这时候this.constructor.name就是"ListCommand"
    
  7. __filename__dirname的区别

    1. __filename当前文件的路径
    2. __dirname当前文件所在文件夹的路径
    3. path.dirname(文件或文件夹)文件或文件夹所在父级文件夹的路径
    4. 所以:path.dirname(__filename)等同于__dirname
  8. node加载一个模块的时候,会向node注入哪些变量?

    等同于:require一个模块的时候,会注入哪些变量?

    等同于:require源码有哪些变量?

    • 总共有5个?
      • module
      • require
      • __filename
      • __dirname
      • exports方法,因为要对外去输出
  9. module.exports暴露多个方法:

    // cwd.js
    module.exports = cwd => {}        // 暴露1
    module.exports.sync = cwd => {}   // 暴露2
    module.exports.dir = cwd => {}    // 暴露3
    
    • 使用:
    const findUp = require('cwd.js')
    findUp()      // 执行暴露1
    findUp.sync() // 执行暴露2
    findUp.dir(); // 执行暴露3
    
  10. path.resolve(a, b, c, ...)

    • 用于**当前路径cd命令的合并**,相当于先获取当前路径,然后cd a,再cd b,然后cd c,…,最终返回的是绝对路径最后一个是文件的话就拼起来
  11. path.join('/user','/yh','..')

    • 用于路径简单合并,相当于先将/user/yh合并成/user/yh,然后合并..对于这种点,用cd ..,那么结果就是/user
      • 练习path.join('/user','/yh','../a')结果是什么?
        • 答案:/user/a
  12. path.dirname(相对或绝对路径)

    • 用于获取父级目录
      • 如果是对相对路径处理,返回的是相对路径
      • 如果是对绝对路径处理,返回的是绝对路径
      • 总之:
        • 值是什么,去掉最后一级即可
        • 特殊:值为"…/“或”./“则结果为”."
  13. path.parse(路径)

    • 返回:
      • root 根路径
      • dir 父文件夹路径
      • base 最后一级路径
      • ext 后缀,文件有后缀,文件夹没后缀为空字符串
      • name 最后一级的文件名(不带后缀)或文件夹名
    • 举例:path.parse("/a/b/c.js")
      • 答案:{ root: '/', dir: '/a/b', base: 'c.js', ext: '.js', name: 'c' }
  14. fs.access(路径)fs.accessSync(路径)

    • 用于判断路径是否存在,这就可以判断文件或文件夹是否存在了

    • 举例:

      // 异步判断路径是否存在
      fs.access("./index.js", (err) => {
        console.log(err)
      })
      
      // 同步判断路径是否存在
      try {
        fs.accessSync("./index.js")
      } catch (err) {
        console.log(err)
      }
      
    • 同步的错误要用try{...}catch(err){...}捕获

  15. fs.exists(path, callback)fs.existsSync(path)

    1. access通用的效果
    2. 但是,异步方法fs.exists(path, callback)已经弃用,以后就不要再使用了。同步的还可以使用
    3. 总的来说,建议使用access方法
  16. 如果要判断路径是否存在,建议使用path-exists库,这个库会帮我们做维护,哪些方法弃用,哪些没弃用,会维护

  17. path.isAbsolute(路径)判断是否为绝对路径,返回布尔值

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值