成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

手把手帶你擼一個(gè)cli工具

xingqiba / 2696人閱讀

摘要:最近,筆者就在為組里的框架去做一套基本的工具。通過這邊文章,筆者希望大家都能簡(jiǎn)單的去實(shí)現(xiàn)一個(gè)屬于自己的腳手架工具。我們?cè)谙滦略鑫募@個(gè)文件導(dǎo)出一個(gè)的類。結(jié)語到此,一個(gè)簡(jiǎn)單的就制作完成了,大家可以參考等優(yōu)秀的適當(dāng)?shù)臄U(kuò)展自己的工具。

你有沒有遇到過在沒有vue-cli、create-react-app這樣子的腳手架的時(shí)候一個(gè)文件一個(gè)文件的去拷貝老項(xiàng)目的配置文件。最近,筆者就在為組里的框架去做一套基本的cli工具。通過這邊文章,筆者希望大家都能簡(jiǎn)單的去實(shí)現(xiàn)一個(gè)屬于自己的腳手架工具。

原文鏈接: https://juejin.im/user/57ac15...
做好準(zhǔn)備工作

首先,我們需要去新建一個(gè)項(xiàng)目并初始化package.json

mkdir my-cli && cd my-cli
npm init

然后我們需要在項(xiàng)目中新建bin文件夾,并將package.json中提供一個(gè)bin字段并指向我們的bin文件夾下,這樣通過npm我們就可以實(shí)現(xiàn)指令的軟鏈了。

"bin": {
  "mycli": "bin/mycli"
},

在mycli中,我們要在頭部增加這樣一句注釋,作用是"指定由哪個(gè)解釋器來執(zhí)行腳本"

#!/usr/bin/env node

console.log("hello world");

接下來,全局安裝我們這個(gè)包,這樣我們就可以直接在本地使用mycli這個(gè)指令了。

sudo npm install -g
提供基本模版

既然我們要去做一個(gè)初始化項(xiàng)目的cli,那么項(xiàng)目模版就必不可少了,筆者在這里提前準(zhǔn)備了一個(gè)demo的項(xiàng)目目錄模版,這里就不展開贅述了。

編寫邏輯

其實(shí)核心邏輯很簡(jiǎn)單,就是通過控制臺(tái)獲取到用戶的一些自定義選項(xiàng),然后根據(jù)選項(xiàng)去從本地或者遠(yuǎn)程倉(cāng)庫(kù)拿到我們提前準(zhǔn)備好的模版,將配置寫入模版并最后拷貝模版到本地就行了。

我們?cè)趕rc下新增creator.js文件,這個(gè)文件導(dǎo)出一個(gè)Creator的類。在這個(gè)類中現(xiàn)在僅需要三個(gè)簡(jiǎn)單的方法:init用于初始化、ask用于和命令行交互獲取用戶選擇輸入的數(shù)據(jù)、write用于調(diào)用模版的構(gòu)建方法去執(zhí)行拷貝文件寫數(shù)據(jù)的任務(wù)。

class Creator {
  constructor() {
    // 存儲(chǔ)命令行獲取的數(shù)據(jù),作為demo這里只要這兩個(gè);
    this.options = {
      name: "",
      description: "",
    };
  }
  // 初始化;
  init() {}
  // 和命令行交互;
  ask() {}
  // 拷貝&寫數(shù)據(jù);
  write() {}
}

module.exports = Creator;

先去完善init方法,這個(gè)方法里我們僅需要調(diào)用ask方法和命令行交互并做一些提示即可(可以通過chalk這個(gè)庫(kù)去豐富我們的命令行交互色彩)

// ...
init() {
  console.log(chalk.green("my cli 開始"));
  console.log();
  this.ask();
}
// ...

接下來是ask方法,在這個(gè)方法中,我們需要根據(jù)提示引導(dǎo)用戶輸入問題并獲取用戶的輸入,這里用到inquirer這個(gè)庫(kù)來和命令行交互。

// ...
ask() {
  // 問題
  const prompt = [];

  prompt.push({
    type: "input",
    name: "name",
    message: "請(qǐng)輸入項(xiàng)目名稱",
    validate(input) {
      if (!input) {
        return "請(qǐng)輸入項(xiàng)目名稱!";
      }

      if (fs.existsSync(input)) {
        return "項(xiàng)目名已重復(fù)!"
      }

      return true;
    }
  });

  prompt.push({
    type: "input",
    name: "description",
    message: "請(qǐng)輸入項(xiàng)目描述",
  });

  // 返回promise
  return inquirer.prompt(prompt);
}
// ...

修改剛才的init方法,將ask方法改為Promise調(diào)用。

