摘要:最近,筆者就在為組里的框架去做一套基本的工具。通過這邊文章,筆者希望大家都能簡單的去實現一個屬于自己的腳手架工具。我們在下新增文件,這個文件導出一個的類。結語到此,一個簡單的就制作完成了,大家可以參考等優秀的適當的擴展自己的工具。
你有沒有遇到過在沒有vue-cli、create-react-app這樣子的腳手架的時候一個文件一個文件的去拷貝老項目的配置文件。最近,筆者就在為組里的框架去做一套基本的cli工具。通過這邊文章,筆者希望大家都能簡單的去實現一個屬于自己的腳手架工具。
原文鏈接: https://juejin.im/user/57ac15...做好準備工作
首先,我們需要去新建一個項目并初始化package.json
mkdir my-cli && cd my-cli npm init
然后我們需要在項目中新建bin文件夾,并將package.json中提供一個bin字段并指向我們的bin文件夾下,這樣通過npm我們就可以實現指令的軟鏈了。
"bin": { "mycli": "bin/mycli" },
在mycli中,我們要在頭部增加這樣一句注釋,作用是"指定由哪個解釋器來執行腳本"。
#!/usr/bin/env node console.log("hello world");
接下來,全局安裝我們這個包,這樣我們就可以直接在本地使用mycli這個指令了。
sudo npm install -g提供基本模版
既然我們要去做一個初始化項目的cli,那么項目模版就必不可少了,筆者在這里提前準備了一個demo的項目目錄模版,這里就不展開贅述了。
其實核心邏輯很簡單,就是通過控制臺獲取到用戶的一些自定義選項,然后根據選項去從本地或者遠程倉庫拿到我們提前準備好的模版,將配置寫入模版并最后拷貝模版到本地就行了。
我們在src下新增creator.js文件,這個文件導出一個Creator的類。在這個類中現在僅需要三個簡單的方法:init用于初始化、ask用于和命令行交互獲取用戶選擇輸入的數據、write用于調用模版的構建方法去執行拷貝文件寫數據的任務。
class Creator { constructor() { // 存儲命令行獲取的數據,作為demo這里只要這兩個; this.options = { name: "", description: "", }; } // 初始化; init() {} // 和命令行交互; ask() {} // 拷貝&寫數據; write() {} } module.exports = Creator;
先去完善init方法,這個方法里我們僅需要調用ask方法和命令行交互并做一些提示即可(可以通過chalk這個庫去豐富我們的命令行交互色彩)
// ... init() { console.log(chalk.green("my cli 開始")); console.log(); this.ask(); } // ...
接下來是ask方法,在這個方法中,我們需要根據提示引導用戶輸入問題并獲取用戶的輸入,這里用到inquirer這個庫來和命令行交互。
// ... ask() { // 問題 const prompt = []; prompt.push({ type: "input", name: "name", message: "請輸入項目名稱", validate(input) { if (!input) { return "請輸入項目名稱!"; } if (fs.existsSync(input)) { return "項目名已重復!" } return true; } }); prompt.push({ type: "input", name: "description", message: "請輸入項目描述", }); // 返回promise return inquirer.prompt(prompt); } // ...
修改剛才的init方法,將ask方法改為Promise調用。
init() { console.log(chalk.green("my cli 開始")); console.log(); this.ask().then((answers) => { this.options = Object.assign({}, this.options, answers); console.log(this.options); }); }
現在我們去命令行試一下,修改bin/mycli文件,然后去運行mycli命令。
#!/usr/bin/env node const Creator = require("../src/creator.js"); const project = new Creator(); project.init();
在和用戶交互完畢并獲取到數據后,我們要做的就是去調用write方法執行拷貝構建了??紤]到日后可能增加很多的模版目錄,不妨我們將每一類的模版拷貝構建工作放到模版中的腳本去做,從而增大可擴展性,新增template/index.js文件。
接下來首先根據項目目錄結構創建文件夾(注意區分項目的執行目錄和項目目錄的關系)。
module.exports = function(creator, options, callback) { const { name, description } = options; // 獲取當前命令的執行目錄,注意和項目目錄區分 const cwd = process.cwd(); // 項目目錄 const projectPath = path.join(cwd, name); const buildPath = path.join(projectPath, "build"); const pagePath = path.join(projectPath, "page"); const srcPath = path.join(projectPath, "src"); // 新建項目目錄 // 同步創建目錄,以免文件目錄不對齊 fs.mkdirSync(projectPath); fs.mkdirSync(buildPath); fs.mkdirSync(pagePath); fs.mkdirSync(srcPath); callback(); }
然后回到creator.js文件,在Creator中的write調用這個方法。
// ... 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 構建開始")); const tplBuilder = require("../template/index.js"); tplBuilder(this, this.options, () => { console.log(chalk.green("my cli 構建完成")); console.log(); console.log(chalk.grey(`開始項目: cd ${this.options.name } && npm install`)); }); } // ...
在開啟文件拷貝寫數據之前,我們需要用到兩個庫mem-fs和mem-fs-editor,前者可以幫助我們在內存中創建一個臨時的文件store,后者可以以ejs的形式去編輯我們的文件。
現在constructor中初始化store。
constructor() { // 創建內存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中增加兩個方法copy和copyTpl分別用于直接拷貝文件和拷貝文件并注入數據。
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); }
然后我們根據ejs的語法修改模版中的package.json文件以實現數據注入的功能
{ "name": "<%= name %>", "version": "1.0.0", "description": "<%= description %>", "main": "index.js", "scripts": {}, "author": "", "license": "ISC" }
回到template/index.js中,對模版中的文件進行相應的拷貝和數據注入操作,最后打印一些可視化的信息。
module.exports = function(creator, options, callback) { const { name, description } = options; // 獲取當前命令的執行目錄,注意和項目目錄區分 const cwd = process.cwd(); // 項目目錄 const projectPath = path.join(cwd, name); const buildPath = path.join(projectPath, "build"); const pagePath = path.join(projectPath, "page"); const srcPath = path.join(projectPath, "src"); // 新建項目目錄 // 同步創建目錄,以免文件目錄不對齊 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(`創建項目: ${name}`)} ${chalk.green("? ")}`); console.log(`${chalk.grey(`創建目錄: ${name}/build`)} ${chalk.green("? ")}`); console.log(`${chalk.grey(`創建目錄: ${name}/page`)} ${chalk.green("? ")}`); console.log(`${chalk.grey(`創建目錄: ${name}/src`)} ${chalk.green("? ")}`); console.log(`${chalk.grey(`創建文件: ${name}/build/build.js`)} ${chalk.green("? ")}`); console.log(`${chalk.grey(`創建文件: ${name}/page/index.html`)} ${chalk.green("? ")}`); console.log(`${chalk.grey(`創建文件: ${name}/src/index.js`)} ${chalk.green("? ")}`); callback(); }); }
執行mycli指令創建項目,一個簡單的cli就完成了。
到此,一個簡單的cli就制作完成了,大家可以參考vue-cli、create-react-app等優秀的cli適當的擴展自己的cli工具。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/102989.html
摘要:方法實現將所有屬性掛載在觀察對象,將每一項做一個數據劫持就是將中每一項用定義新屬性并返回這個對象。當和發生變化時,自動會觸發視圖更新,獲取得到的也就是最新值。 MVVM及Vue實現原理 Github源碼地址:https://github.com/wyj2443573... mvvm 雙向數據綁定數據影響視圖,視圖影響數據angular 臟值檢測 vue數據劫持+發布訂閱模式vue 不...
摘要:組件結構同組件結構通過方法獲取元素的大小及其相對于視口的位置,之后對提示信息進行定位??梢杂脕磉M行一些復雜帶校驗的彈窗信息展示,也可以只用于簡單信息的展示??梢酝ㄟ^屬性來顯示任意標題,通過屬性來修改顯示區域的寬度。 手把手教你擼個vue2.0彈窗組件 在開始之前需要了解一下開發vue插件的前置知識,推薦先看一下vue官網的插件介紹 預覽地址 http://haogewudi.me/k...
摘要:組件結構同組件結構通過方法獲取元素的大小及其相對于視口的位置,之后對提示信息進行定位。可以用來進行一些復雜帶校驗的彈窗信息展示,也可以只用于簡單信息的展示??梢酝ㄟ^屬性來顯示任意標題,通過屬性來修改顯示區域的寬度。 手把手教你擼個vue2.0彈窗組件 在開始之前需要了解一下開發vue插件的前置知識,推薦先看一下vue官網的插件介紹 預覽地址 http://haogewudi.me/k...
閱讀 1164·2021-11-22 15:24
閱讀 4440·2021-09-23 11:51
閱讀 2302·2021-09-08 09:36
閱讀 3514·2019-08-30 15:43
閱讀 1295·2019-08-30 13:01
閱讀 1116·2019-08-30 12:48
閱讀 530·2019-08-29 12:52
閱讀 3366·2019-08-29 12:41