溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

web前端中怎么實(shí)現(xiàn)可執(zhí)行模塊

發(fā)布時(shí)間:2021-11-05 16:33:40 來(lái)源:億速云 閱讀:124 作者:iii 欄目:web開發(fā)

這篇文章主要介紹“web前端中怎么實(shí)現(xiàn)可執(zhí)行模塊”,在日常操作中,相信很多人在web前端中怎么實(shí)現(xiàn)可執(zhí)行模塊問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”web前端中怎么實(shí)現(xiàn)可執(zhí)行模塊”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!

實(shí)現(xiàn)可執(zhí)行模塊

首先,我們需要?jiǎng)?chuàng)建一個(gè)項(xiàng)目,這里就叫yncms-template-cli, 項(xiàng)目結(jié)構(gòu)如下:

- commands  // 此文件夾用于放置自定義命令  - utils  - index.js  // 項(xiàng)目入口  - readme.md

為了測(cè)試,我們先在index.js放點(diǎn)內(nèi)容:

#!/usr/bin/env node  // 必須在文件頭添加如上內(nèi)容指定運(yùn)行環(huán)境為node  console.log('hello cli');

對(duì)于一般的nodejs項(xiàng)目,我們直接使用node index.js就可以了,但是這里是腳手架,肯定不能這樣。我們需要把項(xiàng)目發(fā)布到npm,用戶進(jìn)行全局安裝,然后就可以直接使用我們自定義的命令,類似yncms-template這樣。

所以,我們需要將我們的項(xiàng)目做下改動(dòng),首先在packge.json中添加如下內(nèi)容:

"bin": {     "yncms-template": "index.js"   },

這樣就可以將yncms-template定義為一個(gè)命令了,但此時(shí)僅僅只能在項(xiàng)目中使用,還不能作為全局命令使用,這里我們需要使用npm link將其鏈接到全局命令,執(zhí)行成功后在你的全局node_modules目錄下可以找到相應(yīng)文件。然后輸入命令測(cè)試一下,如果出現(xiàn)如下內(nèi)容說(shuō)明第一步已經(jīng)成功一大半了:

PS E:\WorkSpace\yncms-template-cli> yncms-template  hello cli

但是,目前這個(gè)命令只有我們自己電腦可以用,要想其他人也能安裝使用,需要將它發(fā)布到npm,大致流程如下:

  1.  注冊(cè)一個(gè)npm賬戶,已有賬戶的可以跳過(guò)這一步

  2.  使用npm login登錄,需要輸入username、password、email

  3.  使用npm public發(fā)布

這一步比較簡(jiǎn)單,不多說(shuō),但是請(qǐng)注意如下幾點(diǎn):

  •  使用了nrm的需要先將源切換到npm官方源

  •  package.json中有幾個(gè)字段需要完善:

    •   name為發(fā)布的包名,不能和npm已有的包重復(fù)

    •   version為版本信息,每次發(fā)布都必須要比線上的版本高

    •   homepage、bugs、repository也可以添加上,對(duì)應(yīng)如下頁(yè)面   

web前端中怎么實(shí)現(xiàn)可執(zhí)行模塊

  • 在readme.md加入腳手架介紹及使用方法,方便他人使用。如果需要在文檔中加入徽標(biāo),展示腳手架的下載次數(shù)之類的,可以在這里生成。

web前端中怎么實(shí)現(xiàn)可執(zhí)行模塊

發(fā)布成功后,需要等待一會(huì)兒才可以在npm倉(cāng)庫(kù)搜索到。

創(chuàng)建命令

既然是腳手架,肯定不能只讓它輸出一段文字吧,我們還需要定義一些命令,用戶在命令行輸入這些命令和參數(shù),腳手架會(huì)做出對(duì)應(yīng)的操作。這里不需要我們自己去解析這些輸入的命令和參數(shù),有現(xiàn)成的輪子(commander)可以使用,完全可以滿足我們的需要。

幫助(--help)

安裝好commander后,我們將index.js中內(nèi)容改為如下:

#!/usr/bin/env node  const commander = require('commander');  // 利用commander解析命令行輸入,必須寫在所有內(nèi)容最后面  commander.parse(process.argv);

這時(shí),雖然我們沒(méi)有定義任何命令,但是commander內(nèi)部給我們定義了一個(gè)幫助命令--help(簡(jiǎn)寫-h):

PS E:\WorkSpace\yncms-template-cli> yncms-template -h  Usage: index [options]  Options:    -h, --help  output usage information

版本(--version)

接下來(lái),我們?cè)賱?chuàng)建一個(gè)查詢版本的命令參數(shù),在index.js增加如下內(nèi)容:

// 查看版本號(hào)  commander.version(require('./package.json').version);

這樣,我們?cè)诿钚芯涂梢圆榭窗姹咎?hào)了:

PS E:\WorkSpace\yncms-template-cli> yncms-template -V  1.0.10  PS E:\WorkSpace\yncms-template-cli> yncms-template --version  1.0.10

默認(rèn)參數(shù)是大寫V,如果需要改成小寫,將上面內(nèi)容做如下改動(dòng)即可:

// 查看版本號(hào)  commander      .version(require('./package.json').version)      .option('-v,--version', '查看版本號(hào)');
PS E:\WorkSpace\yncms-template-cli> yncms-template -h  Usage: index [options]  Options:    -V, --version  output the version number    -h, --help     output usage information

init子命令

接下來(lái),我們來(lái)定義一個(gè)init命令,如yncms-template init test。

在index.js中增加如下內(nèi)容:

commander      .command('init <name>') // 定義init子命令,<name>為必需參數(shù)可在action的function中接收,如需設(shè)置非必需參數(shù),可使用中括號(hào)      .option('-d, --dev', '獲取開發(fā)版') // 配置參數(shù),簡(jiǎn)寫和全寫中使用,分割      .description('創(chuàng)建項(xiàng)目') // 命令描述說(shuō)明      .action(function (name, option) { // 命令執(zhí)行操作,參數(shù)對(duì)應(yīng)上面的設(shè)置的參數(shù)          // 我們需要執(zhí)行的所有操作,都在這里完成          console.log(name);          console.log(option.dev);      });

現(xiàn)在測(cè)試一下:

PS E:\WorkSpace\yncms-template-cli> yncms-template init test -d  test  true

commander具體的用法,請(qǐng)自行查看官方文檔。

如此,一個(gè)自定義命令雛形就算完成了,然還有幾件事情要做:

  •  實(shí)現(xiàn)init命令具體執(zhí)行的操作,下面會(huì)有單獨(dú)部分來(lái)說(shuō)。

  •  為了方便維護(hù),將命令action拆分到commands文件夾中

web前端中怎么實(shí)現(xiàn)可執(zhí)行模塊

拉取項(xiàng)目

上面,我們定義了init命令,但是并沒(méi)有達(dá)到初始化項(xiàng)目的目的,接下來(lái)我們就實(shí)現(xiàn)一下。

一般來(lái)說(shuō),項(xiàng)目模板有兩種處理方式:

  •  將項(xiàng)目模板和本腳手架放在一起,好處是用戶安裝腳手架后,模板在本地,初始化會(huì)比較快;缺點(diǎn)是項(xiàng)目模板更新比較麻煩,因?yàn)楹湍_手架耦合在一起了

  •  將項(xiàng)目放置到單獨(dú)的GIT倉(cāng)庫(kù),好處是模板更新比較簡(jiǎn)單,因?yàn)槭窍嗷オ?dú)立的,只需要維護(hù)模板自己的倉(cāng)庫(kù)即可,另外可以控制拉取權(quán)限,因?yàn)槿绻撬接许?xiàng)目,那么沒(méi)有權(quán)限的人員是無(wú)法拉取成功的;缺點(diǎn)就是每次初始化都要去GIT拉取,可能會(huì)慢點(diǎn),不過(guò)影響不大,所以建議選擇此種方式

