Node Server零基礎——開發環境文件自動重載

来源:http://www.cnblogs.com/liuliliuli2017/archive/2017/05/10/6838796.html
-Advertisement-
Play Games

收錄待用,修改轉載已取得 "騰訊雲" 授權 前言 在 web 前端開發中,我們會藉助 Grunt、Gulp 和 Webpack 等工具的 Watch 模塊去監聽文件變化,那服務端應該怎麼做?其實文件變化的監聽依然可以藉助構建工具,但我們還需要自動重啟服務或者熱重載。本文將介紹三種常見的方法。 方案一 ...


收錄待用,修改轉載已取得騰訊雲授權


前言

在 web 前端開發中,我們會藉助 Grunt、Gulp 和 Webpack 等工具的 Watch 模塊去監聽文件變化,那服務端應該怎麼做?其實文件變化的監聽依然可以藉助構建工具,但我們還需要自動重啟服務或者熱重載。本文將介紹三種常見的方法。

方案一:fs.watch

使用 node 原生的 fs.watch 方法監聽文件改動,所謂的“熱重載”也不過是及時清除記憶體中的文件緩存。示例如下:

const fs = require('fs'),
    path = require('path'),
    projectRootPath = path.resolve(__dirname, './src');

const watch = project => {
    require('./src'); // 啟動 APP,自動檢索到 src/index.js
    try { // 監聽文件夾
        fs.watch(project, { recursive: true }, cacheClean)
    } catch(e) {
        console.error('watch file error');
    }
}
// 清除緩存
const cacheClean = () => {
    Object.keys(require.cache).forEach(function (id) {
        if (/[\/\\](src)[\/\\]/.test(id)) {
            delete require.cache[id]
        }
    })
}
// 啟動開發模式
watch(projectRootPath);

註意:在伺服器入口文件 src/index.js 中引用中間件時需要套一層函數,並使用 require 的方式引入模塊才能清除緩存。比如:

// 引入中間件或控制器
app.use(async (ctx, next) => {
    await require('./controllers/main.js')(ctx);
});
// 或引入路由
app.use(async (ctx, next) => {
    await require('./router').routes()(ctx, next)
})

方案二:應用進程管理器

此處以 PM2 為例,supervisorforever 等類似的進程管理工具異曲同工,這裡不再贅述。

PM2 是一款帶有負載均衡功能的 Node 應用進程管理器,具有 —watch 配置項,用來監聽應用目錄的變化,一旦發生變化,立即重啟。詳見:Auto restart apps on file change。他是真正意義上的重啟,不是熱替換。

缺點:PM2 並不提供優雅的方式告知用戶何時重啟或者殺掉進程。
以下是一個簡單的 PM2 配置 (開發環境) start.js,啟動進程 node start.js

const pm2 = require('pm2');

pm2.connect(function(err) {
    if (err) {
        console.error(err);
        process.exit(2);
    }

    pm2.start({
        "watch": ["./app"], // 開啟 watch 模式,並監聽 app 文件夾下的改動
        "ignore_watch": ["node_modules", "assets"], // 忽略監聽的文件
        "watch_options": {
            "followSymlinks": false // 不允許符號鏈接
        },
        name: 'httpServer',
        script: './server/index.js', // APP 入口
        exec_mode: 'fockMode', // 開發模式下建議使用 fockModel
        instances: 1, // 僅啟用 1 個 CPU
        max_memory_restart: '100M' // 當占用 100M 記憶體時重啟 APP
    }, function(err, apps) {
        pm2.disconnect(); // Disconnects from PM2
        if (err) throw err
    });
});

每次修改文件之後保存(Ctrl+S),會有個黑框閃一下,說明應用已經成功重啟了。

方案三:chokidar + babel

chokidar 是對 fs.watch / fs.watchFile / fsevents 的一層封裝。它的優勢包括解決(出自 chokidar 文檔):

1、在 OS X 下不能獲取文件名;

2、在 OS X 下 Sublime 修改文件後不能獲取到修改事件;

3、修改文件會觸發兩次事件;

4、不提供文件遞歸監聽;

5、高 CPU 使用率;

6、…

這裡使用 babel 的原因是想要支持最新的 js 語法,包括 ES2017、Stage-x,以及 import / export default 等模塊語法。

下麵提供一個完整的監聽重載配置文件,並通過註釋說明功能和意義。

const projectRootPath = path.resolve(__dirname, '..'),
    srcPath = path.join(projectRootPath, 'src'),    // 源文件
    appPath = path.join(projectRootPath, 'app'),    // 編譯後輸出文件夾
    devDebug = debug('dev'),
    watcher = chokidar.watch(path.join(__dirname, '../src'))

// 啟動 chokidar 監聽文件改動
watcher.on('ready', function () {
    // babel 編譯文件夾目錄
    babelCliDir({
        outDir: 'app/',
        retainLines: true,
        sourceMaps: true
    }, [ 'src/' ]) // compile all when start

    require('../app') // 啟動 APP(編譯後的文件)

    // 添加監聽方法
    watcher
        // 文件新增
        .on('add', function (absPath) {
            compileFile('src/', 'app/', path.relative(srcPath, absPath), cacheClean)
        })
        // 文件修改
        .on('change', function (absPath) {
            compileFile('src/', 'app/', path.relative(srcPath, absPath), cacheClean)
        })
        // 文件刪除
        .on('unlink', function (absPath) {
            var rmfileRelative = path.relative(srcPath, absPath)
            var rmfile = path.join(appPath, rmfileRelative)
            try {
                fs.unlinkSync(rmfile)
                fs.unlinkSync(rmfile + '.map')
            } catch (e) {
                devDebug('fail to unlink', rmfile)
                return
            }
            console.log('Deleted', rmfileRelative)
            cacheClean(); //清除緩存
        })
})