init() {
  console.log(chalk.green("my cli 開始"));
  console.log();
  this.ask().then((answers) => {
    this.options = Object.assign({}, this.options, answers);
    console.log(this.options);
  });
}

現(xiàn)在我們?nèi)ッ钚性囈幌?,修改bin/mycli文件,然后去運(yùn)行mycli命令。

#!/usr/bin/env node

const Creator = require("../src/creator.js");

const project = new Creator();

project.init();

在和用戶交互完畢并獲取到數(shù)據(jù)后,我們要做的就是去調(diào)用write方法執(zhí)行拷貝構(gòu)建了??紤]到日后可能增加很多的模版目錄,不妨我們將每一類的模版拷貝構(gòu)建工作放到模版中的腳本去做,從而增大可擴(kuò)展性,新增template/index.js文件。

接下來首先根據(jù)項(xiàng)目目錄結(jié)構(gòu)創(chuàng)建文件夾(注意區(qū)分項(xiàng)目的執(zhí)行目錄和項(xiàng)目目錄的關(guān)系)。

module.exports = function(creator, options, callback) {
  const { name, description } = options;

  // 獲取當(dāng)前命令的執(zhí)行目錄,注意和項(xiàng)目目錄區(qū)分
  const cwd = process.cwd();
  // 項(xiàng)目目錄
  const projectPath = path.join(cwd, name);
  const buildPath = path.join(projectPath, "build");
  const pagePath = path.join(projectPath, "page");
  const srcPath = path.join(projectPath, "src");

  // 新建項(xiàng)目目錄
  // 同步創(chuàng)建目錄,以免文件目錄不對(duì)齊
  fs.mkdirSync(projectPath);
  fs.mkdirSync(buildPath);
  fs.mkdirSync(pagePath);
  fs.mkdirSync(srcPath);

  callback();
}

然后回到creator.js文件,在Creator中的write調(diào)用這個(gè)方法。

// ...
init() {
  console.log(chalk.green("my cli 開始"));
  console.log();
  this.ask().then((answers) => {
    this.options = Object.assign({}, this.options, answers);

    this.write();
  });
}

// ...

write() {
  console.log(chalk.green("my cli 構(gòu)建開始"));
  const tplBuilder = require("../template/index.js");
  tplBuilder(this, this.options, () => {
    console.log(chalk.green("my cli 構(gòu)建完成"));
    console.log();
    console.log(chalk.grey(`開始項(xiàng)目:  cd ${this.options.name } && npm install`));
  });
}
// ...

在開啟文件拷貝寫數(shù)據(jù)之前,我們需要用到兩個(gè)庫(kù)mem-fsmem-fs-editor,前者可以幫助我們?cè)趦?nèi)存中創(chuàng)建一個(gè)臨時(shí)的文件store,后者可以以ejs的形式去編輯我們的文件。

現(xiàn)在constructor中初始化store。

constructor() {
  // 創(chuàng)建內(nèi)存store
  const store = memFs.create();
  this.fs = memFsEditor.create(store);

  this.options = {
    name: "",
    description: "",
  };

  this.rootPath = path.resolve(__dirname, "../");
  this.tplDirPath = path.join(this.rootPath, "template");
}

接下來在Creator中增加兩個(gè)方法copy和copyTpl分別用于直接拷貝文件和拷貝文件并注入數(shù)據(jù)。

getTplPath(file) {
  return path.join(this.tplDirPath, file);
}

copyTpl(file, to, data = {}) {
  const tplPath = this.getTplPath(file);
  this.fs.copyTpl(tplPath, to, data);
}

copy(file, to) {
  const tplPath = this.getTplPath(file);
  this.fs.copy(tplPath, to);
}

然后我們根據(jù)ejs的語法修改模版中的package.json文件以實(shí)現(xiàn)數(shù)據(jù)注入的功能

{
  "name": "<%= name %>",
  "version": "1.0.0",
  "description": "<%= description %>",
  "main": "index.js",
  "scripts": {},
  "author": "",
  "license": "ISC"
}

回到template/index.js中,對(duì)模版中的文件進(jìn)行相應(yīng)的拷貝和數(shù)據(jù)注入操作,最后打印一些可視化的信息。

