故事背景
身為一個入門前端七個月的小菜雞,在我入門前端的第一天就接觸到了vue,並且死皮賴臉的跟他打了這么久的交到,還記得第一次用vue init webpack 這句命令一下生成一個模板的時候那種心情,當時我就想,要是自己也能寫一個的話,那會是灰常吃雞的吧 o( ̄▽ ̄)ブ,所以說今天我們也要簡單實現一個自己的腳手架
認識bin
bin的作用
首先我們先來了解一下這個bin ,這個bin和我們最開始用的vue init webpack 這個命令是息息相關的
還記得我們在最開始安裝vue-cli的時候嘛
npm install vue-cli -g
- 這條命令的意思是把vue-cli 安裝到全局 ,以至於你再任何一個地方打開cmd 的時候都能夠使用 vue init webpack
vue init webpack 這條命令實際上是執行的vue-cli 里邊 package.json 里邊的bin屬性下的命令
這個文件大概位置如下

這個路徑里邊有隱藏的路徑,在查找的時候記得打開隱藏目錄可見
這個bin里邊大概長成這個樣子

由圖中可見,這里邊有三個命令
vue vue-init vue-list
- 這個三個命令的意思是執行對應的文件,Npm會在node_modules/.bin/目錄下建立符號鏈接。又因為node_modules/.bin/目錄會在運行時加入系統的PATH變量,因此在運行npm時,就可以不帶路徑,直接通過命令來調用這些文件。
bin所執行的文件和參數
那么說到這里你肯定會好奇這個文件是怎么做到生成模板的對吧,那么我們就來看一下被執行的這個文件到底是何方神聖
#!/usr/bin/env node
const program = require('commander')
program
.version(require('../package').version)
.usage('<command> [options]')
.command('init', 'generate a new project from a template')
.command('list', 'list available official templates')
.command('build', 'prototype a new project')
.command('create', '(for v3 warning only)')
program.parse(process.argv)
上邊這一坨代碼就是 執行vue init webpack 的文件所有內容
首先最重要的一點就是 第一句 #!/usr/bin/env node
這句代碼不可以沒有, #! 指明這個腳本文件的解釋程序,然后這個/usr/bin/env 是說在系統的PATH目錄中查找
這句話整體的意思就是說會有一個新的shell執行指定的腳本,執行這個腳本的解釋程序是node
如果不加這句代碼的話是會報錯的
然后下邊這個引入了一個commander 包 這是一個很牛逼的大佬寫的一個關於命令行一些操作的包,command 里邊的是定義一些子命令,然后后邊在跟的參數,這里暫且不深扒了,附上中文文檔
寫一個自定義命令
好,那么我們現在了解了bin的基本概念和大致流程,下面我們來寫一個自己的命令
首先新建一個文件夾, 在package.json里邊加上這么一句代碼
"bin": {
"zjs-cli": "main.js"
},
和新建一個main.js的文件
然后莫慌,我們還需要再執行一個命令就是
npm link
我們之前全局安裝的都會默認在npm的node_modules目錄下,這個命令可以簡單的理解為在npm的node_modules創建了一個快捷方式
到此為止我們得自定義命令算是走通了,接下來我們說一說文件里邊得內容
搭建腳手架
腳手架得工作流程
上邊我們知道了bin得作用並且,把我們得自定義命令和文件關聯了起來,那么腳手架具體是怎么操作的呢,大概步驟如下
-
進入文件,根據指定的地址和編譯器,執行我們的js
-
從命令行接受參數,執行對應的操作
-
交互性的詢問問題,根據配置選擇拉取的模板
-
從git拉取模板
我們之前用的vue的腳手架大概的流程就是這樣的
安裝依賴
在進入文件之后,為了能夠得到命令行的操作我們就要安裝一些依賴了比如說commander的這個包
npm install commander
然后命令行默認的字體顏色是黑白色的,我們可以引入一些命令行交互的包,不得不說這些寫包的大佬是真牛逼,啥都能寫
npm install chalk
vue 有一個 init 子命令 , 那我們也叫init好了
const cmd = require("commander");
const chalk = require('chalk')
cmd.command('init').description('初始化模板').action(async (args) => {
// 。。。
})
cmd.parse(process.argv)
-
其中command 是添加子命令的
-
description是描述
-
action 是執行這個命令的回調
-
parse 是解析你命令行里邊傳進來的參數 比如 你寫了一個 zjs-cli init demo , 那么這個時候 回調里邊的args的值就是demo這個字符串
然后需要注意process上的是argv , 里邊用的是args ,這里不是筆誤,當時我剛開始玩的時候納悶了好半天
然后做一些交互,讓我們得腳手架看起來更順溜一些
npm install inquirer
npm install ora
上邊這兩個分別是加載動畫和回答問題得,比如vue在新建模板得時候問你的一些列問題,還有那個下載中等待得loading動畫
不要問我怎么能記住這么多得包名字,因為我是看的vue-cli源碼認識得。。。。
拉取git
這里單獨把拉取git拿出來說,雖所內容不多,但畢竟也是今天的主角 o( ̄▽ ̄)ブ
那么問題來了,怎么下載模板呢?很簡單,當然還是npm包。。。。
npm install download-git-repo
這個包是可以從github上邊下載包的
比如說我之前寫的一個demo他叫zjs-template,那么拉取的路徑就是我得git路徑加項目名稱
let url = 'zhou1591/zjs-template'
// 然后第二個參數是拉取下來后的名稱
// 這里我選擇用命令行里邊傳過來的參數做名字
let name = 'args'
然后根據api拉取模板,關閉
let downGit = (name) => {
downLoad(url, name, {
clone
}, err => {
process.exit(1)
})
}
完整代碼如下
// git包
const downLoad = require('download-git-repo')
// 動畫
const ora = require('ora')
let url = 'zhou1591/zjs-template'
let clone = false
let downGit = (name) => {
const spinner = ora('正在拉取模板...')
spinner.start()
downLoad(url, name, {
clone
}, err => {
spinner.stop()
console.log(err?err:"項目創建成功")
process.exit(1)
})
}
module.exports = downGit
引到main.js里邊跑起來就好了,到此為止一個簡單的腳手架已經ok了,就差了最后一步
發布腳手架
創建npm賬號並發布
我們寫完了一個自己的腳手架之后,當然是想迫不及待的體驗一番的
首先我們創建一個npm的賬號npm官網
之后在我們剛才的項目里邊
-
npm login 輸入你的賬號密碼郵箱
-
然后登陸成功后 npm publish 推送
-
package.json 里邊的name 是你的npm包發布的名稱
-
keywords 是搜索你的包的關鍵字
-
description是你的包描述
-
version 是你的版本號
第一次發布npm包可能會遇到的問題
這個是說已經有重復名字的包了 你沒有權限去推
- you must verify your email before publishing a new package: https://www.npmjs.com/email-edit : "your module name"
這個是說第一次發布的時候 說你需要驗證郵箱,在你登陸的最上方
-
每次發布的時候需要更改你的版本號
-
還有一個比較重要的npm ERR! no_perms Private mode enable, only admin can publish this module:
這個是說你沒有在npm最開始的源上邊,你可能切換比如淘寶等等其他的源,當時我就是因為用了公司的源,怎么登陸都登陸不上去,很蛋疼
完美撒花
好了,到這里我們的第一個腳手架就算是完事了, 運行一下
// 全局安裝一下
npm install zjs-template -g
// 按照之前的命令
zjs-cli init myDemo
我得zjs-cli的git地址 https://github.com/zhou1591/zjs-cli/
我得zjs-template的git地址 https://github.com/zhou1591/zjs-template
希望我們每一個前端都喜歡前端,都能夠在學習中不斷充實自己 o( ̄▽ ̄)ブ
下一篇我會簡單實現一個vuex , 喜歡的請點個贊吧~

