首页
学习
活动
专区
圈层
工具
发布
50 篇文章
1
【架构师(第一篇)】整体需求分析和架构设计
2
【架构师(第二篇)】脚手架架构设计和框架搭建
3
【架构师(第三篇)】脚手架开发之掌握Lerna操作流程
4
【架构师(第四篇)】脚手架开发之Lerna源码分析
5
【架构师(第五篇)】脚手架之import-local执行流程及简历设计
6
【架构师(第六篇)】脚手架之需求分析和架构设计
7
【架构师(第七篇)】脚手架之准备阶段编写
8
【架构师(第八篇)】脚手架之 commander 框架使用方法
9
【架构师(第九篇)】如何让 Node 环境支持 ES Module
10
【架构师(第十篇)】脚手架之注册命令及架构优化
11
【架构师(第十一篇)】脚手架之命令注册和执行过程开发
12
【架构师(第十二篇)】脚手架之命令行交互工具 inquirer.js 使用方法
13
【架构师(第十三篇)】脚手架之创建项目准备阶段开发
14
【架构师(第十四篇)】脚手架之 egg.js 和 mongodb 的使用
15
【架构师(第十五篇)】脚手架之创建项目模板开发
16
【架构师(第十六篇)】脚手架之创建项目模板的下载与更新
17
【架构师(第十七篇)】脚手架之 ejs 和 glob 的使用
18
【架构师(第十八篇)】脚手架之项目模板的安装
19
【架构师(第十九篇)】脚手架之组件库模板开发
20
【架构师(第二十篇)】脚手架之自定义模板及第一阶段总结
21
【架构师(第二十一篇)】编辑器开发之需求分析和架构设计
22
【架构师(第二十二篇)】编辑器开发之项目整体搭建
23
【架构师(第二十三篇)】编辑器开发之画布区域组件的渲染
24
【架构师(第二十四篇)】编辑器开发之添加模版到画布
25
【架构师(第二十五篇)】编辑器开发之属性编辑区域表单渲染
26
【架构师(第二十六篇)】编辑器开发之属性编辑同步渲染
27
【架构师(第二十七篇)】前端单元测试框架 Jest 基础知识入门
28
【架构师(第二十八篇)】 测试工具 Vue-Test-Utils 基础语法
29
【架构师(第二十九篇)】Vue-Test-Utils 触发事件和异步请求
30
【架构师(第三十篇)】Vue-Test-Utils 全局组件和第三方库 vuex | vue-router
31
【架构师(第三十一篇)】前端测试之 TDD 的开发方式
32
【架构师(第三十二篇)】 通用上传组件开发及测试用例
33
【架构师(第三十三篇)】 Vue 中的实例及本地图片预览
34
【架构师(第三十四篇)】 业务组件库开发之 vue3 的插件系统
35
【架构师(第三十五篇)】 业务组件库开发之使用 Rollup 进行打包
36
【架构师(第三十六篇)】 业务组件库开发之发布到 NPM
37
【架构师(第三十七篇)】 服务端开发之后端框架与数据库技术选型
38
【架构师(第三十八篇)】 服务端开发之本地安装最新版 MySQL 数据库
39
【架构师(第三十九篇)】 服务端开发之连接 MySQL 数据库
40
【架构师(第四十篇)】 服务端开发之连接 Mongodb 数据库
41
【架构师(第四十一篇)】 服务端开发之安装并连接 Redis数据库
42
【架构师(第四十二篇)】 服务端开发之常用的登录鉴权方式
43
【架构师(第四十三篇)】 服务端开发之单元测试和接口测试
44
【架构师(第四十四篇)】 服务端开发之 pm2 和 nginx 介绍
45
【架构师(第四十五篇)】 服务端开发之认识 Github actions
46
【架构师(第四十六篇)】 服务端开发之安装 Docker
47
【架构师(第四十七篇)】 服务端开发之认识 Docker
48
【架构师(第四十八篇)】 服务端开发之 Dockerfile
49
【架构师(第四十九篇)】 服务端开发之认识 Docker-compose
50
【架构师(第五十篇)】 服务端开发之自动发布到测试机
清单首页架构文章详情

【架构师(第五篇)】脚手架之import-local执行流程及简历设计


import-local 执行流程

作用:当前项目中的 node_modules 中存在一个脚手架命令,和全局的 node 环境中也存在一个脚手架命令的时候,它会优先选用 node_modules 中的本地版本。

代码语言:javascript
复制
// core\lerna\cli.js

// 引入 import-local
const importLocal = require("import-local");

