脚手架设计
参考项目 G:\webpack-learn\my-cli
1. 为什么需要脚手架
脚手架 提供 创建项目, 项目运行, 项目框架, 项目打包, 项目发布,等一系列能力,提升研发效率, 简化复杂流程
2. 当在命令行里输入vue create app
发生了什么
会找到vue对应的可执行文件, 然后执行.
- 如果是苹果系统会执行
which vue
, 找到对应文件后执行. - 如果是window, 用
where vue
, 他会找到对应文件. 找到对应文件vue.js
后, 第一行会有一个#!/usr/bin/env node
,表示该文件是由node执行的, 然后再找node的可执行文件 比如C:\Program Files\nodejs\node.exe
. 再用node.exe执行vue.js. - 找到这些文件后,会把vue后面的字段当做参数,传入可执行文件中. 启动.
- 可执行文件的例子
- node_modules/.bin/webpack-cli.cmd
- C:\Program Files\Git\bin\bash.exe (很多.exe格式)
- package.json里有bin属性
{
"bin": {
"my-app": "./bin/my-app"
},
}
- 启动文件的方式
默认.js文件是没法启动的, 需要告诉系统启动方式, 在文件开头添加#!/usr/bin/env node
, 效果就是在命令行输入/usr/bin/env node console.log(123)
, 命令行就知道用node启动了. - 操作系统window只能执行二进制文件, 比如node.exe. 而vue.js就需要node解析成二进制再执行
脚手架执行流程
- 在终端输入
vue create app
- 终端解析出
vue
命令 - 终端在环境变量中找到
vue
命令 - 终端根据
vue
命令链接到实际文件vue.js
- 终端查看vue.js第一行,
#!/usr/bin/env node
,确实是用node作为执行程序 - 终端执行命令
/usr/bin/env node vue.js
- vue.js解析后续参数
create app
,并执行文件
3. 创建脚手架
- 创建npm项目
- 配置package.json的bin属性
"bin": {
"imooc-ls": "./bin/imooc-ls.js"
},
- 在bin/imooc-ls.js文件开头加上
#!/usr/bin/env node
- 编写imooc-ls.js, 比如
console.log(123)
- 执行命令
npm link
, 将imooc-ls
变成全局命令, 此时在全局的终端都可以使用imooc-ls
命令了- 由于imooc-ls是用node执行的命令,
npm link
会在C:\Program Files\nodejs
文件夹中,会生成关于imooc-ls的命令文件imooc-ls.cmd
- 地址
C:\Program Files\nodejs\node_modules\imooc-ls
是一个软链接,指向我们真实的文件地址. - 执行
imooc-ls
时,是先执行C:\Program Files\nodejs\imooc-ls.cmd
(二进制文件),这个文件会启用node执行imooc-ls.js
- 由于imooc-ls是用node执行的命令,
- 用
npm public
将脚手架发布到npm服务器.
4. imooc-ls.js 命令文件开发
- 获取命令参数用
process.argv
获取
// process.argv: ['node根目录地址', 'imooc-ls目录地址', '命令参数1', '命令参数2', ...]
/* 执行"imooc-ls -all"
[
'C:\\Program Files\\nodejs\\node.exe',
'C:\\Program Files\\nodejs\\node_modules\\imooc-ls\\bin\\index.js',
'-all'
]
*/
console.log(process.argv);
// 执行 node bin/index.js -a
// [
// 'C:\\Program Files\\nodejs\\node.exe',
// 'C:\\Program Files\\nodejs\\node_modules\\imooc-ls\\bin\\index.js',
// '-a'
// ]
imooc-ls -a
和 node bin/index.js -a
, 效果是一样的
- 获取命令终端的工作目录
输入命令行的地方的工作目录 process.cwd()
4. unix系统
Unix系统包括linux, MacOs.
用ls -l
获取到文件权限
// 文件权限
drwxr-xr-x 5 sam staff 160 Apr 4 13:58 bin
-rw-r--r-- 1 sam staff 260 Apr 4 13:58 package.json
文件权限drwxr-xr-x
- d: directory目录, -表示文件
- r: read 读取权限,表示文件是否可读
- w: write 写入权限,是否可修改
- x: execute 执行权限,
- 如果是文件夹,是否可进入,
- 如果是文件,是否可执行.
rwxr-xr-x
: 三个权限为一组,u|g|o
,rwx(user当前用户权限)|r-x(group用户所在分组权限)|r-x(other其他用户权限)
unix使用32位二进制数存储文件类型和权限
在unix中万物都是文件, 文档,目录, 键盘, 监视器, 硬盘,网络通信都是文件. 是文件,就有一套文件属性.
这些文件属性是用一个32位的二进制数保存的
// 32位的2进制数.
0000 0000 0000 0000
0000(文件类型), 000(特殊权限), 000(用户权限), 000(分组权限), 000(其他权限)
前4位0000: 文件类型, 可以表示16种文件类型. 0001
表示file普通文件, 0100
表示directory,目录
这里的文件类型是由 1所在的位置表示的,
1. 0001
, 1在第四位,就是file普通文件
2. 0100
, 1在第二位,就是目录.
用1所在位置记录值,是因为, 二进制程序有专门的位运算符&
, 可以用来快速判断 当前用户是否有某权限.
unix系统文件mode含义
unix系统文件的mode各个位的含义
32位操作系统的位
- 8位二进制: 00000000 可以表示0-255
- 16位二进制: 00000000 00000000 可以表示 0-65535
- 32位二进制: 00000000 00000000 00000000 00000000 可以表示 0-4294976295
操作系统的文件是由二进制数组成的. 是可以直接执行的机器语言.机器语言直接翻译成人类语言就是汇编. 形如
00110000
00001000
00000010
01110000
00000010
00000100
00100100
00000000
8位操作系统: 每一个汇编,由一个8位2进制数表示,也就是有256个汇编语言.
16位操作系统: 每一个汇编语言有两个8位2进制表示, 可以有65526个汇编.
32位操作系统: 每一个汇编语言有4个8位2进制表示, 可以有4294976296个汇编. 但是 不是每一个值的格式都是4个8位二进制.
比如32位操作系统的系统文件类型权限,就是用16位的2进制数表示的. 00000000 00000000
足够表示所有的系统类型.
获取系统文件类型和权限
// file: package.json, bin
const stat = fs.statSync(file);
console.log(
file, // 文件路径
stat.mode, // 描述文件类型和模式的位字段, 转成二进制数, 查看文件类型和权限
stat.isDirectory(), // 是否是文件夹
stat.isFile()); // 是否是文件
// package.json: mode: 33206, false, true
// bin: mode 16877 true, false
fs.statSync(file)
的返回值里有 mode
: 描述文件类型和模式的位字段, 转成二进制数, 查看文件类型和权限
比如: bin文件夹的mode: 16822, 转成二进制 1000001 11101101
,(第一位的0被省略了,自己加上即可)
01000001 11101101
转换成查看用户权限的格式
0100 000 111 101 101
文件类型 特殊权限 用户权限 用户所在分组权限 其他权限
文件类型(前4位): 0100
: 表示文件夹
特殊权限: 000
表示特殊权限, 在ls的输出里不展示.
用户权限: 111
(rwx)(read wirte execute)
翻译成ls输出的格式就是
bin: drwxr-xr-x
package.json: -rw-rw-rw-
位运算符 &
文件权限的计算方式
下面的 mode是 33188, S_IXUSR: 64
"&" 是一个位运算符,表示按位与操作。它将两个数字的二进制表示进行逐位比较,如果两个相应的二进制位都为1,则该位的结果为1,否则为0。
比如下面的 mode & fs.constants.S_IXUSR;
// 当前用户是否有执行权限.
const canUserExecute = mode & fs.constants.S_IXUSR;
// S_IXUSR : 64 => 1 000 000
// mode: 33188 => 10000001 10100100
// 进行位的对比 都不相同所以是 0.
1000 000 110 100 100
001 000 000
fs.constants.S_IXUSR
S_IRUSR: S: 表示system系统文件, I: is是否, R: read阅读权限, USR: user用户. 当前用户的系统文件是否有执行权限
用户阅读常量 S_IRUSR: 0000 0001 0000 0000 => 256
用户修改常量 S_IWUSR: 0000 0000 1000 0000 => 128
用户执行常量 S_IXUSR: 0000 0000 0100 0000 => 64
这些常量共同特点是用2个8位二进制保存的话, 所有二进制位都只有一个1,
文件的mode转成2个8位二进制, 如果有对应位置的1,那就有这个权限, 没有对应位置的1,就没有对应权限.
所以用 mode & fs.constants.S_IXUSR
可以用来判断当前文件是否有此权限. 这个计算方式也是设计好的一环.
mode
mode: 33188 的这个值不是随便取的, 也不是顺序排的. 而是现有二进制,再转成10进制的.
mode的二进制: 1000 000 110 100 100
这里面的16个位, 每一个位都表示一种权限或类型. 比如最开头的1
表示文件夹, 第二个1表示用户的读取权限.
是先根据当前文件的各种权限生成了这个16位的2进制,再为了存储方便,转成10进制,33188,保存在了mode里.
uid, gid
uid: userId 用户id, 可以获取用户名userName
gid: groupId, 用户所在组id, 可以获取用户所在组名groupName
ls -l
结果
drwxr-xr-x 2 root root 4096 Sep 22 15:08 a
-rw-r--r-- 1 root root 1010 Sep 22 16:52 auth.js
结果解析
drwxr-xr-x 2 root root 4096 Sep 22 15:08 a
//文件权限 文件夹下的文件数量 创建人 创建人所在分组 文件大小 修改时间 文件名