摘要:比如一個模板用于創建的組件庫,一個模板用于創建的組件庫,還有一個模板用于創建的工具函數類庫。
緣起
最近公司內部想搭建一個私有的 npm 倉庫,用于將平時用到次數相當頻繁的工具或者組件獨立出來,方便多帶帶管理,隨著項目的規模變大,數量變多,單純的復制粘粘無疑在優雅以及實用性上都無法滿足我們的需求,所以進一步模塊化是必然的。
但是一個組件庫的建立其實是一個非常麻煩的過程,基礎 webpack 的配置不用多說,接著你還要配合增加一些 es-lint 之類的工具來規范化團隊成員的代碼。在開發過程中,你自然需要一個目錄來承載使用示例,方便 dev 這個組件,隨后呢,你還得建立一個打包規范,發布到私有 npm 倉庫中。
如此一來,必然大大降低我們的積極性,所以不如創建一個用于建立模塊包的腳手架工具,方便我們項目的初始化。
tips:最終成品在底部
私有 NPM這里簡單提及一下 私有 npm 的搭建。
npm i verdaccio -g
pm2 start verdaccio
推薦配合 nrm 使用 快速切換倉庫地址
verdaccio github
還整個意大利名,屬實洋氣。
工具在進入正題之前,我先介紹一些要點和工具,有了這寫關鍵點,寫起來其實就相當簡單了。
npm bin大家有沒有想過一些全局安裝的工具,他是如何做到在命令行里面自由調用的呢?
事實上這個東西是 npm 提供的鏈接功能
// package.json { "name": "lucky-for-you", "bin": { "lucky": "bin/lucky" } }
當這樣的一個模塊被發布之后,一旦有人使用 -g 參數全局安裝
sudo npm i luck-for-you -g/usr/local/bin/lucky -> /usr/local/lib/node_modules/luckytiger-package-cli/bin/lucky # npm 幫你進行鏈接
npm 事實上會幫你進行一次鏈接,鏈接到你操作系統的 Path 之中,從而但你敲出 Lucky 這個命令的時候,能從 path 中成功找到對應的程序
另外一點就是用于鏈接執行的文件 一般在開頭都要加上如下內容,讓 bash 能夠正確識別該文件應該如何執行
#!/usr/bin/env node // 意味使用 node 運行該文件 // next scriptCommander.js
tj 大神的作品,可以方便的書寫命令行工具。能夠自動生成幫助命令
const program = require("commander"); program.version("0.0.1").usage("[options]"); program .command("create ") .description("創建一個全新的 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事實上當我第一次使用 vue-cli3.0 的時候,里面的命令行表單真是非常驚艷,翻了 vue-cli3 的源碼 找到了這款工具,用于命令行的表單。能夠更加直觀的配置選項。
inquirer .prompt([ { type: "list", name: "template", message: "template: 請選擇項目起始模板", choices: [ { key: "1", name: "JavaScript Library - 適用于普通 JS 庫", value: "js-lib", }, { key: "2", name: "Vue-components - 適用于 Vue 組件庫", value: "vue-component", }, ], }, { type: "input", name: "author", message: "author: 請輸入你的名字", validate: function(value) { return !!value; }, }, { type: "input", name: "desc", message: "desc: 請輸入項目描述", 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); });
還有很多的表單類型,我這里幾個最簡單的 list + input + confirm 就足夠了。
inquire github
開始構建現在開始分享我的構建流程。由于代碼量比較大,挨個文件帖出來沒有什么必要,所以我這里只做簡單介紹,具體的可以查看我的 github項目。
我把我的 cli 工具大致分為兩部分 template模板 + 創建器
z
創建器的主要功能是吸收用戶的可選項,基于模板進行復制+渲染。Vue-cli3.0對于這部分操作會更加復雜,他把模板里面具體的功能都抽象成了一個 Plugin,可以按需組建模板,對于面向普遍大眾當然是更好的。
但是我這個項目因為是公司內部用,所以不太需要太過泛化的設計,一個模板直接解決一個問題,簡化模型就可以了。比如一個模板用于創建 Vue 的組件庫,一個模板用于創建 React 的組件庫,還有一個模板用于創建JavaScript 的工具函數類庫。
如此一來我們的 template模板 創建器在一定程度上可以做到解耦,也就是說日后需要更多類型的模板,不需要修改創建器部分的代碼。
目錄結構├── README.md ├── bin │ └── lucky #主程序 ├── lib │ ├── copy.js #復制 │ └── create.js #主創建器 ├── package-lock.json ├── package.json ├── templates │ ├── config.js #模板配置 解耦 │ ├── js-lib #預設模板1 │ └── vue-component #預設模板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 模板的效果。
這樣運行
npm run dev:js-lib
就能查看和開發 js-lib 這個模板
主程序bin/lucky
#!/usr/bin/env node const program = require("commander") program.version("0.0.1").usage("[options]") program .command("create ") .description("創建一個全新的 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 }
這個文件主要是做一下基本的命令設置 利用了 commander這個庫
如果用戶調用了創建命令,就會轉發給 lib/create.js 處理
主創建器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(`無效的項目名: "${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(`該目錄下已經存在該文件夾 請刪除或者修改項目名`)) return } const answers = await inquirer.prompt([ { type: "list", name: "template", message: "template: 請選擇項目模板", choices: templates.map((v, i) => ({ key: i, name: v.name, value: v.dir })) }, { type: "input", name: "author", message: "author: 請輸入你的名字", validate: function(value) { return !!value } }, { type: "input", name: "desc", message: "desc: 請輸入項目描述", validate: function(value) { return !!value } }, { type: "confirm", name: "confirm", message: "confirm: 完成配置了?", default: false } ]) // 啟動復制流程 const sourceDir = path.resolve(__dirname, "..", "templates", answers.template) console.log(chalk.blue(`
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/105566.html
摘要:什么是讀音,類似于是一套用于構建用戶界面的漸進式框架。的核心庫只關注視圖層,不僅易于上手,還便于與第三方庫或既有項目整合。 什么是vue.js Vue (讀音 /vju?/,類似于 view) 是一套用于構建用戶界面的漸進式框架。與其它大型框架不同的是,Vue 被設計為可以自底向上逐層應用。Vue 的核心庫只關注視圖層,不僅易于上手,還便于與第三方庫或既有項目整合。另一方面,當與現代化...
摘要:的官方下載地址點我進入的官方下載地址下載電腦系統對應文件,然后進行安裝,安裝成功之后通過命令行工具進入安裝目錄。注系統命令行工具通過開始菜單輸入打開,系統為終端。 showImg(https://segmentfault.com/img/bVPL6q?w=200&h=200); Vue — 漸進式 JavaScript 框架 介紹 Vue.js 是什么 vue.js 是一套構建用戶界面...
摘要:的官方下載地址點我進入的官方下載地址下載電腦系統對應文件,然后進行安裝,安裝成功之后通過命令行工具進入安裝目錄。注系統命令行工具通過開始菜單輸入打開,系統為終端。 showImg(https://segmentfault.com/img/bVPL6q?w=200&h=200); Vue — 漸進式 JavaScript 框架 介紹 Vue.js 是什么 vue.js 是一套構建用戶界面...
摘要:的官方下載地址點我進入的官方下載地址下載電腦系統對應文件,然后進行安裝,安裝成功之后通過命令行工具進入安裝目錄。注系統命令行工具通過開始菜單輸入打開,系統為終端。 showImg(https://segmentfault.com/img/bVPL6q?w=200&h=200); Vue — 漸進式 JavaScript 框架 介紹 Vue.js 是什么 vue.js 是一套構建用戶界面...
摘要:寫在前面使用框架開發時,很多人會選擇官方提供的腳手架,最新的已經更新到完全無配置,只需下載就能方便的使用構建的項目工程,但基礎的并不能滿足正常的項目開發,在開發中我們需要根據自己的習慣和業務功能而添加些基礎功能。 寫在前面 使用vue框架開發時,很多人會選擇vue官方提供的cli腳手架,最新的cli已經更新到3.0完全無配置,只需下載就能方便的使用vuecli構建的項目工程,但基礎的c...
閱讀 1634·2023-04-26 02:11
閱讀 2979·2023-04-25 16:18
閱讀 3711·2021-09-06 15:00
閱讀 2630·2019-08-30 15:55
閱讀 1934·2019-08-30 13:20
閱讀 2051·2019-08-26 18:36
閱讀 3121·2019-08-26 11:40
閱讀 2538·2019-08-26 10:11