摘要:比如一個(gè)模板用于創(chuàng)建的組件庫(kù),一個(gè)模板用于創(chuàng)建的組件庫(kù),還有一個(gè)模板用于創(chuàng)建的工具函數(shù)類庫(kù)。
緣起
最近公司內(nèi)部想搭建一個(gè)私有的 npm 倉(cāng)庫(kù),用于將平時(shí)用到次數(shù)相當(dāng)頻繁的工具或者組件獨(dú)立出來(lái),方便多帶帶管理,隨著項(xiàng)目的規(guī)模變大,數(shù)量變多,單純的復(fù)制粘粘無(wú)疑在優(yōu)雅以及實(shí)用性上都無(wú)法滿足我們的需求,所以進(jìn)一步模塊化是必然的。
但是一個(gè)組件庫(kù)的建立其實(shí)是一個(gè)非常麻煩的過(guò)程,基礎(chǔ) webpack 的配置不用多說(shuō),接著你還要配合增加一些 es-lint 之類的工具來(lái)規(guī)范化團(tuán)隊(duì)成員的代碼。在開(kāi)發(fā)過(guò)程中,你自然需要一個(gè)目錄來(lái)承載使用示例,方便 dev 這個(gè)組件,隨后呢,你還得建立一個(gè)打包規(guī)范,發(fā)布到私有 npm 倉(cāng)庫(kù)中。
如此一來(lái),必然大大降低我們的積極性,所以不如創(chuàng)建一個(gè)用于建立模塊包的腳手架工具,方便我們項(xiàng)目的初始化。
tips:最終成品在底部
私有 NPM這里簡(jiǎn)單提及一下 私有 npm 的搭建。
npm i verdaccio -g
pm2 start verdaccio
推薦配合 nrm 使用 快速切換倉(cāng)庫(kù)地址
verdaccio github
還整個(gè)意大利名,屬實(shí)洋氣。
工具在進(jìn)入正題之前,我先介紹一些要點(diǎn)和工具,有了這寫關(guān)鍵點(diǎn),寫起來(lái)其實(shí)就相當(dāng)簡(jiǎn)單了。
npm bin大家有沒(méi)有想過(guò)一些全局安裝的工具,他是如何做到在命令行里面自由調(diào)用的呢?
事實(shí)上這個(gè)東西是 npm 提供的鏈接功能
// package.json { "name": "lucky-for-you", "bin": { "lucky": "bin/lucky" } }
當(dāng)這樣的一個(gè)模塊被發(fā)布之后,一旦有人使用 -g 參數(shù)全局安裝
sudo npm i luck-for-you -g/usr/local/bin/lucky -> /usr/local/lib/node_modules/luckytiger-package-cli/bin/lucky # npm 幫你進(jìn)行鏈接
npm 事實(shí)上會(huì)幫你進(jìn)行一次鏈接,鏈接到你操作系統(tǒng)的 Path 之中,從而但你敲出 Lucky 這個(gè)命令的時(shí)候,能從 path 中成功找到對(duì)應(yīng)的程序
另外一點(diǎn)就是用于鏈接執(zhí)行的文件 一般在開(kāi)頭都要加上如下內(nèi)容,讓 bash 能夠正確識(shí)別該文件應(yīng)該如何執(zhí)行
#!/usr/bin/env node // 意味使用 node 運(yùn)行該文件 // next scriptCommander.js
tj 大神的作品,可以方便的書寫命令行工具。能夠自動(dòng)生成幫助命令
const program = require("commander"); program.version("0.0.1").usage("[options]"); program .command("create ") .description("創(chuàng)建一個(gè)全新的 npm 組件模塊") .action((name, cmd) => { const options = cleanArgs(cmd); require("../lib/create")(name, options); }); // 用戶未輸入完整命令 輸出幫助 if (!process.argv.slice(2).length) { program.outputHelp(); } program.parse(process.argv);
Commander.js github
inquirer事實(shí)上當(dāng)我第一次使用 vue-cli3.0 的時(shí)候,里面的命令行表單真是非常驚艷,翻了 vue-cli3 的源碼 找到了這款工具,用于命令行的表單。能夠更加直觀的配置選項(xiàng)。
inquirer .prompt([ { type: "list", name: "template", message: "template: 請(qǐng)選擇項(xiàng)目起始模板", choices: [ { key: "1", name: "JavaScript Library - 適用于普通 JS 庫(kù)", value: "js-lib", }, { key: "2", name: "Vue-components - 適用于 Vue 組件庫(kù)", value: "vue-component", }, ], }, { type: "input", name: "author", message: "author: 請(qǐng)輸入你的名字", validate: function(value) { return !!value; }, }, { type: "input", name: "desc", message: "desc: 請(qǐng)輸入項(xiàng)目描述", validate: function(value) { return !!value; }, }, { type: "confirm", name: "confirm", message: "confirm: 完成配置了?", default: false, }, ]) .then(answers => { console.log(answers.template); console.log(answers.author); console.log(answers.desc); });
還有很多的表單類型,我這里幾個(gè)最簡(jiǎn)單的 list + input + confirm 就足夠了。
inquire github
開(kāi)始構(gòu)建現(xiàn)在開(kāi)始分享我的構(gòu)建流程。由于代碼量比較大,挨個(gè)文件帖出來(lái)沒(méi)有什么必要,所以我這里只做簡(jiǎn)單介紹,具體的可以查看我的 github項(xiàng)目。
我把我的 cli 工具大致分為兩部分 template模板 + 創(chuàng)建器
z
創(chuàng)建器的主要功能是吸收用戶的可選項(xiàng),基于模板進(jìn)行復(fù)制+渲染。Vue-cli3.0對(duì)于這部分操作會(huì)更加復(fù)雜,他把模板里面具體的功能都抽象成了一個(gè) Plugin,可以按需組建模板,對(duì)于面向普遍大眾當(dāng)然是更好的。
但是我這個(gè)項(xiàng)目因?yàn)槭枪緝?nèi)部用,所以不太需要太過(guò)泛化的設(shè)計(jì),一個(gè)模板直接解決一個(gè)問(wèn)題,簡(jiǎn)化模型就可以了。比如一個(gè)模板用于創(chuàng)建 Vue 的組件庫(kù),一個(gè)模板用于創(chuàng)建 React 的組件庫(kù),還有一個(gè)模板用于創(chuàng)建JavaScript 的工具函數(shù)類庫(kù)。
如此一來(lái)我們的 template模板 創(chuàng)建器在一定程度上可以做到解耦,也就是說(shuō)日后需要更多類型的模板,不需要修改創(chuàng)建器部分的代碼。
目錄結(jié)構(gòu)├── README.md ├── bin │ └── lucky #主程序 ├── lib │ ├── copy.js #復(fù)制 │ └── create.js #主創(chuàng)建器 ├── package-lock.json ├── package.json ├── templates │ ├── config.js #模板配置 解耦 │ ├── js-lib #預(yù)設(shè)模板1 │ └── vue-component #預(yù)設(shè)模板2 ├── utils # 工具目錄 │ └── dir.jspackage.json
{ "name": "luckytiger-package-cli", "version": "1.1.14", "description": "package-cli", "bin": { "lucky": "bin/lucky" }, "scripts": { "lucky": "node bin/lucky", "bootstarp": "cnpm i && cd ./templates/js-lib/ && cnpm i && cd ../vue-component/ && cnpm i ", "dev:js-lib": "cd templates/js-lib && npm run dev", "dev:vue-component": "cd templates/vue-component && npm run dev", "dev:create": "rm -rf test-app && node bin/lucky create test-app", "clear": "sudo rm -rf node_modules && sudo rm -rf templates/js-lib/node_modules && sudo rm -rf templates/vue-component/node_modules" }, "author": "zhangzhengyi", "license": "ISC", "dependencies": { "chalk": "^2.4.2", "commander": "^2.20.0", "ejs": "^2.6.2", "inquirer": "^6.4.1", "validate-npm-package-name": "^3.0.0" } }
配置了一些腳本 方便快速 DEV 模板的效果。
這樣運(yùn)行
npm run dev:js-lib
就能查看和開(kāi)發(fā) js-lib 這個(gè)模板
主程序bin/lucky
#!/usr/bin/env node const program = require("commander") program.version("0.0.1").usage("[options]") program .command("create ") .description("創(chuàng)建一個(gè)全新的 npm 組件模塊") .action((name, cmd) => { const options = cleanArgs(cmd) require("../lib/create")(name, options) }) if (!process.argv.slice(2).length) { program.outputHelp() } program.parse(process.argv) // commander passes the Command object itself as options, // extract only actual options into a fresh object. function cleanArgs(cmd) { const args = {} cmd.options.forEach(o => { const key = camelize(o.long.replace(/^--/, "")) // if an option is not present and Command has a method with the same name // it should not be copied if (typeof cmd[key] !== "function" && typeof cmd[key] !== "undefined") { args[key] = cmd[key] } }) return args }
這個(gè)文件主要是做一下基本的命令設(shè)置 利用了 commander這個(gè)庫(kù)
如果用戶調(diào)用了創(chuàng)建命令,就會(huì)轉(zhuǎn)發(fā)給 lib/create.js 處理
主創(chuàng)建器lib/cerate.js
const path = require("path") const inquirer = require("inquirer") const validateProjectName = require("validate-npm-package-name") const chalk = require("chalk") const copy = require("./copy") const fs = require("fs") const dir = require("../utils/dir") const templates = require("../templates/config") async function create(projectName, options) { const cwd = options.cwd || process.cwd() const inCurrent = projectName === "." const name = inCurrent ? path.relative("../", cwd) : projectName const targetDir = path.resolve(cwd, projectName || ".") const result = validateProjectName(name) if (!result.validForNewPackages) { console.error(chalk.red(`無(wú)效的項(xiàng)目名: "${name}"`)) result.errors && result.errors.forEach(err => { console.error(chalk.red.dim("Error: " + err)) }) result.warnings && result.warnings.forEach(warn => { console.error(chalk.red.dim("Warning: " + warn)) }) return } if (!dir.isDir(targetDir)) { fs.mkdirSync(targetDir) } else { console.error(chalk.red(`該目錄下已經(jīng)存在該文件夾 請(qǐng)刪除或者修改項(xiàng)目名`)) return } const answers = await inquirer.prompt([ { type: "list", name: "template", message: "template: 請(qǐng)選擇項(xiàng)目模板", choices: templates.map((v, i) => ({ key: i, name: v.name, value: v.dir })) }, { type: "input", name: "author", message: "author: 請(qǐng)輸入你的名字", validate: function(value) { return !!value } }, { type: "input", name: "desc", message: "desc: 請(qǐng)輸入項(xiàng)目描述", validate: function(value) { return !!value } }, { type: "confirm", name: "confirm", message: "confirm: 完成配置了?", default: false } ]) // 啟動(dòng)復(fù)制流程 const sourceDir = path.resolve(__dirname, "..", "templates", answers.template) console.log(chalk.blue(`
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/105566.html
摘要:什么是讀音,類似于是一套用于構(gòu)建用戶界面的漸進(jìn)式框架。的核心庫(kù)只關(guān)注視圖層,不僅易于上手,還便于與第三方庫(kù)或既有項(xiàng)目整合。 什么是vue.js Vue (讀音 /vju?/,類似于 view) 是一套用于構(gòu)建用戶界面的漸進(jìn)式框架。與其它大型框架不同的是,Vue 被設(shè)計(jì)為可以自底向上逐層應(yīng)用。Vue 的核心庫(kù)只關(guān)注視圖層,不僅易于上手,還便于與第三方庫(kù)或既有項(xiàng)目整合。另一方面,當(dāng)與現(xiàn)代化...
摘要:的官方下載地址點(diǎn)我進(jìn)入的官方下載地址下載電腦系統(tǒng)對(duì)應(yīng)文件,然后進(jìn)行安裝,安裝成功之后通過(guò)命令行工具進(jìn)入安裝目錄。注系統(tǒng)命令行工具通過(guò)開(kāi)始菜單輸入打開(kāi),系統(tǒng)為終端。 showImg(https://segmentfault.com/img/bVPL6q?w=200&h=200); Vue — 漸進(jìn)式 JavaScript 框架 介紹 Vue.js 是什么 vue.js 是一套構(gòu)建用戶界面...
摘要:的官方下載地址點(diǎn)我進(jìn)入的官方下載地址下載電腦系統(tǒng)對(duì)應(yīng)文件,然后進(jìn)行安裝,安裝成功之后通過(guò)命令行工具進(jìn)入安裝目錄。注系統(tǒng)命令行工具通過(guò)開(kāi)始菜單輸入打開(kāi),系統(tǒng)為終端。 showImg(https://segmentfault.com/img/bVPL6q?w=200&h=200); Vue — 漸進(jìn)式 JavaScript 框架 介紹 Vue.js 是什么 vue.js 是一套構(gòu)建用戶界面...
摘要:的官方下載地址點(diǎn)我進(jìn)入的官方下載地址下載電腦系統(tǒng)對(duì)應(yīng)文件,然后進(jìn)行安裝,安裝成功之后通過(guò)命令行工具進(jìn)入安裝目錄。注系統(tǒng)命令行工具通過(guò)開(kāi)始菜單輸入打開(kāi),系統(tǒng)為終端。 showImg(https://segmentfault.com/img/bVPL6q?w=200&h=200); Vue — 漸進(jìn)式 JavaScript 框架 介紹 Vue.js 是什么 vue.js 是一套構(gòu)建用戶界面...
摘要:寫在前面使用框架開(kāi)發(fā)時(shí),很多人會(huì)選擇官方提供的腳手架,最新的已經(jīng)更新到完全無(wú)配置,只需下載就能方便的使用構(gòu)建的項(xiàng)目工程,但基礎(chǔ)的并不能滿足正常的項(xiàng)目開(kāi)發(fā),在開(kāi)發(fā)中我們需要根據(jù)自己的習(xí)慣和業(yè)務(wù)功能而添加些基礎(chǔ)功能。 寫在前面 使用vue框架開(kāi)發(fā)時(shí),很多人會(huì)選擇vue官方提供的cli腳手架,最新的cli已經(jīng)更新到3.0完全無(wú)配置,只需下載就能方便的使用vuecli構(gòu)建的項(xiàng)目工程,但基礎(chǔ)的c...
閱讀 1650·2023-04-26 02:11
閱讀 2993·2023-04-25 16:18
閱讀 3722·2021-09-06 15:00
閱讀 2638·2019-08-30 15:55
閱讀 1943·2019-08-30 13:20
閱讀 2060·2019-08-26 18:36
閱讀 3134·2019-08-26 11:40
閱讀 2553·2019-08-26 10:11