日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

git 创建webpack项目_从0到1开发一个小程序cli脚手架(一)创建页面/组件模版篇...

發(fā)布時間:2025/3/11 编程问答 15 豆豆
生活随笔 收集整理的這篇文章主要介紹了 git 创建webpack项目_从0到1开发一个小程序cli脚手架(一)创建页面/组件模版篇... 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

github地址:

https://github.com/jinxuanzheng01/xdk-cli

cli工具是什么?

在正文之前先大致描述下什么是cli工具,

cli工具英文名command-line interface,也就是命令行交互接口,比較典型的幾個case例如,create-react-app,vue-cli,具體可以去百度一下,下面gif是小打卡目前用的一套自動化發(fā)布工具?

可以看到整個發(fā)布流程大致是以選擇或默認(rèn)項的形式實現(xiàn),大致分析下面幾步

  • 選擇打包形式 ? ?開發(fā)模式/debug模式/發(fā)布模式

  • 設(shè)置版本號

  • 填寫發(fā)布信息

  • 選擇環(huán)境

  • 是否提交版本commit

是不是非常無腦?是不是再也不用擔(dān)心線上發(fā)錯環(huán)境了?有了它就算不同項目間,就算一天發(fā)n次版本還需要擔(dān)心什么呢?

當(dāng)然除了簡單的發(fā)布功能還,還可以做很多的事情,比如創(chuàng)建page/component模版等一些更多有趣的事情

為了節(jié)約版面就不貼圖了,具體可以看下倉庫 ?https://github.com/jinxuanzheng01/xdk-cli(目前該工具是從小打卡現(xiàn)有的cli庫中抽離的部分功能)

明確痛點

也就是我為什么要做這么一個工具,其實最開始我只是為了解決一個問題,就是在整個發(fā)布流程中需要人工去改動/確認(rèn)發(fā)布環(huán)境和版本信息,大致可以想象下把線下環(huán)境發(fā)布到線上的尷尬處境

后續(xù)發(fā)現(xiàn)從cli角度觸發(fā),很多東西都變得簡單了,大致列了下:

  • 環(huán)境變量切換(線上環(huán)境,線下環(huán)境)

  • 創(chuàng)建啟動模版,包括頁面,組件

  • 自動化發(fā)布

  • ...

準(zhǔn)備工作

本文會以快速創(chuàng)建頁面模版文件為例教你怎么快速擼一個屬于自己的cli工具,

如果覺得自己做比較麻煩,可以clone下我的倉庫自己改裝下

需要了解的三方庫

中間會用到一些第三方庫

  • commander, 一個解析命令行命令和參數(shù)工具

  • inquirer,常用交互式命令行用戶界面的集合

  • chalk,美化你的終端輸出樣式

  • fuzzy,字符串模糊匹配的插件,根據(jù)輸入關(guān)鍵詞進(jìn)行模糊匹配

  • json-format,json美化/格式化工具

其他的一些小知識:比如path模塊,fs模塊,大家可以去node官網(wǎng)自行查看:https://nodejs.org/api/

搭建開發(fā)環(huán)境

創(chuàng)建一個空文件夾,并且npm初始化, 并且創(chuàng)建一個index.js頁面,這個index.js將作為你整個包的入口文件

npm init -y

安裝上述的三方包,當(dāng)然也可以后續(xù)按需安裝,這樣更能清楚每個包是做什么的

npm install @moyuyc/inquirer-autocomplete-prompt commander chalk commander fuzzy inquirer json-format --save

在package.json里添加bin字段, 將自定義的命令軟連到全局環(huán)境,同時執(zhí)行npm link創(chuàng)建鏈接,這里如果報錯{code EACCES,errno:13,...},是因為權(quán)限不足,可以嘗試sudo npm link

"bin": { "cli-demo": "./index.js" }

在入口文件,index.js 行首加入一行#!/usr/bin/env node指定當(dāng)前腳本由node.js進(jìn)行解析

#!/usr/bin/env node// 輸出文本console.log('Hello World!!!');

這時可以在命令行中執(zhí)行 cli-demo驗收一下成果了

ok,可以看到當(dāng)在全局狀態(tài)下輸入自定義命令時,正確運行了入口文件,也就意味著的開發(fā)玩具已經(jīng)搭建完成

Let‘ Go

整理邏輯

以快速創(chuàng)建頁面模版文件為例,就需要考慮需要哪些邏輯:

  • 設(shè)置頁面名稱

  • 找到已有模版文件

  • copy到項目中

  • 修改app.json

識別命令行

在剛才的Hello World!!!環(huán)節(jié),已經(jīng)可以正確識別cli-demo,但是需要在一個cli工具中集成更多功能,可能需要有不同的執(zhí)行策略,以git為例:git clone, git status,git push,所以需要識別不同的命令和參數(shù),

是時候就需要用到commander這個第三方包幫助解析命令行參數(shù)了,當(dāng)然你也可以自己擼一個lib,本質(zhì)上還是方便解析process.argv

