在命令行中输入kjl dev
之后的具体执行流程
首先,kjl是一个自定义的命令,那么如何自定义的命令呢?
自定义一个命令
- 在桌面上新建一个为lingwu的文件
touch lingwu.js
在文件写写入console.log('lingwu');
- 再来查看一下文件的具体信息
看用红框圈住的@符号之前的一串字符-rw-r--r--
可以忽略掉第一个字符-
(表示文件类型),然后就剩下9个字符rw-r--r--
,其实这9个字符没3个是一个组,分别对应于当前用户、当前用户所在的组,其他用户对该文件的执行权限
r
:表示对该文件有r (read)
的权限w
:表示对该文件有w (weite)
的权限x
:表示对文件有执行的权限
对于lingwu
这个文:-rw-r--r--
- 第一个字符表示文件类型
- 接下来3个字符是rw-,表示该文件对于当前用户的权限是r/w,即当前用户能对111.txt读、写,但是不能执行,所以执行权限块是-,表示没有执行权限。
- 再接下来3个字符是r–,表示该文件对于当前用户所在的组的成员来说,只能执行读,写和执行都是无权限的。
- 最后3个字符是r–,表示该文件对于其他用户来说也是只能读,不能写和执行。
现在这个文件不是一个可执行文件,那么如何将它变成可执行的呢?
- 修改文件的权限
- 修改权限的命令格式 chmod <权限范围><权限操作><具体权限> 具体文件具体权限>权限操作>权限范围>
- 权限范围
u:User,
即文件或目录的拥有者。g:Group,
即文件或目录的所属群组。o:Other,
除了文件或目录拥有者或所属群组之外,其他用户皆属于这个范围。a:All,
即全部的用户,包含拥有者,所属群组以及其他用户。 - . 权限操作
+:
表示增加权限-:
表示取消权限=:
表示唯一设定权限 - 具体权限
r:
表示可读取 ` w:可写入
x :`表示可执行
执行一下修改文件的命令
可以这个文件多了一个x权限
如何成为一个可执行命令
前提是在每个需要被执行文件的第一行加入
#!/usr/bin/env node
,即为文件提供可执行环境#!/usr/bin/env node console.log('lingwu');
(1)是否是绝对路径/相对路径
第一个命令是个相对路径,即在当前目录下面有lingwu.js
这个文件,故可以执行成功,第一个报错,找不到该文件,那么我们如何直接输入文件名就可以执行这个文件呢?答案就是这个命令是否是个环境变量
(2)是否是别名
我们在使用git的时候,一般可以用g来表示git,那么g就是git的别名
(3)是否是环境变量
如何将命令添加到环境变量里面呢?
建立软链接
建立软链接之后,再输入lingwu
就不会报错了
到这里,我们就自定义了一个叫做lingwu
的命令
代码流程
当我们在kjl-site
根目录下面输入kjl dev
时,首先会去找到kjl
命令所对应的可执行文件,即/usr/local/bin/node_modules/@qunhe/def-cli/bin/kjl.js
kjl.js
#!/usr/bin/env node
require('../lib/main')();
该文件中只有2行代码
- 第一行是为该文件指定编译环境,即node
- 第二行是引入
../lib/main
导出的函数,并执行,所以核心代码都在../lib/main.js
中
核心步骤 (1)引入外部依赖、全局配置和工具函数utils
// 引入外部依赖、全局配置、工具函数
const injects = require('./injects');
let config = require('./config');
const {
pkgUp,
program,
path
} = injects;
const utils = await require('./prepareUtils')(config, injects);
logger = utils.logger;
(2)在执行kjl
命令的目录下面找到package.json
,因为我是在kjl-site
的根目录下执行的kjl dev
,所以找到的package.json
就是kjl-site
根目录下面的package.json
const pkgPath = pkgUp.sync();
const lg = logger.getLogger();
let workspace;
if (pkgPath) {
workspace = path.dirname(pkgPath);
lg.info(`当前工作空间为:${workspace}`);
} else {
workspace = process.cwd();
lg.info('没有在工程目录下执行命令, package.json 文件不存在');
}
(3)初始化cli
const ctx = await require(path.join(toolRoot, 'lib/initCli'))(config, injects, utils);
- 检查版本
lib/middlewares/checkNodeVersion
- 将
def-cli
的版本和套件信息添加到全局配置中lib/middlewares/initial
const path = require('path'); module.exports = async (config, injects, utils) => { return { async value (ctx, next) { const { toolRoot } = config; const { program, getTemplateInfo } = injects; ctx.commands = []; const pkg = require(path.join(toolRoot, 'package.json')); program.version(pkg.version); config.version = pkg.version; config.templateInfo = getTemplateInfo(config); ctx.toolInfo = require(path.join(toolRoot, 'package.json')); await next(); } }; };
getTemplateInfo.js
```javascript const path = require(‘path’);
module.exports = ({ workspace, // 工作区间,在你成功执行kjl dev命令的目录 templatesRoot //套件所在的目录,在home目录下面的kjl-templates }) => { let templateInfo; try { templateInfo = require(path.join(workspace, ‘package.json’))[‘kjl-template’]; } catch (e) { templateInfo = undefined; }
// 如果套件存在的话,那套件所在的目录就是在/kjl-templates/node_modules/@qunhe/kjl-template_${templateInfo.name}
if (templateInfo && templateInfo.name) {
const templateRoot = path.join(templatesRoot, `node_modules/@qunhe/kjl-template_${templateInfo.name}`);
templateInfo.templateRoot = templateRoot;
}
return templateInfo; }; ``` * 判断套件是否已经安装 `lib/middlewares/ensureTemplate`,就是判断全局配置中的templateInfo && templateInfo.name是否存在,temolateInfo在上一步已经被添加到了全局配置中 * 初始化命令:`lib/middlewares/getCommands`收集当前工程所使用的套件的所有生命周期和插件,和全局插件一起合并到default commands上形成一份命令配置 ```javascript ctx.commands = mergeCommands(defaultCommands, lifecycles, plugins); ``` * 注册并执行命令:`lib/middlewares/registerCommands`把上面的配置注册到一个Commander实例上面,解析当前命令行参数并执行命令 ```javascript const {
commands } = ctx; Object.keys(commands).forEach((name) => {
const command = commands[name];
const {
command: commandName,
description,
before = noop,
__wrapper = defalutAsyncMiddleware,
middlewares,
after = noop,
__confirm = defalutAsyncMiddleware,
config: mwConfig,
injects: mwInjects,
alias,
allowUnknownOption,
options = []
} = command;
const p = program.command(commandName || name).description(description);
options.forEach(op => {
p.option(op.flags, op.description, op.handleOption || (a => a), op.defaultValue);
}); }); ``` * 检查更新`/lib/middlewares/checkForUpdates`
(4)解析执行命令行参数
program.parse(process.argv);
现在命令行参数是dev
(1)dev命令存在于套件的生命周期目录下,执行该目录下的index.js
文件
module.exports = async (config, injects) => ({
async middlewares ({ meta }) {
return [
require('../../common/middleware/yarn-install'),
require('./middleware/handle-options'),
require('./middleware/sync-pr-common'),
require('./middleware/dev-server')
];
}
});
核心代码就是执行4个函数,即安装依赖、判断当前启动服务的模式、同步pr-common、启动服务 ** **完成