// 動態編譯文件
function compileFile (srcDir, outDir, filename, cb) {
    const outFile = path.join(outDir, filename),
        srcFile = path.join(srcDir, filename);

    try {
        babelCliFile({
            outFile: outFile,
            retainLines: true,
            highlightCode: true,
            comments: true,
            babelrc: true,
            sourceMaps: true
        }, [ srcFile ], {
            highlightCode: true,
            comments: true,
            babelrc: true,
            ignore: [],
            sourceMaps: true
        })
    } catch (e) {
        console.error('Error while compiling file %s', filename, e)
        return
    }
    console.log(srcFile + ' -> ' + outFile)
    cb && cb() // 通常為清除緩存
}
// 清除緩存
function cacheClean () {
    Object.keys(require.cache).forEach(function (id) {
        if (/[\/\\](app)[\/\\]/.test(id)) {
            delete require.cache[id]
        }
    })
    console.log('App Cache Cleaned...')
}
// 監聽程式退出
process.on('exit', function (e) {
    console.log('App Quit')
})

註意:為了能讓緩存失效,我們同樣需要在 use 里包裹一層函數,並以 require 的方式引入路由

app.use(async (ctx, next) => {
    await require('./router').routes()(ctx, next)
})

方案四:開發插件

nodemon 和 node-dev 都是可用於 node.js 開發版插件,提供簡單易用的開發環境。以 nodemon 為例,全局安裝或本地安裝都可
npm install nodemon -g
然後通過 nodemon ./server.js localhost 8080 啟動開發進程。獨立、簡單,好用!

詳見:remy/nodemon

綜上

每個方法都有不同的適用場景。如果想要嘗試最新語法,推薦試用方案三;如果追求簡單快捷,方案二是不錯的選擇。

這就結束了嗎?

如果我既想用最新的語法特性,又需要像 PM2 那樣簡單,怎麼辦?babel 構建工具(如 webpack)對於每個前端開發並不陌生,再加一款 PM2 足以解決所有問題。


原文鏈接:https://www.qcloud.com/community/article/476280


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 原文獻上, 點擊滴滴滴 迭代器模式(Iterator)定義: 提供一種方法順序訪問聚合對象的各個元素嗎而又不暴露該對象的內部展示 不用Iterator的壞處 原文中編寫了三個簡單的集合 ArraryList HashSet LinkedList 原先是沒有實現Iterable 內部沒有具體實現ite ...
  • 前言:Zookeeper的監聽機制很多人都踩過坑,感覺實現了watcher 介面,後面節點的變化都會一一推送過來,然而並非如此。 Watch機制官方聲明:一個Watch事件是一個一次性的觸發器,當被設置了Watch的數據發生了改變的時候,則伺服器將這個改變發送給設置了Watch的客戶端,以便通知它們 ...
  • 本文是博主在開發某電商平臺項目的一些雜項記錄,方便自己和團隊同事查閱,偏向於具體技術或應用的細節和個人理解,但也未必非常具體。文中未提的更多內容可能會另起篇章。 導航屬性——EF實體關係fluent配置 AutoMapper Autofac Repository模式 Model & DTO 開源&商 ...
  • 1.Dubbo是什麼? Dubbo是一個分散式服務框架,致力於提供高性能和透明化的RPC遠程服務調用方案,以及SOA服務治理方案。簡單的說,dubbo就是個服務框架,如果沒有分散式的需求,其實是不需要用的,只有在分散式的時候,才有dubbo這樣的分散式服務框架的需求,並且本質上是個服務調用的東東,說 ...
  • 之前在講表拆分的時候氛圍垂直拆分和水平拆分 垂直拆分的查詢其實不難,就是從單表變為了多表,而大部分情況下只是對主表的查詢多,從表的查詢會很少用到,這樣的情況下關聯查詢不需要太多的考慮 水平拆分之前講了大數據量的情況下根據歷史時間來查詢,那麼今天來說另外一種,還有一隻是根據主鍵id取模後根據這樣的規則 ...
  • 參考:http://design-patterns.readthedocs.io/zh_CN/latest/creational_patterns/builder.html ...
  • 轉載請標明原文地址:http://www.cnblogs.com/zhangyukof/p/6829538.html 隨著編程經驗的積累,我對編程的理解也不斷的發生變化。最開始學的是演算法,然後是數據結構,現在開始學習編程思想,這是一個不斷進步的過程。編程思想可能是最基礎但卻是最重要的,以前對這些概念 ...
  • 一.簡介 ZK的安裝和配置十分簡單,既可以配置成單機模式,也可以配置成集群模式,zk使用java編寫的運行在java環境上,3個ZK服務進程是建議的最小進程數量,而且建議部署在不通的物理機上面,減少宕機帶來的風險。 二.下載並解壓 http://www.apache.org/dyn/closer.c ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...