module.exports = function(creator, options, callback) {
  const { name, description } = options;

  // 獲取當(dāng)前命令的執(zhí)行目錄,注意和項(xiàng)目目錄區(qū)分
  const cwd = process.cwd();
  // 項(xiàng)目目錄
  const projectPath = path.join(cwd, name);
  const buildPath = path.join(projectPath, "build");
  const pagePath = path.join(projectPath, "page");
  const srcPath = path.join(projectPath, "src");

  // 新建項(xiàng)目目錄
  // 同步創(chuàng)建目錄,以免文件目錄不對(duì)齊
  fs.mkdirSync(projectPath);
  fs.mkdirSync(buildPath);
  fs.mkdirSync(pagePath);
  fs.mkdirSync(srcPath);

  creator.copyTpl("packagejson", path.join(projectPath, "package.json"), {
    name,
    description,
  });

  creator.copy("build/build.js", path.join(buildPath, "build.js"));

  creator.copy("page/index.html", path.join(pagePath, "index.html"));

  creator.copy("src/index.js", path.join(srcPath, "index.js"));

  creator.fs.commit(() => {
    console.log();
    console.log(`${chalk.grey(`創(chuàng)建項(xiàng)目: ${name}`)} ${chalk.green("? ")}`);
    console.log(`${chalk.grey(`創(chuàng)建目錄: ${name}/build`)} ${chalk.green("? ")}`);
    console.log(`${chalk.grey(`創(chuàng)建目錄: ${name}/page`)} ${chalk.green("? ")}`);
    console.log(`${chalk.grey(`創(chuàng)建目錄: ${name}/src`)} ${chalk.green("? ")}`);
    console.log(`${chalk.grey(`創(chuàng)建文件: ${name}/build/build.js`)} ${chalk.green("? ")}`);
    console.log(`${chalk.grey(`創(chuàng)建文件: ${name}/page/index.html`)} ${chalk.green("? ")}`);
    console.log(`${chalk.grey(`創(chuàng)建文件: ${name}/src/index.js`)} ${chalk.green("? ")}`);

    callback();
  });
}

執(zhí)行mycli指令創(chuàng)建項(xiàng)目,一個(gè)簡(jiǎn)單的cli就完成了。

結(jié)語

到此,一個(gè)簡(jiǎn)單的cli就制作完成了,大家可以參考vue-cli、create-react-app等優(yōu)秀的cli適當(dāng)?shù)臄U(kuò)展自己的cli工具。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/102989.html

相關(guān)文章

  • 了解MVVM及Vue實(shí)現(xiàn)原理,把手你擼源碼。

    摘要:方法實(shí)現(xiàn)將所有屬性掛載在觀察對(duì)象,將每一項(xiàng)做一個(gè)數(shù)據(jù)劫持就是將中每一項(xiàng)用定義新屬性并返回這個(gè)對(duì)象。當(dāng)和發(fā)生變化時(shí),自動(dòng)會(huì)觸發(fā)視圖更新,獲取得到的也就是最新值。 MVVM及Vue實(shí)現(xiàn)原理 Github源碼地址:https://github.com/wyj2443573... mvvm 雙向數(shù)據(jù)綁定數(shù)據(jù)影響視圖,視圖影響數(shù)據(jù)angular 臟值檢測(cè) vue數(shù)據(jù)劫持+發(fā)布訂閱模式vue 不...

    cooxer 評(píng)論0 收藏0
  • 把手你擼個(gè)vue2.0彈窗組件

    摘要:組件結(jié)構(gòu)同組件結(jié)構(gòu)通過方法獲取元素的大小及其相對(duì)于視口的位置,之后對(duì)提示信息進(jìn)行定位??梢杂脕磉M(jìn)行一些復(fù)雜帶校驗(yàn)的彈窗信息展示,也可以只用于簡(jiǎn)單信息的展示。可以通過屬性來顯示任意標(biāo)題,通過屬性來修改顯示區(qū)域的寬度。 手把手教你擼個(gè)vue2.0彈窗組件 在開始之前需要了解一下開發(fā)vue插件的前置知識(shí),推薦先看一下vue官網(wǎng)的插件介紹 預(yù)覽地址 http://haogewudi.me/k...

    mrli2016 評(píng)論0 收藏0
  • 把手你擼個(gè)vue2.0彈窗組件

    摘要:組件結(jié)構(gòu)同組件結(jié)構(gòu)通過方法獲取元素的大小及其相對(duì)于視口的位置,之后對(duì)提示信息進(jìn)行定位??梢杂脕磉M(jìn)行一些復(fù)雜帶校驗(yàn)的彈窗信息展示,也可以只用于簡(jiǎn)單信息的展示。可以通過屬性來顯示任意標(biāo)題,通過屬性來修改顯示區(qū)域的寬度。 手把手教你擼個(gè)vue2.0彈窗組件 在開始之前需要了解一下開發(fā)vue插件的前置知識(shí),推薦先看一下vue官網(wǎng)的插件介紹 預(yù)覽地址 http://haogewudi.me/k...

    taoszu 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<