Node.js Web应用代码热更新

1,088 阅读1分钟

🙂实现思路:将启动文件中的 router、proxy 文件分离出主文件,对分离出去的文件实现热更新。关键问题点:

  • 如何更新模块代码
  • 如何使用新模块处理请求
  • 如何释放老模块的资源

如何更新模块代码

引入 chokidar 当监听文件修改时,清除该模块缓存,delete require.cache[path]

如何使用新模块处理请求

使用koa框架,app.use 操作会保存旧的 router.js 模块,因此模块更新了,请求依然会使用老模块

// 利用闭包的特性获取最新的router对象,避免app.use缓存router对象
app.use((ctx, next) => router.routes()(ctx, next)).use(router.allowedMethods())

// 监听文件修改重新加载代码
const watcher = chokidar.watch(path.resolve(__dirname, '../www'), { ignored: /index\.js/ })
 watcher.on('ready', () => {
   logger.info(`will watching at '${path.resolve(__dirname, '../www')}`)
   watcher.on('all', (event, file) => {
     logger.info(`server-side hot-reload due to: ${file}`)
     Object.keys(require.cache).forEach((id) => {
       if (/\/www\//.test(id)) {
         cleanCache(id)
         try {
           if (file.endsWith('router.js')) {
             router = require('./router')
           }
           if (file.endsWith('proxies.js')) {
             proxies = require('./proxies')
           }
         } catch (ex) {
           console.error(`module ${file} update failed`)
         }
       }
     })
   })
 })

function cleanCache (module) {
   var path = require.resolve(module);
   delete require.cache[path];
}

如何释放老模块的资源

让老模块的代码更新后,确保没有对象保持了模块的引用 ,Node.js 会自动为所有模块添加一个引用

function cleanCache(modulePath) {
    var module = require.cache[modulePath];
    // remove reference in module.parent
    if (module.parent) {
        module.parent.children.splice(module.parent.children.indexOf(module), 1);
    }
    require.cache[modulePath] = null;
}

解决了 koa 热更新问题。


附上github: github.com/Jarryxin/mp…


参考: fex.baidu.com/blog/2015/0…