摘要:管理文件當前用戶目錄下文件的增刪改查是配置文件是默認的配置發布將本腳手架發布至上。
腳手架
vue-cli, create-react-app、react-native-cli 等都是非常優秀的腳手架,通過腳手架,我們可以快速初始化一個項目,無需自己從零開始一步步配置,有效提升開發體驗。盡管這些腳手架非常優秀,但是未必是符合我們的實際應用的,我們可以定制一個屬于自己的腳手架(或公司通用腳手架),來提升自己的開發效率。
更多優質文章可戳: https://github.com/YvetteLau/...
腳手架的作用
減少重復性的工作,不需要復制其他項目再刪除無關代碼,或者從零創建一個項目和文件。
可以根據交互動態生成項目結構和配置文件。
多人協作更為方便,不需要把文件傳來傳去。
實現的功能在開始之前,我們需要明確自己的腳手架需要哪些功能。vue init template-name project-name 、create-react-app project-name。我們這次編寫的腳手架(eos-cli)具備以下能力(腳手架的名字愛叫啥叫啥,我選用了Eos黎明女神):
eos init template-name project-name 根據遠程模板,初始化一個項目(遠程模板可配置)
eos config set
eos config get [
eos --version 查看當前版本號
eos -h
大家可以自行擴展其它的 commander,本篇文章旨在教大家如何實現一個腳手架。
效果展示
初始化一個項目
修改.eosrc文件,從 vuejs-template 下載模板
需要使用的第三方庫babel-cli/babel-env: 語法轉換
commander: 命令行工具
download-git-repo: 用來下載遠程模板
ini: 格式轉換
inquirer: 交互式命令行工具
ora: 顯示loading動畫
chalk: 修改控制臺輸出內容樣式
log-symbols: 顯示出 √ 或 × 等的圖標
關于這些第三方庫的說明,可以直接npm上查看相應的說明,此處不一一展開。
初始化項目創建一個空項目(eos-cli),使用 npm init 進行初始化。
安裝依賴npm install babel-cli babel-env chalk commander download-git-repo ini inquirer log-symbols ora目錄結構
├── bin │ └── www //可執行文件 ├── dist ├── ... //生成文件 └── src ├── config.js //管理eos配置文件 ├── index.js //主流程入口文件 ├── init.js //init command ├── main.js //入口文件 └── utils ├── constants.js //定義常量 ├── get.js //獲取模板 └── rc.js //配置文件 ├── .babelrc //babel配置文件 ├── package.json ├── README.mdbabel 配置
開發使用了ES6語法,使用 babel 進行轉義,
.bablerc
{ "presets": [ [ "env", { "targets": { "node": "current" } } ] ] }eos 命令
node.js 內置了對命令行操作的支持,package.json 中的 bin 字段可以定義命令名和關聯的執行文件。在 package.json 中添加 bin 字段
package.json
{ "name": "eos-cli", "version": "1.0.0", "description": "腳手架", "main": "index.js", "bin": { "eos": "./bin/www" }, "scripts": { "compile": "babel src -d dist", "watch": "npm run compile -- --watch" } }
www 文件
行首加入一行 #!/usr/bin/env node 指定當前腳本由node.js進行解析
#! /usr/bin/env node require("../dist/main.js");鏈接到全局環境
開發過程中為了方便調試,在當前的 eos-cli 目錄下執行 npm link,將 eos 命令鏈接到全局環境。
啟動項目npm run watch處理命令行
利用 commander 來處理命令行。
main
import program from "commander"; import { VERSION } from "./utils/constants"; import apply from "./index"; import chalk from "chalk"; /** * eos commands * - config * - init */ let actionMap = { init: { description: "generate a new project from a template", usages: [ "eos init templateName projectName" ] }, config: { alias: "cfg", description: "config .eosrc", usages: [ "eos config set下載模板", "eos config get ", "eos config remove " ] }, //other commands } // 添加 init / config 命令 Object.keys(actionMap).forEach((action) => { program.command(action) .description(actionMap[action].description) .alias(actionMap[action].alias) //別名 .action(() => { switch (action) { case "config": //配置 apply(action, ...process.argv.slice(3)); break; case "init": apply(action, ...process.argv.slice(3)); break; default: break; } }); }); function help() { console.log(" Usage:"); Object.keys(actionMap).forEach((action) => { actionMap[action].usages.forEach(usage => { console.log(" - " + usage); }); }); console.log(" "); } program.usage(" [options]"); // eos -h program.on("-h", help); program.on("--help", help); // eos -V VERSION 為 package.json 中的版本號 program.version(VERSION, "-V --version").parse(process.argv); // eos 不帶參數時 if (!process.argv.slice(2).length) { program.outputHelp(make_green); } function make_green(txt) { return chalk.green(txt); }
download-git-repo 支持從 Github、Gitlab 下載遠程倉庫到本地。
get.js
import { getAll } from "./rc"; import downloadGit from "download-git-repo"; export const downloadLocal = async (templateName, projectName) => { let config = await getAll(); let api = `${config.registry}/${templateName}`; return new Promise((resolve, reject) => { //projectName 為下載到的本地目錄 downloadGit(api, projectName, (err) => { if (err) { reject(err); } resolve(); }); }); }init 命令 命令行交互
在用戶執行 init 命令后,向用戶提出問題,接收用戶的輸入并作出相應的處理。命令行交互利用 inquirer 來實現:
inquirer.prompt([ { name: "description", message: "Please enter the project description: " }, { name: "author", message: "Please enter the author name: " } ]).then((answer) => { //... });視覺美化
在用戶輸入之后,開始下載模板,這時候使用 ora 來提示用戶正在下載模板,下載結束之后,也給出提示。
import ora from "ora"; let loading = ora("downloading template ..."); loading.start(); //download loading.succeed(); //或 loading.fail();
index.js
import { downloadLocal } from "./utils/get"; import ora from "ora"; import inquirer from "inquirer"; import fs from "fs"; import chalk from "chalk"; import symbol from "log-symbols"; let init = async (templateName, projectName) => { //項目不存在 if (!fs.existsSync(projectName)) { //命令行交互 inquirer.prompt([ { name: "description", message: "Please enter the project description: " }, { name: "author", message: "Please enter the author name: " } ]).then(async (answer) => { //下載模板 選擇模板 //通過配置文件,獲取模板信息 let loading = ora("downloading template ..."); loading.start(); downloadLocal(templateName, projectName).then(() => { loading.succeed(); const fileName = `${projectName}/package.json`; if(fs.existsSync(fileName)){ const data = fs.readFileSync(fileName).toString(); let json = JSON.parse(data); json.name = projectName; json.author = answer.author; json.description = answer.description; //修改項目文件夾中 package.json 文件 fs.writeFileSync(fileName, JSON.stringify(json, null, " "), "utf-8"); console.log(symbol.success, chalk.green("Project initialization finished!")); } }, () => { loading.fail(); }); }); }else { //項目已經存在 console.log(symbol.error, chalk.red("The project already exists")); } } module.exports = init;config 配置
eos config set registry vuejs-templates
config 配置,支持我們使用其它倉庫的模板,例如,我們可以使用 vuejs-templates 中的倉庫作為模板。這樣有一個好處:更新模板無需重新發布腳手架,使用者無需重新安裝,并且可以自由選擇下載目標。
config.js
// 管理 .eosrc 文件 (當前用戶目錄下) import { get, set, getAll, remove } from "./utils/rc"; let config = async (action, key, value) => { switch (action) { case "get": if (key) { let result = await get(key); console.log(result); } else { let obj = await getAll(); Object.keys(obj).forEach(key => { console.log(`${key}=${obj[key]}`); }) } break; case "set": set(key, value); break; case "remove": remove(key); break; default: break; } } module.exports = config;
rc.js
.eosrc 文件的增刪改查
import { RC, DEFAULTS } from "./constants"; import { decode, encode } from "ini"; import { promisify } from "util"; import chalk from "chalk"; import fs from "fs"; const exits = promisify(fs.exists); const readFile = promisify(fs.readFile); const writeFile = promisify(fs.writeFile); //RC 是配置文件 //DEFAULTS 是默認的配置 export const get = async (key) => { const exit = await exits(RC); let opts; if (exit) { opts = await readFile(RC, "utf8"); opts = decode(opts); return opts[key]; } return ""; } export const getAll = async () => { const exit = await exits(RC); let opts; if (exit) { opts = await readFile(RC, "utf8"); opts = decode(opts); return opts; } return {}; } export const set = async (key, value) => { const exit = await exits(RC); let opts; if (exit) { opts = await readFile(RC, "utf8"); opts = decode(opts); if(!key) { console.log(chalk.red(chalk.bold("Error:")), chalk.red("key is required")); return; } if(!value) { console.log(chalk.red(chalk.bold("Error:")), chalk.red("value is required")); return; } Object.assign(opts, { [key]: value }); } else { opts = Object.assign(DEFAULTS, { [key]: value }); } await writeFile(RC, encode(opts), "utf8"); } export const remove = async (key) => { const exit = await exits(RC); let opts; if (exit) { opts = await readFile(RC, "utf8"); opts = decode(opts); delete opts[key]; await writeFile(RC, encode(opts), "utf8"); } }發布
npm publish 將本腳手架發布至npm上。其它用戶可以通過 npm install eos-cli -g 全局安裝。
即可使用 eos 命令。
本項目完整代碼請戳: https://github.com/YvetteLau/...
編寫本文,雖然花費了一定時間,但是在這個過程中,我也學習到了很多知識,謝謝各位小伙伴愿意花費寶貴的時間閱讀本文,如果本文給了您一點幫助或者是啟發,請不要吝嗇你的贊和Star,您的肯定是我前進的最大動力。
https://github.com/YvetteLau/...
[1] npm依賴文檔(https://www.npmjs.com/package...
關注公眾號,加入技術交流群。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/106017.html
摘要:前言一次在使用的時候,發現使用命令行的時候有些關鍵字會自動提示。介紹隨著,等框架的流行,命令行工具越來越流行,但是很多時候命令太多,根本無法記住所有參數,或者參數太長輸入太不方便。下文,我們一起來優化這個工具。備注不支持自動補全 前言 一次在使用symfony的時候,發現使用命令行的時候有些關鍵字會自動提示。 showImg(https://segmentfault.com/img/b...
摘要:最近項目中遇到一個需求,需要把一張圖片加上平鋪的水印類似這樣的效果首先想到的是用完成這種功能,因為我之前也沒有接觸過,所以做這個功能的時候,就是一步一步的摸索中學習,過程還是挺的,接下來跟我一步步來實現這個功能以及發現一些的坑吧。 最近項目中遇到一個需求,需要把一張圖片加上平鋪的水印 類似這樣的效果showImg(https://segmentfault.com/img/remote/...
閱讀 2499·2021-11-25 09:43
閱讀 2609·2021-11-16 11:50
閱讀 3290·2021-10-09 09:44
閱讀 3201·2021-09-26 09:55
閱讀 2839·2019-08-30 13:50
閱讀 1031·2019-08-29 13:24
閱讀 2076·2019-08-26 11:44
閱讀 2802·2019-08-26 11:37