首先,我們利用download-git-repo封裝一個(gè)clone方法,用于從git拉取項(xiàng)目。

// utils/clone.js  const download = require('download-git-repo');  const symbols = require('log-symbols');  // 用于輸出圖標(biāo)  const ora = require('ora'); // 用于輸出loading  const chalk = require('chalk'); // 用于改變文字顏色  module.exports = function (remote, name, option) {      const downSpinner = ora('正在下載模板...').start();      return new Promise((resolve, reject) => {          download(remote, name, option, err => {              if (err) {                  downSpinner.fail();                  console.log(symbols.error, chalk.red(err));                  reject(err);                  return;              };              downSpinner.succeed(chalk.green('模板下載成功!'));              resolve();          });      });    };
// commands/init.js  const shell = require('shelljs');  const symbols = require('log-symbols');  const clone = require('../utils/clone.js');  const remote = 'https://gitee.com/letwrong/cli-demo.git';  let branch = 'master';  const initAction = async (name, option) => {      // 0. 檢查控制臺(tái)是否可以運(yùn)行`git `,      if (!shell.which('git')) {          console.log(symbols.error, '對(duì)不起,git命令不可用!');          shell.exit(1);      }      // 1. 驗(yàn)證輸入name是否合法      if (fs.existsSync(name)) {          console.log(symbols.warning,`已存在項(xiàng)目文件夾${name}!`);          return;      }      if (name.match(/[^A-Za-z0-9\u4e00-\u9fa5_-]/g)) {          console.log(symbols.error, '項(xiàng)目名稱存在非法字符!');          return;      }      // 2. 獲取option,確定模板類型(分支)      if (option.dev) branch = 'develop';      // 4. 下載模板      await clone(`direct:${remote}#${branch}`, name, { clone: true });  };  module.exports = initAction;

測(cè)試一下,不出意外就可以成功拉取項(xiàng)目了。

web前端中怎么實(shí)現(xiàn)可執(zhí)行模塊

這里拉取的項(xiàng)目是和遠(yuǎn)程倉(cāng)庫(kù)關(guān)聯(lián)的,我們需要將其刪掉(由于我們項(xiàng)目是svn管理,所以直接把.git文件夾刪掉,如果使用git的話,可以git init初始化即可),清理掉一些多余文件:

// commands/init.js  // 5. 清理文件  const deleteDir = ['.git', '.gitignore', 'README.md', 'docs']; // 需要清理的文件  const pwd = shell.pwd();  deleteDir.map(item => shell.rm('-rf', pwd + `/${name}/${item}`));

來(lái)點(diǎn)個(gè)性化

在上述過(guò)程中,我們實(shí)現(xiàn)了一個(gè)腳手架的基本功能,大致分為三個(gè)流程(拉取模板->創(chuàng)建項(xiàng)目->收尾清理),也解決了上面我項(xiàng)目中遇到的第一個(gè)問(wèn)題。接下來(lái),我們就來(lái)看下第二個(gè)問(wèn)題如何解決。

解決的思路就是在創(chuàng)建項(xiàng)目的時(shí)候,就通過(guò)命令行強(qiáng)制要求開發(fā)人員輸入對(duì)應(yīng)的配置,然后自動(dòng)寫入配置文件,這樣就可以有效避免忘記填寫的尷尬。當(dāng)然通過(guò)這種方式也可以實(shí)現(xiàn)根據(jù)用戶的輸入來(lái)動(dòng)態(tài)初始化項(xiàng)目,達(dá)到個(gè)性化的目的。

這里我們直接使用現(xiàn)成的輪子inquirer就可以搞定,效果和VueCli創(chuàng)建項(xiàng)目一樣,支持很多類型,比較強(qiáng)大,也比較簡(jiǎn)單,具體用法看官方文檔就可以了。這里我直接上代碼,在第4步(下載模板)前面增加如下:

