項目結構javascript
最近在學習使用打包工具 yarn 構建應用程序。html
安裝 yarn: npm i -g yarn
。而後就能夠在命令行中輸入 yarn 命令:java
$ yarn -v 1.9.4
使用 yarn init
初始化新項目,這會在當前目錄下建立一些文件,其中 package.json 文件是配置文件。node
在 package.json 中添加linux
{ ... "scripts": { "build": "rollup -c" } }
而後在終端中輸入 yarn build
,實際將會執行 rollup -c
命令,爲了可以使用 rollup,咱們須要先添加依賴:yarn add rollup
。git
而後在當前目錄下新建 rollup.config.js
文件,輸入如下內容:github
export default { input: 'src/Main.js', output: [ { format: 'umd', name: 'Main', file: 'build/main.js', indent: '\t' }, { format: 'es', file: 'build/main.module.js', indent: '\t' } ] };
接下來運行 yarn build
,將會在當前目錄下(若不存在則建立)建立一個 build 目錄,裏面有兩個生成的文件 main.js
和 main.module.js
。npm
首先要引用 fs
模塊: const fs = require('fs');
,fs 模塊提供了 watch
方法,用於監視某個文件夾中的文件變更狀況,使用的 NodeJS 版本爲 8.x,本來該版本的 Node 已經提供了遞歸監視子文件夾的選項,可是因爲 recursive 選項僅在 Windows 系統和 macOS 系統下生效,所以此處只能監視某個特定的文件夾。json
如下是 nodejs 官網對 watch 函數的警告:api
Caveats
The fs.watch API is not 100% consistent across platforms, and is unavailable in some situations.
The recursive option is only supported on macOS and Windows.
對於文件的監控實際上很是簡單,fs.watch
方法會返回一個 fs.FSWatcher
對象,在該對象上註冊 change 的回調函數便可。(也能夠在調用 fs.watch
方法時將回調函數傳遞到第三個參數)
const fs = require('fs'); const TO_WATCH = __dirname + '/src'; function onChange(eventType, filename) { if( filename ) { console.log( filename ); } }; var watcher = fs.watch( TO_WATCH, { recursive: true } ); watcher.on( 'change', onChange );
接下來,使用 node 運行上述 JavaScript 代碼,對 src 目錄下的 Main.js 文件作一些改動,而後保存,在個人電腦的控制檯上可以看到如下內容:
Main.js Main.js
能夠看到,代碼正確運行了,而且可以監視出是哪一個文件變更。(儘管還有些小問題,Main.js 輸出了兩次,稍後就會解決這個問題)
前面提到過,在 Linux 系統中,fs.watch(filename[, options][, listener])
方法的 recursive 選項不起做用,然而在 src
目錄下經常須要根據代碼功能劃分不一樣的子模塊(子文件夾),若是不對 Linux 系統做一些額外的處理的話,那麼前面給出的 JavaScript 代碼將沒法監視 src
下的子目錄文件變更。
爲了實現遞歸監視功能,須要用到 fs.readdir(path[, options], callback)
方法,在 node 10.x 中,該方法支持名爲 withFileTypes: <boolean>
的選項,將該選項設爲 true,在以後的回調函數中傳遞的 files 參數將不是一個字符串數組,而是一個 fs.Dirent[]。(fs.Dirent 對象自帶有 isDirectory() 方法,自 10.10.0 版本後加入,使用起來是很是簡單的。)
然而很遺憾,在 node 8.x 中,該方法的選項僅支持 encoding: <string>
,回調函數中傳遞的 files 參數只是一個字符串數組,因此爲了判斷出 src 目錄下的文件是否爲文件夾,還須要 fs.stat(path, callback)
方法:
var watcher = []; watcher[0] = fs.watch( TO_WATCH, { recursive: true } ); watcher[0].on( 'change', onChange ); // on linux watch recursive option is invalid fs.readdir( TO_WATCH, { withFileTypes: true }, (err, files) => { if( err ) { throw err; } for(let i = 0; i < files.length; i++ ) { let file = files[i] // file is just the name of certain file, // we have to prepend "src/" or the absolute path fs.stat( TO_WATCH + "/" + file, (err, stats) => { if( err ) { throw err; } if( stats && stats.isDirectory() ) { let w = watcher.length; watcher[w] = fs.watch( TO_WATCH + "/" + file ); watcher[w].on( 'change', onChange ); } }) } } );
一切都準備就緒,對 src
的子目錄下的文件作出修改並保存,能夠在控制檯上看到修改的文件名(不過仍然會打印兩次文件名,打印的次數根據系統環境等不一樣而不一樣,由於 fs.watch
API 不是 100% 穩定的)。
爲了防止修改一次文件而屢次觸發 onChange
回調函數,咱們可使用時間進行簡單的過濾重複事件。
var last = Date.now(); function onChange(eventType, filename) { let nd = Date.now(); if( nd - last > 100 && filename ) { console.log( filename ); } last = nd; };
這裏判斷 onChange
方法執行的間隔時間,若是小於 100ms 就只須要執行一次命令。如今在嘗試改動 src
目錄下的文件,就只會打印一次文件名了。
執行命令須要用到 child_porcess
模塊中的 exec
方法,使用起來比較簡單,執行以前在終端中輸入的命令 yarn build
:
const exec = require('child_process').exec; exec("yarn build", (err, stdout, stderr) => { console.log( stdout ); });
這裏只打印出標準輸出,對於錯誤信息沒有打印。
以上不到 50 行的 JavaScript 代碼就實現了遞歸監視目錄及其子目錄的功能,當目錄中的文件變化時自動構建應用。因爲 Node 10.x 中 watch
方法提供了遞歸監視的功能,能夠對不一樣的 node 版本做不一樣的處理。可是這一功能並無在本例的代碼中實現。
完整代碼在 github 倉庫 上。
https://yarnpkg.com/zh-Hans/docs/getting-started
https://yarnpkg.com/zh-Hans/package/rollup
https://nodejs.org/docs/latest-v8.x/api/fs.html