vue 使用fs_模仿vue-cli,手写一个脚手架
vue-cli
在vue的開發的過程中,經常會使用到vue-cli腳手架工具去生成一個項目。在終端運行命令vue create hello-world后,就會有許多自動的腳本運行。
- 為什么會這樣運行呢?
- 我們自己是否也能寫一個腳手架工具?
帶著這樣的疑問,我們先來看看vue-cli。
解讀vue-cli
首先我們可以來到vue-cli的安裝目錄:
mac用戶來到路徑:/usr/local/lib/node_modules 可以看到(windows可以自行到全局安裝的目錄下查看)
此時用我們的編輯器 打開@vue文件:
lib內放的是具體各種配置和各種類,對于我們來說,這個目錄內的就是所謂的業務邏輯。
bin內放的就是腳本命令的入口,調用lib的入口,入口在package.json內紅框定義。我們姑且先放下業務邏輯,來看看這個入口文件。
現在,我們先放下所有的疑慮,我們打開bin/vue.js。我們可以看到以下內容:
看完之后有什么感覺?咦?怎么跟終端內輸出的好像?沒錯,就是這樣,這就是我們使用vue-cli的時候具體的命令。我們去終端輸入vue:
發現了嗎,終端內的具體命令全在vue.js內定義過了。
program.command('create <app-name>').description('create a new project powered by vue-cli-service') program.command('add <plugin> [pluginOptions]').description('install a plugin and invoke its generator in an already created project') program.command('invoke <plugin> [pluginOptions]')好了,剩下代碼有興趣的可以自行打開對應目錄讀下去,可以學習人家優秀的設計思想。對于本文來說,剩下的許多東西都是業務代碼了。我們開頭的疑問為什么會這樣運行呢?已經了解了一個大概了。我們現在來看看我們自己是否也能寫一個腳手架工具?,答案是肯定的。開始動手吧。
手寫一個自己的腳手架
先來看看可能需要用到哪些npm的包:
- commander:參數解析
- inquirer:交互式命令行工具,有他就可以實現命令行的選擇功能
- chalk:輸出文本顏色,為了美麗~
后續可能隨著模塊的增加,會出現更多需要的包
1. 創建項目
npm init -y # 初始化package.json2. 創建文件目錄
- 在package.json內添加“bin”
- bin下的文件沒有格式,且第一行必須是#! /usr/bin/env node
3. 鏈接包到全局
npm link # // 取消鏈接 npm unlink有時候可能需要在上面命令后面拼接 --force,mac權限問題記得前面sudo
可以去目錄:/usr/local/lib/node_modules 查看,發現我們多了一個,同時在這時候終端輸入一下試試,我們在package.json下叫的name叫superman-cli,所以我們的命令就是叫superman-cli:
好了,基礎配置初始化的工作全部結束了!
4. 第一個命令
首先安裝包commander
npm install commander --save在目錄bin/superman內
#! /usr/bin/env node// console.log(1) const program = require('commander')program.version(`Version is ${require('../package.json').version}`).description('從0開始 手寫腳手架').usage('<command> [options]')program.parse(process.argv)測試有效!
然后我們在前面Version命令下加入代碼:
program.command('create <app-name>').description('create a new project').option('-f, --force', 'Overwrite target directory if it exists').option('-c, --clone', 'Use git clone when fetching remote preset').action((name, cmd) => {console.log('name', name)console.log('cmd', cmd)})仔細對比我們的代碼合終端的輸出,我們就可以看到我們寫的很多東西都生效了。接下來我們就優化一下.action下的參數,畢竟一大堆也不好處理:
program.command('create <app-name>').description('create a new project').option('-f, --force', 'Overwrite target directory if it exists').option('-c, --clone', 'Use git clone when fetching remote preset').action((name, cmd) => {const options = cleanArgs(cmd)console.log(options)}) function camelize (str) {return str.replace(/-(w)/g, (_, c) => c ? c.toUpperCase() : '') } function cleanArgs (cmd) {const args = {}// console.log(cmd)cmd.options.forEach(o => {const key = camelize(o.long.replace(/^--/, ''))// console.log(key)// console.log(cmd[key])// console.log(typeof cmd[key])if (typeof cmd[key] !== 'function' && typeof cmd[key] !== 'undefined') {args[key] = cmd[key]}})return args }具體不懂的也可以像我注釋的console.log一樣,慢慢看就明白了
image
我們第一個命令已經完成一大半了,接下來就是我們這個create命令具體干什么事情。(在這個文件里,我們只管命令,就像vue-cli一樣,這也是我們需要學習的地方,模塊如何去處理)
// 在上面.action內補充一行代碼.action((name, cmd) => {const options = cleanArgs(cmd)console.log(options)require('../lib/create')(name, options)})同時去lib下創建文件create.js
const path = require('path') // const fs = require('fs-extra') async function create (projectName, options) {console.log(projectName, options)const cwd = process.cwd(); // 獲取當前命令執行時的工作目錄const targetDir = path.join(cwd,projectName); // 目標目錄console.log(targetDir) }module.exports = (...args) => {return create(...args) }繼續執行superman-cli create hello -f,我們可以得到,force:true,如果新建的話,將來的目錄會是/Users/chenjing/hello
接下來我們嘗試創建目錄hello,不過我們需要考慮幾個問題:
- 是否已經存在目錄hello了?(使用fs-extra包)
- 若存在是要刪除覆蓋還是停止操作?(這里就需要用到插件inquirer啦,進行選擇)
直接上代碼:
const path = require('path') const fsextra = require('fs-extra') const fs = require('fs') const Inquirer = require('inquirer') async function create (projectName, options) {console.log(projectName, options)const cwd = process.cwd(); // 獲取當前命令執行時的工作目錄const targetDir = path.join(cwd,projectName); // 目標目錄console.log(targetDir)if (fsextra.existsSync(targetDir)) {if (options.force) {// 如果強制創建 ,刪除已有的await fsextra.remove(targetDir);console.log('刪除成功')createDir(projectName)} else {let { action } = await Inquirer.prompt([{name: 'action',type: 'list',message: 'Target directory already exists Pick an action:',choices: [{name:'Overwrite',value:'overwrite'},{name:'Cancel',value:false}]}])if (!action) {console.log('取消操作')return} else if (action === 'overwrite') {console.log(`rnRemoving....`);await fsextra.remove(targetDir)console.log('刪除成功')createDir(projectName)}}} else {createDir(projectName)} } function createDir (projectName) {fs.mkdir(`./${projectName}`, function (err) {if (err) {console.log('創建失敗')} else {console.log('創建成功')}}) }module.exports = (...args) => {return create(...args) }看效果,先來的一個空目錄
superman-cli create hello superman-cli create hello // 再次 superman-cli create hello -f // 覆蓋4. 小結
本篇的源碼github地址
并不是說我們手寫腳手架就到此結束了,只是要完整實現一個功能不是一兩篇文章可以搞定的。不過我相信寫到這里,動手能力強的一定也能體驗一把手動模仿vue-cli的爽了。至于能寫出什么牛C的腳手架,真的就是個人需求和業務代碼堆加。當然可以發散思維后續還可以做許多許多事情。強烈建議閱讀vue-cli。或者其他腳手架的源碼,都在目錄:/usr/local/lib/node_modules 下面,看源碼真的是學習最直接的方法了,甚至copy人家的代碼到自己的cli內執行。其樂無窮
作者:超人陳立青
鏈接:https://www.jianshu.com/p/75de24392de8
來源:簡書
總結
以上是生活随笔為你收集整理的vue 使用fs_模仿vue-cli,手写一个脚手架的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 子之错父之过什么意思_胎教是什么意思?胎
- 下一篇: html5倒计时秒杀怎么做,vue 设