1. 程式人生 > >NodeJS 開發應用

NodeJS 開發應用

types fig direct RoCE 做出 tin 沒有 list star

NodeJS 開發應用

  • 使用的 Node 版本: V8.11.4
  • 開發工具: VSCode 1.27.1
  • 系統: Deepin 15.7 Desktop x64

項目結構

項目結構

  • Project
    • index.html
    • index.js
    • package.json
    • yarn.lock
    • rollup.config.js
    • src
      • Main.js
      • ...(js files)
      • subdirs
        • ...(js files)
    • build
      • main.js

yarn + rollup 構建應用程序

最近在學習使用打包工具 yarn 構建應用程序。

安裝 yarn: npm i -g yarn

。然後就可以在命令行中輸入 yarn 命令:

$ yarn -v
1.9.4

使用 yarn init 初始化新項目,這會在當前目錄下創建一些文件,其中 package.json 文件是配置文件。

在 package.json 中添加

{
    ...

    "scripts": {
        "build": "rollup -c"
    }
}

然後在終端中輸入 yarn build,實際將會執行 rollup -c 命令,為了能夠使用 rollup,我們需要先添加依賴:yarn add rollup

然後在當前目錄下新建 rollup.config.js

文件,輸入以下內容:

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.jsmain.module.js

在 Node 8.x 中監視文件變動情況

首先要引用 fs 模塊: const fs = require(‘fs‘);,fs 模塊提供了 watch 方法,用於監視某個文件夾中的文件變動情況,使用的 NodeJS 版本為 8.x,原本該版本的 Node 已經提供了遞歸監視子文件夾的選項,但是由於 recursive 選項僅在 Windows 系統和 macOS 系統下生效,因此此處只能監視某個特定的文件夾。

以下是 nodejs 官網對 watch 函數的警告:

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 版本作不同的處理。但是這一功能並沒有在本例的代碼中實現。

Reference

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

NodeJS 開發應用