index.js (本質(zhì)上這個js就是一個路由)#!/usr/bin/env nodeconst version = require('./package').version; // 版本號/* = package import-------------------------------------------------------------- */const program = require('commander'); // 命令行解析/* = task events-------------------------------------------------------------- */const createProgramFs = require('./lib/create-program-fs'); // 創(chuàng)建項目文件/* = config-------------------------------------------------------------- */// 設(shè)置版本號program.version(version, '-v, --version');/* = deal receive command-------------------------------------------------------------- */program .command('create') .description('創(chuàng)建頁面或組件') .action((cmd, options) => createProgramFs(cmd));/* 后續(xù)可以根據(jù)不同的命令進(jìn)行不同的處理,可以簡單的理解為路由 */// program// .command('build [cli]')// .description('執(zhí)行打包構(gòu)建')// .action((cmd, env) => callback);/* = main entrance-------------------------------------------------------------- */program.parse(process.argv)

這時候當(dāng)鍵入cli-demo create時會自動執(zhí)行createProgramFs

// createProgramFs.jsmodule.exports = function () { console.log('Hi, create-program-fs.js');};

命令行輸入``cli-demo create``

可以看到已經(jīng)成功的開辟出了一塊獨立的業(yè)務(wù)模塊,后續(xù)就只需要依據(jù)需求填補相應(yīng)的內(nèi)容即可

創(chuàng)建交互命令

收到執(zhí)行命令,這個時候按第一張圖,是需要開始一系列QA(當(dāng)然你也可以不做交互式,直接配置命令行參數(shù)),

引入三方包 inquirer,來指定問題隊列

