前端開發(fā)過程中常見的CLI有:
create-react-app
vue-cli
webpack-cli
prettier-cli
基本復(fù)雜一點(diǎn)的工具都在集成CLI,為啥都要搞成CLI呢?
因?yàn)镃LI可以提供更強(qiáng)大的功能:
通過命令搭配實(shí)現(xiàn)不同的功能
管理項(xiàng)目模版
啟動(dòng)本地服務(wù)
生成模版文件
對(duì)代碼進(jìn)行格式化
我們先搭建一個(gè)最簡(jiǎn)單的CLI來(lái)體驗(yàn)下,然后逐步實(shí)現(xiàn)復(fù)雜點(diǎn)的功能。
首先新建項(xiàng)目作為CLI源代碼地址
mkdir cli-demo cd cli-demo npm init 復(fù)制代碼
yargs文檔配置:該插件將用戶通過終端輸入的參數(shù)解析成對(duì)象,可以配置各種參數(shù)。
yarn add yargs 復(fù)制代碼
命令使用語(yǔ)法:
.command(cmd, desc, [builder], [handler]) 復(fù)制代碼
下面的配置說(shuō)明:
配置命令get
聲明信息make a get HTTP request
并配置了參數(shù)url
信息
最后callback函數(shù)獲取用戶執(zhí)行的參數(shù)
具體使用:編輯index.js
,第一行一定要加注釋,表明運(yùn)行在node環(huán)境下
#!/usr/bin/env node const yargs = require('yargs/yargs') const { hideBin } = require('yargs/helpers') yargs(hideBin(process.argv)) .command( 'get', 'make a get HTTP request', function (yargs) { return yargs.options({ url: { alias: 'u', describe: 'the URL to make an HTTP request to' } }) }, function (argv) { console.log("callback", argv.url) } ) .help() .argv 復(fù)制代碼
執(zhí)行命令,可以獲取輸入的參數(shù)
這里get就是定義的指令,url是指令下的key值,用--url輸入,alias就是別名,用-u表示,后面跟要輸入的參數(shù)。
接著我們發(fā)布下npm,然后一個(gè)CLI就完成了。
登陸npm倉(cāng)庫(kù),沒有的話去注冊(cè)一個(gè),地址
npm login 復(fù)制代碼
選擇一個(gè)中意的cli名字,查一下是否存在,這里我們起個(gè)名字cli-demo3
執(zhí)行npm version patch && npm publish --registry=https://registry.npmjs.org
,不出意外的話,就發(fā)布成功了。
然后我們本地使用下,首先下載到本地,全局下載npm install -g cli-demo3
cli-demo3是我們前期測(cè)試使用寫的CLI,后面繼續(xù)使用我正常部署的CLI:u-amin-cli,原理是一樣的
# 這里使用4版本,升級(jí)到5版本不再支持require方式導(dǎo)入 yarn add log-symbols@4.1.0 復(fù)制代碼
使用方法
使用效果
# 這里使用4版本,升級(jí)到5版本不再支持require方式導(dǎo)入 yarn add chalk@4.1.2 復(fù)制代碼
1、支持傳入string,array和模版字符串
使用方法
console.log(chalk.blue("this is blue")) console.log(chalk.blue('Hello', 'World!', 'Foo', 'bar', 'biz', 'baz')); console.log(` CPU: ${chalk.red('90%')} RAM: ${chalk.green('40%')} DISK: ${chalk.yellow('70%')} `); 復(fù)制代碼
使用效果
2、支持修改背景色、各種顏色格式、指定不同文本的顏色
使用方法
console.log(chalk.blue.bgRed.bold('Hello world!')); console.log(chalk.red('Hello', chalk.underline.yellowBright('world') + '!')); console.log(chalk.hex('#DEADED').underline('Hello, world!')) console.log(chalk.rgb(15, 100, 204).inverse('Hello!')) 復(fù)制代碼
使用效果
3、支持自行封裝一些顏色
使用方法
const error = chalk.bold.red; const warning = chalk.hex('#FFA500'); // Orange color console.log(error('Error!')); console.log(warning('Warning!')); 復(fù)制代碼
使用效果
# 這里使用5版本,升級(jí)到6版本不再支持require方式導(dǎo)入 yarn add ora@5.4.1 復(fù)制代碼
使用方法
const ora = require('ora'); const spinner = ora('Loading unicorns').start(); setTimeout(() => { spinner.color = 'yellow'; spinner.text = 'Loading rainbows'; }, 1000); 復(fù)制代碼
使用效果
使用方法
var inquirer = require('inquirer'); inquirer .prompt([ { name: "templateType", type: "list", default: "vue", choices: [ { name: "React", value: "react", }, ], message: "Select the template type.", } ]) .then((answers) => { // Use user feedback for... whatever!! }) .catch((error) => { if (error.isTtyError) { // Prompt couldn't be rendered in the current environment } else { // Something else went wrong } }); 復(fù)制代碼
使用效果
這樣就可以給客戶提示選擇來(lái)處理邏輯。
使用方法
const download = require("download-git-repo"); download('direct:https://gitlab.com/flippidippi/download-git-repo-fixture.git#my-branch', 'test/tmp', { clone: true }, function (err) { console.log(err ? 'Error' : 'Success') }) 復(fù)制代碼
還有很多類似的插件,來(lái)豐富cli的功能,根據(jù)需要添加即可
open 打開瀏覽器
yargs/commander 執(zhí)行cli命令
get-port 獲取當(dāng)前端口號(hào)
啟動(dòng)文件index.js
const yargs = require('yargs/yargs') const { hideBin } = require('yargs/helpers') const config = require('./config') const yargsCommand = yargs(hideBin(process.argv)) config.forEach(commandConfig => { const { command, descriptions, options, callback } = commandConfig yargsCommand.command( command, descriptions, yargs => yargs.options(options), (argv, ...rest) => { callback(argv, ...rest); } ) }) yargsCommand.help().argv 復(fù)制代碼
指令文件config.js
const commandOptions = [ { command: "create", descriptions: "拉取一個(gè)項(xiàng)目模版", options: { name: { alias: "n", type: "string", require: true, describe: "項(xiàng)目名稱", }, }, callback: async (argv) => { create({name: argv.name}) } }] 復(fù)制代碼
提取配置,就很清晰了
前端工程化:Prettier+ESLint+lint-staged+commitlint+Hooks+CI 自動(dòng)化配置處理
上一步我們對(duì)配置進(jìn)行了提取,接著根據(jù)配置生成使用文檔,如下
使用方法
yarn add json2md@1.12.0 -D 復(fù)制代碼
const json2md = require("json2md") // 按json2md需要的數(shù)據(jù)格式組合 const data = json2md([ { h1: "JSON To Markdown" } , { blockquote: "A JSON to Markdown converter." } ])) // 寫入Readme.md文檔 fs.writeFile(path.join(__dirname, "../Readme.md"), json2md(data), (err) => { if (err) throw err; console.log("update docs success"); }); 復(fù)制代碼
{ command: "create", descriptions: "拉取一個(gè)項(xiàng)目模版", options: { name: { alias: "n", type: "string", require: true, describe: "項(xiàng)目名稱", }, }, callback: async (argv) => { create({name: argv.name}) } } 復(fù)制代碼
const map = { vue: "https://github.com/luchx/ECHI_VUE_CLI3.0.git", react: "git@github.com:richLpf/antd-template-demo.git#main" } 復(fù)制代碼
1、inquirer提示用戶選擇對(duì)應(yīng)的模版,具體可以看前面用法
2、通過download下載模版文件
module.exports = function downloadFromRemote(url, name) { return new Promise((resolve, reject) => { download(`direct:${url}`, name, { clone: true }, function (err) { if (err) { reject(err); return; } resolve(); }); }); }; 復(fù)制代碼
3、通過ora在下載過程中展示loading
這是主要的下載邏輯,關(guān)于日志,我們可以更好的展示,也可以配置更復(fù)雜的命令:替換下載的項(xiàng)目名稱,刪除.git目錄,修改package.json配置
前端在開發(fā)的過程中,總會(huì)遇到后端接口無(wú)法按時(shí)提供的情況,這種情況下有很多解決方案,常見的通過客戶端生成模擬api,在項(xiàng)目中引入Mock。
這里我們通過CLI來(lái)實(shí)現(xiàn)一個(gè)更加簡(jiǎn)單好用的模擬方案
通過CLI啟動(dòng)一個(gè)或多個(gè)服務(wù)器,通過Express做路由轉(zhuǎn)發(fā)本地的JSON文件
首先我們配置mock命令,設(shè)定參數(shù)type
、port
、create
分別代表API類型、啟動(dòng)Http服務(wù)器端口號(hào),默認(rèn)9000,create
是否自動(dòng)生成接口數(shù)據(jù)JSON文件。
{ command: "mock", descriptions: "啟動(dòng)一個(gè)本地服務(wù),模擬返回接口數(shù)據(jù)", options: { type: { alias: "t", type: "string", default: "action", describe: "選擇API類型", choices: ['action', 'restful'] }, port: { alias: "P", type: "number", default: 9000, describe: "選擇啟動(dòng)的端口號(hào)", }, create: { alias: "c", type: "boolean", default: false, describe: "如果mock目錄不存在是否自動(dòng)創(chuàng)建,默認(rèn)不自動(dòng)創(chuàng)建" }, }, callback: async (argv) => { mock({ ...argv }) } 復(fù)制代碼
const app = express() app.use(bodyParser.json({limit: '50mb'})) app.use(express.urlencoded({ extended: true })); app.all('*', (req, res, next) => { res.header('Access-Control-Allow-Origin', '*'); //訪問控制允許來(lái)源:所有 res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept'); //訪問控制允許報(bào)頭 X-Requested-With: xhr請(qǐng)求 res.header('Access-Control-Allow-Metheds', 'PUT, POST, GET, DELETE, OPTIONS'); //訪問控制允許方法 res.header('X-Powered-By', 'nodejs'); //自定義頭信息,表示服務(wù)端用nodejs res.header('Content-Type', 'application/json;charset=utf-8'); next(); }); const filePath = path.join(process.cwd(), `./mock/`) app.listen(port, () => console.log(`Mock api listening on port ${port}!`)); 復(fù)制代碼
比如請(qǐng)求url為:
http://localhost:9000/acl 復(fù)制代碼
請(qǐng)求體為:
{ Action: "GetUsers" } 復(fù)制代碼
此時(shí)在CLI執(zhí)行的目錄,新建mock/acl/GetUsers.json
GetUsers.json內(nèi)容為返回的json數(shù)據(jù)
{ "RetCode": 0, "Message": "this is error", "Data": [] } 復(fù)制代碼
然后通過fs
模塊讀取json文件的數(shù)據(jù),直接返回模擬的數(shù)據(jù),因?yàn)槭菍?shí)時(shí)讀取的,所以更新json數(shù)據(jù)不需要重啟服務(wù)。主要邏輯如下
app.post('*', async(req, res) => { const key = req.params[0].substring(1) const { Action } = req.body const file = `${filePath}${key}/${Action}.json`; fs.readFile(file, 'utf-8', function(err, data) { if (err) { res.send(NotFoundResponse); } else { res.send(data); } }) }) 復(fù)制代碼
比如請(qǐng)求url為:
http://localhost:9000/acl/users 復(fù)制代碼
post請(qǐng)求體為:
{ limit: 10 } 復(fù)制代碼
此時(shí)在CLI執(zhí)行的目錄,新建mock/acl/users/post.json
post.json內(nèi)容為返回的json數(shù)據(jù)
{ "RetCode": 0, "Message": "get users", "Data": [] } 復(fù)制代碼
如果是get請(qǐng)求,只需要添加get.json
就可以了。
然后同樣通過fs
讀取對(duì)應(yīng)的json數(shù)據(jù)
app.all("*", async(req, res) => { const key = req.params[0] const method = req.method const file =`${filePath}${key}/${method}.json` console.log("file", file) fs.readFile(file, 'utf-8', function(err, data) { if (err) { res.send(NotFoundResponse); } else { res.send(data); } }) }) 復(fù)制代碼
這樣就完成了CLI啟動(dòng)一個(gè)模擬的http服務(wù),用起來(lái)很方便,并且可以支持直接在項(xiàng)目中使用。
具體可以試試看u-admin-cli
對(duì)于大部分mock來(lái)說(shuō),復(fù)雜的配置是不需要的,這里僅僅是用了固定的json數(shù)據(jù),我覺得就夠用了,當(dāng)然還可以自行處理數(shù)據(jù),引入Mock規(guī)則,自行定義生成數(shù)據(jù)類型等
以上就是搭建一個(gè)CLI的過程,我們從最簡(jiǎn)單的開始構(gòu)建了一個(gè)基礎(chǔ)CLI,在這個(gè)基礎(chǔ)上進(jìn)行了交互優(yōu)化,然后實(shí)際開發(fā)了CLI的兩個(gè)功能:
1、通過CLI管理部門內(nèi)的模版項(xiàng)目
2、通過CLI啟動(dòng)Http服務(wù)器,模擬接口生成
項(xiàng)目代碼:github.com/richLpf/u-a…
CLI地址:www.npmjs.com/package/u-a…
碼字不易,歡迎點(diǎn)贊????,有問題請(qǐng)留言。
作者:前端中后臺(tái)
鏈接:https://juejin.cn/post/7090001607596703758
來(lái)源:稀土掘金
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/127965.html
摘要:以下閱讀將花費(fèi)分鐘前言日常開發(fā)中,我們都只專注在業(yè)務(wù)上的開發(fā),拿起一套開箱即用的模板項(xiàng)目就直接開搞了,不知道大家有沒有思考過,平時(shí)我們使用的腳手架里面到底做了什么,并且如果是自己來(lái)搭一套腳手架,應(yīng)該怎么去搭呢在本博客中,將記錄作者搭建腳手架 (以下閱讀將花費(fèi)10分鐘) 前言 日常開發(fā)中,我們都只專注在業(yè)務(wù)上的開發(fā),拿起一套開箱即用的模板項(xiàng)目就直接開搞了,不知道大家有沒有思考過,平時(shí)我們...
摘要:后來(lái)經(jīng)過排查你會(huì)發(fā)現(xiàn)是由于目前還沒有版本??梢允褂迷摲绞浇鉀Q。這就是我為什么不推薦你使用創(chuàng)建腳手架的原因此文的受眾是想要進(jìn)階中級(jí)的初級(jí)前端人員。 最近在知乎看到一個(gè)問題,原問題如下: 很奇怪,為什么現(xiàn)在能找到自己手動(dòng)創(chuàng)建vue腳手架的文章非常少,而且大家似乎對(duì)webpack4的熱情并不高,對(duì)于想基于vue2.0+webpack4搭建一個(gè)腳手架的我來(lái)說(shuō)資料真是少得可憐。難道現(xiàn)在一般的做...
摘要:如何在下搭建多模塊單模塊多路由骨架屏前言骨架屏的用戶感知比更好,此前看過很多專欄以及文章,此次實(shí)踐中還是遇到需要學(xué)習(xí)的部分。包括因?yàn)榭赡苄畔⒚娌蝗?,?duì)插件源碼進(jìn)行了詳細(xì)解讀,希望對(duì)于將要在項(xiàng)目中搭建骨架屏的小伙伴們有所幫助。 如何在webpack+vue+vue-cli下搭建多模塊/單模塊多路由骨架屏 前言 骨架屏的用戶感知比loading更好,此前看過很多專欄以及文章,此次實(shí)踐中還是...
摘要:如何在下搭建多模塊單模塊多路由骨架屏前言骨架屏的用戶感知比更好,此前看過很多專欄以及文章,此次實(shí)踐中還是遇到需要學(xué)習(xí)的部分。包括因?yàn)榭赡苄畔⒚娌蝗瑢?duì)插件源碼進(jìn)行了詳細(xì)解讀,希望對(duì)于將要在項(xiàng)目中搭建骨架屏的小伙伴們有所幫助。 如何在webpack+vue+vue-cli下搭建多模塊/單模塊多路由骨架屏 前言 骨架屏的用戶感知比loading更好,此前看過很多專欄以及文章,此次實(shí)踐中還是...
摘要:之所以寫這篇如何運(yùn)用腳手架自動(dòng)化構(gòu)建出一個(gè)項(xiàng)目的大架構(gòu),主要是面向想入門的小伙伴。之前,我第一次接觸,一直摸不著頭腦,想在網(wǎng)上搜個(gè)接地氣的教程都找不到。 WHY 之所以寫這篇如何運(yùn)用腳手架自動(dòng)化構(gòu)建出一個(gè)項(xiàng)目的大架構(gòu),主要是面向想入門vue的小伙伴。之前,我第一次接觸vue,一直摸不著頭腦,想在網(wǎng)上搜個(gè)接地氣的教程都找不到。SO,我以如何搭建結(jié)構(gòu)為開始,向想入門vue的童鞋們把我僅有的...
閱讀 1583·2025-02-07 13:29
閱讀 1008·2024-11-07 18:25
閱讀 131502·2024-02-01 10:43
閱讀 1377·2024-01-31 14:58
閱讀 1149·2024-01-31 14:54
閱讀 83576·2024-01-29 17:11
閱讀 3877·2024-01-25 14:55
閱讀 2395·2023-06-02 13:36