hello 大家好,🙎🏻♀️🙋🏻♀️🙆🏻♀️
我是一个热爱知识传递,正在学习写作的作者,ClyingDeng
凳凳!
今天我要给大家带来webpack-cli的原理浅析和它的自定义命令行工具💞💞💞
事情是这样的,最近在看webpack相关教程,然后发现教程中讲webpack-cli中使用yargs模块解析命令出于好奇,我就当场拉了webpack-cli的代码,发现使用命令解析的并不是yargs而是commander啊!😥😥😥
我是下了个假的cli嘛?🤔🤔🤔
这是不可能的,顶多是版本的问题!🤣🤣🤣
我找了webpack-cli历史版本,经查证后:
从webpack-cli 4.0.0后,不仅目录结构发生了较大的变动外,自动生成命令行也换成了commander。
在webpack-cli 3 中,在bin/cli.js
文件中解析cli参数,通过bin/utils/convert-argv.js
文件,将得到的命令行参数转换为webpack 配置选项对象。
webapck-cli 4 在packages/webpack-cli/bin/cli.js
中解析cli参数,通过commander模块解析cli参数。在packages/webpack-cli/src/webpack-cli.ts
中的run方法中,对参数进行处理。
webpack-cli 原理
其实webpack-cli就是将cli参数和webpack配置文件中的配置整合得到完整的配置对象。
- 通过解析命令行模块解析命令行参数。
- 将命令行参数转换为webpack配置选对象:
webpack-cli内部存在参数默认值,会去判断命令行是否指定具体路径的配置文件,如果指定配置文件就会去执行配置文件,否则就会根据默认参数和cli参数整合到一起,如果存在重复部分,优先使用cli参数。 - 开始载入webpack核心模块,传入配置选项,创建Compiler对象。
commander使用
在此,我们以webpack 5 默认的cli版本4.9.2 的 commander为主。简单介绍一下commander。
安装 commander:
npm install commander
我们通过 node 执行名命令传递参数给commander,利用commander处理不同命令代表的功能。
commander 处理参数
展示版本号
新建一个file.js文件。我们先来看看通常输入-V或者--version查看当前版本号是怎么实现的。
const { program } = require('commander') program .version('1.0.0') // 版本号
引入commander,使用version来传入版本,再命令行执行该文件
node file.js -V
这样我们就可以查看到当前版本号了。
逻辑处理
我们通过处理传递的命令参数,实现取参数的绝对值和取参数的整数部分。引入commander,实现通过命令传参实现对参数取绝对值和取整数位的功能。
const { program } = require('commander'); // 绝对值 const abs=(num)=>{ return Math.abs(num) } // 取整数部分 const integer = (num)=>{ return parseInt(num) }
我们想要实现通过参数实现功能,就需要使用commander的.option()
方法来定义选项,每个选项可以定义一个短选项名称(-后面接单个字符)和一个长选项名称(--后面接一个或多个单词),使用逗号、空格或|
分隔。
program .option('-abs, --integer <number>') // 取绝对值 .option('-integer --float <number>') // 取小数整数部分 program.parse(); const options = program.opts(); if(options.integer !== undefined) console.log(abs(options.integer)); if(options.float !== undefined) console.log(integer(options.float));
输入命令:
// 取参数绝对值 node file.js -abs -1 // 取参数整数部分 node file.js -integer -1.2
替换node
有人可能要有疑问了,我们一般使用webpack都是webpack xx类型,根本就没有node 执行一个文件再传参数的啊。
好,安排!
在同目录下初始化package,得到package.json文件。我们在文件中加入
"bin": { "dy": "./dy.js" },
bin中可以是字符串也可以是对象,如果是字符串那么命令就是该字符串,在此我们是使用的是对象,那么命令就是对象的key值。执行key 就相当于运行key对应值的文件。
使用npm link
,将本地命令和本地npm模块建立联系,成功之后我们就可以使用dy代替node某文件了。
dy.js文件中:
#!/usr/bin/env node const { program } = require('commander') program .version('1.0.0') // 版本号 .name('testModule') .argument('<params1>', '加数1') // 尖括号表示,例如<required> .argument('<params2>', '加数2') .action((params1, params2) => { console.log(Number(params1) + Number(params2)) }) program.parse(process.argv)
执行查看版本号和逻辑命令:
通过上图可以发现,已经成功代替node xx文件。
注意:
既然使用dy自定义命令,就需要知道,dy已经被注册到本地模块中。dy默认就是执行当前目录下的dy.js文件。想要跟换执行文件,只在package.json中更改dy对应文件路径是行不通的。
需要先npm unlink
断开连接之后,修改后再link。如果link无效,可以到自己下图电脑文件路径中删除相关文件。
文件夹的commander文件就是链接的标志。
删除后,还需要删除相关脚本命令文件才能重新link。