打造屬於自己的cnpm/npm安裝,生成自定義專案架構

清一色天空發表於2017-12-08

一些廢話(直接看程式碼的可跳過)

現在前端圈子框架繁多,不乏一些自主研發或合作開發的公司內部框架,模組/元件化、框架設計理念、架構分析、底層封裝等去搭建高樓大廈的骨架,為的就是“維護、複用、二次開發、高效”等理念,濃縮就是兩字好用(toulan)

公司內部研發的框架體系一般都會趨向於圖形化、視覺化,不過大多數都會做到最後一步,那就是模組化的選擇了該結構,該樣式(皮膚)然後想去一鍵生成這個專案的時候,啊?沒這個功能,實現不了,npm/cnpm的一堆依賴結構不是我想要的!那這篇文章就是來解救你了,讓我們來打造屬於自己的專案結構檔案依賴(是時候解放你的雙手了)。


技術實現

以下技術實現是基於js、node以及自帶的fs模組

想要達到的目的

  1. 只用一句命令列,一個檔案來搞定專案結構的建立
  2. 執行過程視覺化,在cmd命令指示符中顯示檔案建立的進度
    loading
  3. 需要有生成專案目錄的樹狀圖
    tree
  4. 專案結構任意化
  5. 程式碼可二次開發性

需要的工具

  • node
  • cmd(命令指示符)

打造一個極簡的專案結構建立(試水篇)

步驟一:進入你想要一鍵生成的檔案目錄

1、win+r輸入cmd回車 2、cd進入到該專案目錄(想一建生成目錄的地方) 3、node如何安裝自行百度


步驟二:建立server.js

開啟你善用的編輯器直接複製以下程式碼

var fs = require("fs")

var mkDir = ['css', 'fonts', 'img', 'module']
/* 建立目錄 */
for (var i = 0; i < mkDir.length; i++) {
  fs.mkdir(mkDir[i], function (err) {
    if (err) {
      return console.error(err);
    }
  })
}
複製程式碼

ctrl+s儲存,在cmd中輸入

node server

回頭看一下你的專案結構吧。 如果不出意外的話,專案結構已經變成了這樣

tree

這裡不得不佩服fs的強大,以下附上node fs API地址。

http://nodejs.cn/api/fs.html


步驟三:還沒完,還有讀取檔案以及生成檔案

上面已經出現了我們想要的專案結構,不過這需求對我們來說還遠遠不足,我們還需要建立js檔案以及html檔案之類呢。

1)在該目錄下建立index.html

裡面寫書寫以下程式碼:
複製程式碼
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
	</head>
	<body>
	  <h1>Hello World!</h1>
	</body>
</html>

複製程式碼

2)server.js

var fs = require("fs")

/* 讀取index.html檔案建立indexx.html檔案 */
fs.readFile('index.html', 'utf8', function (err, data) {
    if (err) {
      return console.error(err);
    }
    fs.appendFile('indexx.html', data, 'utf8', function (err) {
      if (err) {
        return console.error(err);
      }
    });
});

複製程式碼

cmd執行

node server

回頭看下專案目錄,是否多了個indexx.html的檔案,如果多了就說明成功了,以上的操作是讀取了index.html內的所有文字內容,然後建立了indexx.html的超文字,當然對fs來說,只是修改了字尾名而已。

這裡寫圖片描述


打造一個自定義幷包含完善的Catalog、Tree、color、Path的專案結構(進階篇)

Tips:以下步驟會分步介紹各個階段的執行過程(最下方含有完整的github專案地址)
複製程式碼

解析一:構建server.js程式碼過程化

var _methods = {
  data: { /*資料存放位置*/
	now: 0, /*當前程式計數*/
	sum: 0, /*一共程式次數*/
	log: '' /*輸出的tree*/
  },
  _nodeInit: function (mkDir) { /*初始化*/
    this._nodeSum(mkDir) /*先得出一共需要的執行次數,以便去判斷非同步回來的當前次數*/
    this._nodeFor(mkDir) /*進入下個流程 --- 建立*/
  },
  _nodeFor: function (mkDir) { /*建立*/
	/*這兒是執行目錄結構建立的地方
	  並且每次非同步回撥後執行
	  this._nodeTree(++now)
	  以便去顯示當前建立進度*/
  },
  _nodeSum: function () { /*計算一共的建立次數*/
	/*為什麼要先獲取總共的建立次數,
	因為fs的函式建立是非同步的,
	過程中很難判斷全部非同步是否已經完成
	並且tree的建立也是在這執行的
	輸出給this.tree以及this.sum*/
  },
  _nodeTree: function () { /*當前進度判斷*/
	/*如果當前進度===總進度時
	則執行之前就已經建立好了的
	去console.log(this.tree)出來*/
  }
}