// 判断 importLocal(__filename) 为 true 的时候 会输出一行 log 
// 判断本地 `node_modules` 中是否存在脚手架
// __filename 就是当前文件所在的地址  D:\lerna-main\core\lerna\cli.js
if (importLocal(__filename)) {
  // 输出使用本地版本的log
  require("npmlog").info("cli", "using local version of lerna");
} else {
  require(".")(process.argv.slice(2));
}

查看 import-local 的源码,源码看起来并不是很多

代码语言:javascript
复制
// node_modules\import-local\index.js

const path = require('path');
const resolveCwd = require('resolve-cwd');
const pkgDir = require('pkg-dir');

module.exports = filename => {
  // filename 脚手架所在全局的执行文件
  // 获取脚手架所在的全局目录,包含 package.json 的目录
  // 如果当前模块嵌套比较深  会逐层向上找 找到包含 package.json的目录
  const globalDir = pkgDir.sync(path.dirname(filename)); 
  // 将 globalDir 和 filename 进行相对路径比较 得到最后的cli.js
  const relativePath = path.relative(globalDir, filename);
  // 将 globalDir 和 package.json 的路径进行合并 , 并拿到 package.json 文件的内容
  const pkg = require(path.join(globalDir, 'package.json'));
  // 将 pkg.name 和 relativePath 进行了合并 得到lerna/cli.js
  // 然后调用 resolveCwd 判断当前项目的本地有没有这个模块 返回本地模块所在的路径
  const localFile = resolveCwd.silent(path.join(pkg.name, relativePath));
  // 如果模块存在 加载模块 否则返回 null
  return localFile && path.relative(localFile, filename) !== '' ? require(localFile) : null;
};

可以看到 import-local 模块就是一个函数,当条件满足的时候,会先执行函数内部的 require(localFile),然后再返回来执行

代码语言:javascript
复制
require("npmlog").info("cli", "using local version of lerna");

那为什么 using local version of lerna 会在最前面打印出来呢,因为前一篇文章中提到,脚手架 command 内部的实现是利用了微任务队列,虽然先执行了 require(localFile),但是真正的执行逻辑都放在微任务队列里了,而 using local version of lerna 是宏任务最后的内容,所以会在执行宏任务的时候输出 log,然后再执行微任务队列里脚手架实际的业务逻辑代码。

基于 Lerna 设计简历

完全掌握本章以后可在简历中增加

注:第二周 4-12 ~ 4-18 没看懂,后面需要再复习一下,但是不影响主课程的进行

  • 熟悉 yargs 脚手架开发框架
  • 熟悉多 package 管理工具 lerna 的使用方法和实现原理
  • 深入理解 node.js 模块路径解析流程

如何使用 yargs 开发一个脚手架

先讲一下脚手架构成,以 vue-cli 为例,最基本的命令 vue create project --force

  • binpackage.json 中配置的 bin 属性,可以理解为主命令,也就是 vue,本地开发的时候通过 npm link 进行本地安装。
  • 需要在 bin 指向的文件,也就是脚手架的可执行文件中添加 #!/usr/bin/env node ,告诉操作系统在环境变量中查询 node,并通过 node 来执行此文件。
  • command:命令,也就是例子中的 create
  • param:参数,也就是例子中的 project
  • option:参数也可以携带选项,比如例子中的 --force

然后说一下脚手架初始化流程

  • 调用构造函数生成一个脚手架:Yargs()
  • 调用 yargs 常用方法,对脚手架的功能进行增强
    • Yargs.options
    • Yargs.group
    • ... ...
  • 解析脚手架的参数
    • 利用 yargs/helpers 提供的 hideBin ,调用 Yargs(hideBin(process.argv)).argv 完成解析
    • Yargs.parse(argv,options)
  • 注册脚手架命令
    • Yargs.command(command,describe,builder,handler)
    • Yargs.command({command,describe,builder,handler})

lerna 的实现原理是什么

lerna 是基于 git + npm 的多 package 项目管理工具

Lerna 的用法

  • Lerna init
  • Lerna create
  • Lerna add
  • Lerna link
  • ... ...

Lerna 的实现原理

  • 通过 import-local 优先调用本地 lerna 命令。
  • 通过 Yargs 生成脚手架,先注册全局属性,再注册命令,最后通过 parse 方法解析参数。
  • Lerna 命令注册时需要传入 builderhandler 两个参数,builder 方法用于注册命令专属的 optionshandler 用来处理命令的业务逻辑。
  • Lerna 通过配置 npm 本地依赖的方式来进行本地开发,具体写法是在 package.json 的依赖中写入:file:your-local-module-path,在 lerna publish 的时候会自动将改路径替换成线上路径。

node.js 模块路径解析流程

... ...loading

下一篇
举报
领券