前言:緊接上篇,這篇文章着重講解create.js,這是建立項目的主文件。css
從上而下,逐行解析。vue
const fs = require('fs-extra') // 這個是操做文件的庫,node自帶的庫須要寫不少的hack const path = require('path') // 路徑 const chalk = require('chalk') // console上色 const inquirer = require('inquirer') // 這個很重要,是命令行交互用的,好比咱們建立項目的時候,他會讓你選擇是否採用vue-router,是否使用vuex。 const Creator = require('./Creator') // 這個後面細說 const { clearConsole } = require('./util/clearConsole') // 這個就是console一些信息,不重要 const { getPromptModules } = require('./util/createTools') // 這個後面說 const validateProjectName = require('validate-npm-package-name') // 校驗包名字,不重要
async function create (projectName, options) { // projectName就是咱們建立的項目名字,好比hello-word // options就是咱們輸入的參數了,例如 -p -f -d 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 (fs.existsSync(targetDir)) { // 目錄是否存在 if (options.force) { //參數是否有-f,若是有就強制刪除目錄 await fs.remove(targetDir) } else { // 不然就讓用戶本身選擇,是覆蓋啊,合併啊,仍是啥的 await clearConsole() // 輸出一些提示吧,這個不重要 if (inCurrent) { // 若是是當前目錄建立項目,給個confirm提示 const { ok } = await inquirer.prompt([ { name: 'ok', type: 'confirm', message: `Generate project in current directory?` } ]) if (!ok) { return } } else { / const { action } = await inquirer.prompt([ { name: 'action', type: 'list', message: `Target directory ${chalk.cyan(targetDir)} already exists. Pick an action:`, choices: [ { name: 'Overwrite', value: 'overwrite' }, { name: 'Merge', value: 'merge' }, { name: 'Cancel', value: false } ] } ]) if (!action) { return } else if (action === 'overwrite') { console.log(`\nRemoving ${chalk.cyan(targetDir)}...`) await fs.remove(targetDir) } } } } // 總結上面的一堆代碼,就是建立一個項目目錄,來放代碼,若是目錄存在是強制刪除仍是覆蓋合併。 const creator = new Creator(name, targetDir, getPromptModules()) // 真正建立的代碼在這裏面去了。 // name就是項目名 // targetDir就是 path.resolve(cwd, projectName || '.')就是目錄地址 // getPromptModules這個是引入第三方庫 await creator.create(options) }
看下getPromptModules(),他引入了好多的庫,這些庫,在用戶選擇不一樣的初始化項目的時候用獲得。node
return [ 'babel', 'typescript', 'pwa', 'router', 'vuex', 'cssPreprocessors', 'linter', 'unit', 'e2e' ].map(file => require(`../promptModules/${file}`))
真正的建立看來仍是要等到下一篇文章再說了,再重點介紹下inquirer這個庫。vue-router
inquirer命令行交互的庫,好比咱們常見的vuex
一個是讓你手動輸入,y或者n,一個是選擇。typescript
當全部的交互完成會,會返回一個對象,就是用戶選擇或者輸入的值,後續的輸出邏輯就依賴這個值。npm
const inquirer = require('inquirer'); inquirer.prompt([ { type: 'input', message: '請選擇是否建立(y/n)', name: 'xory', default: 'y', }, { type: 'list', message: '你喜歡什麼水果?', name: 'xig', default: '0', choices:['西瓜','蘋果','香蕉'] }, { type: 'input', message: '請輸入手機號:', name: 'phone', validate: function(val) { if(val.match(/\d{11}/g)) { // 校驗位數 return true; } return "請輸入11位數字"; } } ]).then(answer => { console.log(answer); // answer就是用戶的輸入 })
重點的方法就prompt,prompt接收一個數組,數組裏面是一個配置對象,重點是type,不一樣的type須要配置不一樣的數據,好比當type是list的時候,須要傳一個choices,用於給用戶選擇。數組