// init.js  const inquirer = require('inquirer');  // 定義需要詢問(wèn)的問(wèn)題  const questions = [    {      type: 'input',      message: '請(qǐng)輸入模板名稱:',      name: 'name',      validate(val) {        if (!val) return '模板名稱不能為空!';        if (val.match(/[^A-Za-z0-9\u4e00-\u9fa5_-]/g)) return '模板名稱包含非法字符,請(qǐng)重新輸入';        return true;      }    },    {      type: 'input',      message: '請(qǐng)輸入模板關(guān)鍵詞(;分割):',      name: 'keywords'    },    {      type: 'input',      message: '請(qǐng)輸入模板簡(jiǎn)介:',      name: 'description'    },    {      type: 'list',      message: '請(qǐng)選擇模板類型:',      choices: ['響應(yīng)式', '桌面端', '移動(dòng)端'],      name: 'type'    },    {      type: 'list',      message: '請(qǐng)選擇模板分類:',      choices: ['整站', '單頁(yè)', '專題'],      name: 'category'    },    {      type: 'input',      message: '請(qǐng)輸入模板風(fēng)格:',      name: 'style'    },    {      type: 'input',      message: '請(qǐng)輸入模板色系:',      name: 'color'    },    {      type: 'input',      message: '請(qǐng)輸入您的名字:',     name: 'author'    }  ];  // 通過(guò)inquirer獲取到用戶輸入的內(nèi)容  const answers = await inquirer.prompt(questions);  // 將用戶的配置打印,確認(rèn)一下是否正確  console.log('------------------------');  console.log(answers);  let confirm = await inquirer.prompt([      {          type: 'confirm',          message: '確認(rèn)創(chuàng)建?',          default: 'Y',          name: 'isConfirm'      }  ]);  if (!confirm.isConfirm) return false;

web前端中怎么實(shí)現(xiàn)可執(zhí)行模塊

獲取到用戶輸入的配置以后,就可以寫入配置文件或者做個(gè)性化的處理了,這個(gè)太簡(jiǎn)單,我這里就不贅述了。

錦上添花

到這里,一個(gè)完全滿足需求的腳手架就完成了,但是作為一個(gè)有追求的程序員,我們可以在界面和易用性上面再做點(diǎn)什么:

  •  為異步操作加上loding動(dòng)畫,可以直接使用ora  

const installSpinner = ora('正在安裝依賴...').start();  if (shell.exec('npm install').code !== 0) {      console.log(symbols.warning, chalk.yellow('自動(dòng)安裝失敗,請(qǐng)手動(dòng)安裝!'));      installSpinner.fail(); // 安裝失敗      shell.exit(1);  }  installSpinner.succeed(chalk.green('依賴安裝成功!'));
  •  在操作成功或者失敗給出圖標(biāo)提示,使用log-symbols    

web前端中怎么實(shí)現(xiàn)可執(zhí)行模塊

  • 可以給文字加點(diǎn)顏色,同理用現(xiàn)成的輪子Chalk    

web前端中怎么實(shí)現(xiàn)可執(zhí)行模塊

  • 在安裝依賴或者其他耗時(shí)比較長(zhǎng)的時(shí)候,用戶可能會(huì)把終端切到后臺(tái),這時(shí)我們的操作完成后可以使用node-notifier發(fā)出系統(tǒng)通知給予用戶提示。 

notifier.notify({      title: 'YNCMS-template-cli',      icon: path.join(__dirname, 'coulson.png'),      message: ' ?(^&forall;^●)? 恭喜,項(xiàng)目創(chuàng)建成功!'  });
  •  在創(chuàng)建項(xiàng)目的時(shí)候,我們可能會(huì)需要執(zhí)行一些shell命令,可以使用shelljs來(lái)完成,例如我們要在項(xiàng)目創(chuàng)建結(jié)束后打開vscode并退出終端 

// 8. 打開編輯器  if (shell.which('code')) shell.exec('code ./');  shell.exit(1);

到此,關(guān)于“web前端中怎么實(shí)現(xiàn)可執(zhí)行模塊”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注億速云網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

web
AI