const question = [ // 選擇模式使用 page -> 創(chuàng)建頁面 | component -> 創(chuàng)建組件 { type: 'list', name: 'mode', message: '選擇想要創(chuàng)建的模版', choices: [ 'page', 'component', ] }, // 設(shè)置名稱 { type: 'input', name: 'name', message: answer => `設(shè)置 ${answer.mode} 名稱 (e.g: index):`, },];module.exports = function() { // 問題執(zhí)行 inquirer.prompt(question).then(answers => { console.log(answers); });};

可以看到通過一系列QA交互,實際輸出拿到的是一個json對象,第一步已完成

創(chuàng)建模版文件

創(chuàng)建一個存放模版文件的文件夾template,并準(zhǔn)備好你希望的模版

項目中創(chuàng)建模版文件

為了方便閱讀,下面的代碼,需要明確下面變量的定義,

Config.dir_root ?= 命令行執(zhí)行目錄

Config.root ?= cli項目根目錄

Config.appRoot = 小程序項目路徑

Config.template = 模版目錄

這里有兩個點,一個是執(zhí)行路徑的問題,另一個是分包的問題,具體如下:

執(zhí)行路徑

這里一定要弄明白__dirname, process.cwd()的區(qū)別,同時還有一些小程序是自己搭的gulp/webpack,可能小程序項目是在src目錄下,一定要分清楚

  • __dirname:被執(zhí)行js文件的絕對路徑,一般在index.js執(zhí)行時緩存起來作為項目的全局路徑,比如找到template文件夾就會使用 `${__dirname}/template`

  • process.cwd():當(dāng)前命令行運行時的工作目錄,比如在/Users/xuan/Documents/cli-demo

  • 如果當(dāng)前項目在src,或其他文件夾里怎么辦?可以提供一個給用戶項目中的配置文件,類似于gulpfile.js或是webpack.config.js的形式,內(nèi)容例如(具體可以看git倉庫)

module.exports = { // 小程序路徑 app: './src', // 模版文件夾 template: './template'};

可以看到對象中app屬性,可以指定你當(dāng)前小程序項目的路徑

分包

因為小程序的分包機制會導(dǎo)致頁面實際路徑與在主包的路徑不相符,例如:

  • 主包:pages/index/index

  • 分包:pages/main_module/pages/habit_enlist/habit_enlist

解決這個問題一方面是要有頁面創(chuàng)建要有一定的規(guī)范,統(tǒng)一格式,另一方面需要根據(jù)規(guī)則解析app.json,

上面的主包,分包路徑差不多是我目前使用的規(guī)范

解析app.json

// 獲取app.jsonfunction getAppJson() { let appJsonRoot = path.join(Config.appRoot, '/app.json'); try { return require(appJsonRoot); }catch (e) { Log.error(`未找到app.json, 請檢查當(dāng)前文件目錄是否正確,path: ${appJsonRoot}`); process.exit(1); // 異常退出 }}// 解析app.jsonlet parseAppJson = () => { // app Json 原文件 let appJson = __Data__.appJson = getAppJson(); // 獲取主包頁面 appJson.pages.forEach(path => __Data__.appPagesList[getPathSubSting(path)] = ''); // 獲取分包,頁面列表 appJson.subPackages.forEach(item => { __Data__.appModuleList[getPathSubSting(item.root)] = item.root; item.pages.forEach(path => __Data__.appPagesList[getPathSubSting(path)] = item.root); });};// __Data__.appPagesList = 小程序全部頁面// __Data__.appModuleList = 小程序全部分包頁面// item結(jié)構(gòu) {util_module: 'pages/util_module/'},這么定義結(jié)構(gòu)是為了方便后續(xù)取數(shù)question隊列里,增加刪選分包的選項 // 設(shè)置page所屬module { type: 'autocomplete', name: 'modulePath', message: 'Set page ownership module', choices: [], suggestOnly: false, source(answers, input) { // none 代表放在主包 return Promise.resolve(fuzzy.filter(input, ['none', ...Object.keys(__Data__.appModuleList)]).map(el => el.original)); }, filter(input) { if (input === 'none') { return ''; } return __Data__.appModuleList[input]; }, when(answer) { return answer.mode === 'page'; } }

autocomplete類型本質(zhì)上是個列表,但是可以進(jìn)行模糊查詢,非常方便,像小打卡有接近30個分包的情況下效果尤為明顯

有了文件名,有了分包路徑,有了可供copy的模版,接下來就很簡單了,把模版文件塞進(jìn)項目就可以了,下面是一串從倉庫里copy的代碼,利用async/await很方便的寫出一維代碼,基本上的流程:

獲取路徑 -> 校驗 -> 獲取文件信息 -> 復(fù)制文件 -> 修改app.json -> 輸出結(jié)果信息

async function createPage(name, modulePath = '') { // 獲取模版文件路徑 let templateRoot = path.join(Config.template, '/page'); if (!Util.checkFileIsExists(templateRoot)) { Log.error(`未找到模版文件, 請檢查當(dāng)前文件目錄是否正確,path: ${templateRoot}`); return; } // 獲取業(yè)務(wù)文件夾路徑 let page_root = path.join(Config.appRoot, modulePath, '/pages', name); // 查看文件夾是否存在 let isExists = await Util.checkFileIsExists(page_root); if (isExists) { Log.error(`當(dāng)前頁面已存在,請重新確認(rèn), path: ` + page_root); return; } // 創(chuàng)建文件夾 await Util.createDir(page_root); // 獲取文件列表 let files = await Util.readDir(templateRoot); // 復(fù)制文件 await Util.copyFilesArr(templateRoot, `${page_root}/${name}`, files); // 填充app.json await writePageAppJson(name, modulePath); // 成功提示 Log.success(`createPage success, path: ` + page_root);}

擴展

一個基本的快速創(chuàng)建頁面模版的cli工具就這樣完成,但是有可能需要更多的一些功能

自定義模版

比如說每個項目的模版都有可能不太一樣,很大程度上需要根據(jù)項目進(jìn)行定制,這時候可能就需要前文提到的給用戶開放config文件的插槽了

項目中的config:

// xdk.config.jsmodule.exports = { // 小程序路徑 app: './', // 模版文件夾 template: './template'};// create-program-fs.jsmodule.exports = function() { // 校驗:當(dāng)前是否存在配置文件 let customConfPath = `${Config.dir_root}/xdk.config.js`; if (!Util.checkFileIsExists(customConfPath)) { Log.error('當(dāng)前項目尚未創(chuàng)建xdk.config.js文件'); return; } // 獲取用戶配置項 let {app, template = ''} = require(customConfPath); // 小程序目錄 Config.appRoot = path.resolve(path.join(Config.dir_root, app)); // 模版文件目錄(默認(rèn)使用cli提供的默認(rèn)模版,當(dāng)config文件有設(shè)置template路徑時,使用自定義路徑) !!template && (Config.template = path.resolve(path.join(Config.dir_root, template)))); // 問題執(zhí)行 inquirer.prompt(question).then(answers => { console.log(answers); });};

發(fā)布的npm倉庫

目前從開發(fā)到調(diào)試本質(zhì)上是在本地提供服務(wù),利用npm link提供軟連接到全局PATH,

其實也可以直接發(fā)到npm上,讓其他使用的該cli的成員一建安裝,比如``npm install -g xxxxxxx``

教程的話百度,google有很多,作者表示很懶,遇到問題下面留言吧。。

最后

可以看到整個功能邏輯相對于平時寫的復(fù)雜的業(yè)務(wù)邏輯來說相對簡單,主要是工具庫的一些使用方面的東西,中間的難點可能就是node中概念性的一些東西,然而這些多看一下文檔基本就可以解決,希望大家可以從本文中了解到如何快速搭建一個屬于自己的cli工具

順便預(yù)告下后續(xù)的話可能會更新一些如何利用cli工具做到自動化發(fā)布,版本號控制,環(huán)境變量切換,自動生成文檔等一系列有趣的功能

總結(jié)

以上是生活随笔為你收集整理的git 创建webpack项目_从0到1开发一个小程序cli脚手架(一)创建页面/组件模版篇...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。