很久沒有更新博客了。。。不知不覺作前端已過去一年有餘了,漸漸發現如今入門前端的門檻愈來愈高了,須要學習的東西也多了很多,工做中效率也愈來愈慢,那麼提升本身的打碼速度也就愈加的重要了,而做爲程序員的咱們也應該把和業務無關的東西提取出來,讓它自動化,簡單化,這樣才能事半功倍。因而便有了我作工具鏈的想法,通過兩個版本的迭代,npm上也有3千多的下載了,也算是穩定了下來,這個系列我就來一步步的講述整個工具鏈的始末吧~css
首先,先貼上github地址 nuts工具鏈,(求關注 (☆_☆))在文檔中記錄瞭如何使用,在這裏我就再也不贅述了,咱們就從一個個的命令開始吧。html
個人工具鏈是基於gulp開發的,因此在運行的時候須要gulp命令進行操做,今天就來介紹一下 create 這個命令是如何實現的。首先看這個命令的用法:前端
gulp create --name xxxx
通常來講咱們的項目的目錄組成是由 html文件,js文件和css文件以及圖片字體等靜態資源組成的,那麼咱們在建立新項目的時候也就應該擁有這些內容了。那麼這整個是怎麼開始運行起來的呢?這就要從開始輸入命令行的時候提及來了,在這個命令行中,create 關鍵字是一個任務,而這個任務接收 -- 結尾的參數,而且拿到參數的內容已交給後續的程序處理,這其實就是整個庫的結構了,而最外層的gulpfile.js 文件就是咱們項目的配置文件了,由於使用的是gulp3.X的版本,因此必須存在這個gulpfile文件才能正常運行gulp任務,而在這個文件中我也僅僅是引入了 controller 文件而且運行其中的 run 方法,剩下的僅僅是提供一個config的配置對象而已,那麼這個 run 方法又是作什麼的呢?node
exports.run = ()=> { fs.readdirSync('./nuts/tasks/').forEach((files) => { if (/(\.(js)$)/i.test(path.extname(files))) { require('./tasks/' + files); } }); };
在這個方法中我循環加載了tasks文件夾下的全部文件,也就是說tasks文件夾下的每個文件都是一個任務,同時爲了支持ES6的代碼,nuts中使用了webpack做爲打包工具,下面這個方法返回的就是一個最基礎的webpack配置:webpack
// webpack的配置文件,通常狀況下不須要修改 exports.webpackConfig = (dev)=> { return { watch: false, module: { loaders: [ { test: /\.js$/, loader: 'babel-loader', exclude: './node_modules/', query: { presets: ['es2015'] } } ] }, plugins: (dev == 'dev') ? [] : [new webpack.optimize.UglifyJsPlugin()] } };
而整個命令行會接收多少參數呢?端口號,項目名稱,打包版本等等,這麼多的參數,我選擇採用一個對象來進行保存,這樣便於管理和替換:git
/** * 經過命令行傳入的參數,在這裏進行緩存,方便後面調用。 */ exports.arguments = ()=> { let inputArgv = minimist(process.argv.slice(2)); return { _name: inputArgv.name || inputArgv.dir, _port: inputArgv.port, _clean: inputArgv.clean, _dev: inputArgv.dev, _build: inputArgv.build, _create: inputArgv.create, _ver: inputArgv.ver, _include: inputArgv.include }; };
這段代碼中的 minmist 方法是一個第三方的庫,這是一個可讓node接收命令行參數的庫,雖然功能簡單,可是夠用就行了~況且它還特別的小~程序員
其實這個流程總結下來就是由 minmist 接收命令行中傳來的參數,而後交給 controller文件去處理,而後再將各個參數傳給不一樣的tasks去處理的流程,只不過,在這個當中,我作了一些針對本身的處理。下面咱們看看這個 create 命令裏面究竟作了些什麼~github
packages._core.task('create', () => { let proName = controller.arguments()._name || defaultName(), devDir = `${controller.config.sourceDir}/${proName}`; if (!!path.basename(proName)) { fs.exists(devDir, (exists) => { if (exists) { console.log('警告!!!您要建立的項目已經存在!'); } else { createProject('nuts/templets', devDir, path.basename(proName)); } }); } else { console.log('警告!!!這是一個須要完整路徑的項目!'); } });
在這個任務初始化的時候咱們首先初始化兩個參數,一個是須要建立的項目名稱 proName,以及這個項目相對的路徑 devDir,而後檢查這個項目是否已經建立,若是不存在的話就調用 createProject 方法來進行建立。web
/** * 建立新項目的函數 * @param templet * @param devDir 項目路徑 * @param name 項目名稱 */ function createProject(templet, devDir, name) { var letter_name = name.replace(/\_(\w)/g, (all, letter)=> { return letter.toUpperCase(); }); packages._core.src(`${templet}/index.html`) .pipe(packages._replace('@@main', name)) .pipe(packages._core.dest(`${devDir}/`)); packages._core.src(`${templet}/scss/main.scss`) .pipe(packages._rename(`${name}.scss`)) .pipe(packages._core.dest(`${devDir}/scss`)); packages._core.src(`${templet}/js/main.tmpl`) .pipe(packages._replace({ '@@project_name': name, '@@author': controller.config.author, '@@date': time, '@@project': letter_name.replace(/(\w)/, v=> v.toUpperCase()), '@@letter': letter_name })) .pipe(packages._rename(`${name}.js`)) .pipe(packages._core.dest(`${devDir}/js`)); // 建立圖片和字體文件夾 mkdirs(path.resolve(__dirname, `../../${devDir}/`), (err)=>{ if (err) { console.log(err); } fs.mkdirSync(path.resolve(__dirname, `../../${devDir}/images`)); fs.mkdirSync(path.resolve(__dirname, `../../${devDir}/font`)); }); console.log(name + '項目建立完成!!!'); }
這個方法接受3個參數,可是使用者只能傳入後兩個參數,我要作的就是建立html文件,js文件和scss文件以及images和font兩個文件夾,同時在輸出這些文件的時候我也會根據配置文件中的設置去替換模板中的關鍵字,其中須要注意的就是node在建立文件夾的時候須要若是父文件夾不存在時則會拋出錯誤,那麼這個時候就須要遞歸的建立缺失的文件夾了,因此我寫了 mkdirs 方法來解決這個問題。npm
在tasks同級的目錄下有個util目錄,裏面放着一些非任務的腳本,一般是用來處理諸如此類的問題的:
/** * 建立多層文件夾 異步 * Created by fuhuixiang on 16-9-1. */ const fs = require('fs'), path = require('path'); module.exports = (dirpath, callback)=> { mkdirs(dirpath, ()=> { callback(); }); }; // 異步文件夾建立 遞歸方法 function mkdirs(dirpath, _callback) { fs.exists(dirpath, (exists)=> { if (exists) { _callback(dirpath); } else { //嘗試建立父目錄,而後再建立當前目錄 mkdirs(path.dirname(dirpath), ()=> { fs.mkdir(dirpath, _callback); }); } }); }
經過這樣一個簡單的遞歸方式,就能夠循環的建立文件夾了,到此create命令中的兩點,建立文件和替換關鍵字的功能點都實現了,下面就是真正的使用了~下篇我將介紹真正使用最多的dev命令~
gulp create ---name test1 gulp create ---name 2016/test1