var fs = require("fs") /*引入fs*/
var mkDir = [ /*專案結構樹一覽*/
  {
    name: 'csss', /*資料夾名稱*/
    child: [
      {
        name: 'public.css', /*檔名稱*/
        val: '' /*檔案內容*/
      }, {
	    name: 'asd',
	    child: [
		  {
			  name: 'asd'
		  }
		]
      }
    ]
  }
]
_methods._nodeInit(mkDir)
複製程式碼

大致流程如上,這兒有一些技術棧:

1、_nodeSum: 多執行緒非同步的情況下,沒能很好得知是否全部執行完成,所以採用了該方式(定時器不可取)

2、_nodeTree: 樹結構console.log並不是很完美
複製程式碼

解析二:_nodeFor:無限子節點非同步回撥建立目錄結構(核心程式碼)

_nodeFor: function (mkDir, path) {
    var self = this
    for (var i = 0; i < mkDir.length; i++) {
      var name = mkDir[i].name
      var child = mkDir[i].child
      var path_block = path ? (path + '/' + name) : name 
      if (name.lastIndexOf('.') === -1) { /*判斷檔案or資料夾 --- 資料夾*/
        (function (path, child, name) { /*防止非同步回撥後變數被汙染*/
          fs.mkdir(path, function (err) {
            if (err) {
              return console.error(err)
            }
            self._nodeTree(++self.data.now, path, name) /*載入loading*/
            if (child) {
              self._nodeFor(child, path) /*遞迴*/
            }
          })
        })(path_block, child, name)
      } else { /*檔案*/
        (function (path, val, name) {
          fs.appendFile(path_block, val ? val : '', 'utf8', function (err) {
            if (err) {
              return console.error(err)
            }
            self._nodeTree(++self.data.now, path, name) /*載入loading*/
          })
        })(path_block, mkDir[i].val, name)
      }
    }
  }
複製程式碼

技術棧:

這段程式碼並不是很難理解,但除錯起來確實是費勁,畢竟含有遞迴+非同步的40行復雜程式碼誰也不能保證一次就能寫成功,在node下,無論是debugger還是console.log()在cmd中除錯都很難受,這兒推薦個強大的node-debug除錯環境,讓你在喜歡的谷歌下除錯

技術學習or推薦

node-inspector
複製程式碼

除錯工具(基於npm安裝):node-inspector

執行流程:

1、安裝 node-inspector

npm install node-inspector -g

2、監聽埠(執行)

node-inspector

run

3、cmd到你的目錄下執行node debug模式

node --debug-brk server.js

run

4、開啟谷歌瀏覽器,在位址列輸入以上顯示的地址:http://127.0.0.1:8080/debug?port=5858 就可以進行除錯了,成功後會到以下頁面,按F8即可執行到你打斷點處,如果沒打則直接結束。(如果不行請重新整理下)

Debug


解析三:_nodeSum:計算總執行次數

    console.log('\x1B[90m' + 'Downloading Current JS to ' + __dirname + '\x1B[39m')
    var self = this
    function count (mkDir, j) { /*i為次數, j為層級*/
      for (var i = 0; i < mkDir.length; i++) {
        (function (mkDir, i, j) {
          var log = log_j(j)
          var name = mkDir[i].name.lastIndexOf('.') === -1 ? mkDir[i].name : ('\x1B[90m' + mkDir[i].name + '\x1B[39m')
          self.data.log += log + '--' + name + '\n'
          if (mkDir[i].child) {
            count(mkDir[i].child, ++j)
          }
          self.data.sum++
        })(mkDir, i, j ? j : 0)
      }
    }
    function log_j (val) {
      var log = ''
      if (val === 0) return '|'
      for (var i = 0; i < val; i++) {
        log += ' ' + '|'
      }
      return '|' + log
    }
    count(arr)
    console.log('\x1B[90m' + 'Altogether contains ' + this.data.sum + 'second Execution process' + '\x1B[90m')
複製程式碼

簡述:

這兒是在非同步執行_nodeFor之前就先預解析完了樹結構以及總共的執行次數,因為是同步遞迴思想,只要注意作用域以及避免變數汙染即可。

技術棧:

那就是之前提過的,沒有一個好的方法可以監聽到多執行緒非同步的回撥是否全部執行完成,如果有的話請在下方評論並且沒有很好看的輸出樹結構,仍然有些瑕疵。

技術學習or推薦

讓你的console.log色彩繽紛
複製程式碼

這兒有兩種,一種是node上的寫法,一種是平常網頁除錯的寫法(兩者不同)

1、node寫法

console.log('\x1B[90m' + 'Hello, Do you think my color has changed?'  + '\x1B[39m')
複製程式碼
/* 顏色參考值 */

'bold'          : ['\x1B[1m',  '\x1B[22m'],  

'italic'        : ['\x1B[3m',  '\x1B[23m'],  

'underline'     : ['\x1B[4m',  '\x1B[24m'],  

'inverse'       : ['\x1B[7m',  '\x1B[27m'],  

'strikethrough' : ['\x1B[9m',  '\x1B[29m'],  

'white'         : ['\x1B[37m', '\x1B[39m'],  

'grey'          : ['\x1B[90m', '\x1B[39m'],  

'black'         : ['\x1B[30m', '\x1B[39m'],  

'blue'          : ['\x1B[34m', '\x1B[39m'],  

'cyan'          : ['\x1B[36m', '\x1B[39m'],  

'green'         : ['\x1B[32m', '\x1B[39m'],  

'magenta'       : ['\x1B[35m', '\x1B[39m'],  

'red'           : ['\x1B[31m', '\x1B[39m'],  

'yellow'        : ['\x1B[33m', '\x1B[39m'],  

'whiteBG'       : ['\x1B[47m', '\x1B[49m'],  

'greyBG'        : ['\x1B[49;5;8m', '\x1B[49m'],  

'blackBG'       : ['\x1B[40m', '\x1B[49m'],  

'blueBG'        : ['\x1B[44m', '\x1B[49m'],  

'cyanBG'        : ['\x1B[46m', '\x1B[49m'],  

'greenBG'       : ['\x1B[42m', '\x1B[49m'],  

'magentaBG'     : ['\x1B[45m', '\x1B[49m'],  

'redBG'         : ['\x1B[41m', '\x1B[49m'],  

'yellowBG'      : ['\x1B[43m', '\x1B[49m']  
複製程式碼

2、Web端除錯寫法

console.log("%cHello, Do you think my color has changed?", "color: green")
複製程式碼

這個一看就懂了。


解析四:_nodeTree:當前值與sum的比較輸出打造猶如cnpm的實時進度

  _nodeTree: function (now, path, name) { /*非同步過程介面化*/
    console.log('[' + now + '/' + this.data.sum + ']\x1B[90m ' + name + '\x1B[39m' + '\x1B[32m' + ' installed ' + '\x1B[39m' + 'at ' + path)
    if (now === this.data.sum) { /*噹噹前進度 === sum時*/
      console.log('\x1B[32m' + 'All package installed ' + this.data.sum + ' project installed from ' + __dirname + '\x1B[39m')
      console.log('\x1B[35m' + 'Project catalogue:' + '\x1B[39m')
      console.log(this.data.log + '------------------------------------')
      console.log(",'''╭⌒╮⌒╮.',''',,',.'',,','',.\n" +
      " ╱◥██◣''o',''',,',.''.'',,',.\n" +
      "|田|田田│ '',,',.',''',,',.''\n" +
      "╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬" + '\n------------------------------------')
      console.log('\x1B[35m' + 'MAKE:o︻そ╆OVE▅▅▅▆▇◤\nBLOG:http://blog.csdn.net/mcky_love\nGITHUB:https://github.com/gs3170981' + '\x1B[39m')
    }
  }
複製程式碼

簡述:

這兒執行的就是實時顯示當前進度以及全部執行完成後的tree與我個人的資訊(#^.^#)
複製程式碼

實時當前進度:

loading

結束後的tree

tree

與個人資訊

info


解析五:mkDir:調參的陣列寫法

/*------------------------注意事項------------------------
1、資料夾名稱不可相同、檔名稱相同的情況下字尾名不可相同
2、資料夾內方可建立child子專案目錄,檔案下建立child物件不執行
3、資料夾名稱不可包含'.'字元
----------------------------END--------------------------*/

var mkDir = [
  {
    name: 'csss',
    child: [
      {
        name: 'public.css',
        val: 'body{font-size: 12px;}'
      }, {
        name: 'publicccc',
        child: [
          {
            name: 'asd'
          }
        ]
      }
    ]
  }, {
    // ......
  }
]
複製程式碼

簡述:

通俗易懂的格式,不過如注意事項所說,這兒並沒有對‘.’下建立資料夾與不執行的地方進行try提示,需要的朋友可自行git修改。


一個完整的DEMO

github:https://github.com/gs3170981/cnpmDIY(好用的話記得加星哦!)


##關於

make:o︻そ╆OVE▅▅▅▆▇◤(清一色天空)

blog:http://blog.csdn.net/mcky_love


結束語

自定義專案結構與自定義的框架完美契合,適用於視覺化開發,模組化合作開發,單人專案開發,多人維護等,這兒就不科普具體用處了,fs幫我們解決了大多數問題,剩下的用途僅限制於你的腦洞!

相關文章