【问题标题】:Is it possible to clear node.js require cache using express.js?是否可以使用 express.js 清除 node.js 需要缓存?
【发布时间】:2020-07-19 15:25:21
【问题描述】:

我为自己编写了 node.js 小应用程序,它在处理请求之前使用小 js 代码清除 require 缓存:

let clearCache
if (process.env.NODE_ENV === 'development') {
  const {cache} = require
  clearCache = (except) => {
    for (let key in cache)
      if (!except.includes(key) && key.indexOf('/node_modules/') === -1)
        delete cache[key]
  }
} else {
  clearCache = () => {}
}

const { createServer } = require('http')
const persistentPaths = ['/path/to/my/db/file']
createServer((req, res) => {
  clearCache(persistentPaths)
  require('./handleRequest')(req, res)
}).listen(3000, () => {})

我相信这是在开发中使用应用的最有效方式。

当我更改代码时,它会立即生效,这对我来说很好。

现在我想使用 express.js,但似乎无法使用这种方法。

好的,看来这是一个自我回答的问题,我需要使用 nodemon。

但我真的不想使用监视所有文件并重新启动整个服务器的工具。恐怕会慢很多。

在我的示例中,您可以看到我重新加载了除 db 文件之外的文件,因此我正在开发的应用程序仅连接到数据库一次并保持该连接。如果使用 nodemon 应用程序还需要加载所有 node_modules 代码,每次代码更改时都与 db 建立新连接,也许每次都会连接到 postgres 和 redis。

问题是:我不能这样做,有没有解决方案为 express.js 重新加载模块?

【问题讨论】:

    标签: node.js express require reload


    【解决方案1】:

    您无需编写一个实用程序。你可以使用像 chokidar 这样的模块。可以同时指定目录和忽略。

    您可以在回调手表时重新加载。

    来自 wiki 的示例:https://github.com/paulmillr/chokidar

    const chokidar = require("chokidar");
    
    // Full list of options. See below for descriptions.
    // Do not use this example!
    chokidar.watch("file", {
      persistent: true,
    
      ignored: "*.txt",
      ignoreInitial: false,
      followSymlinks: true,
      cwd: ".",
      disableGlobbing: false,
      awaitWriteFinish: {
        stabilityThreshold: 2000,
        pollInterval: 100,
      },
    
      ignorePermissionErrors: false,
      atomic: true, // or a custom 'atomicity delay', in milliseconds (default 100)
    });
    // One-liner for current directory
    chokidar.watch(".").on("all", (event, path) => {
      // Reload module here.
    });
    

    【讨论】:

    • Chokidar 会产生开销:它是单独的过程,必须查看许多文件,在代码编辑和重新加载之间增加了额外的延迟,这就是我不想使用它的原因 感谢您的回复,但是,您没有展示如何使用 chokidar 重新加载 express 应用代码,仅展示如何使用 chokidar
    • 重新加载很容易再次要求。手表就是这样工作的,拉或推。在这里推送是不可能的,你必须拉上特定的时间戳。您可以在配置中降低频率。
    • 这里是 chokidar 代码,它不会为每个文件创建线程。你在哪里看到节点 js 中的线程?? github.com/paulmillr/chokidar/blob/master/lib/nodefs-handler.js
    • node js 是单线程框架。所以你不要在nodejs代码中创建一个线程。除非你使用工作模块。这里没用过。
    • 但我没有使用word thread,只使用整个chokidar的过程。我看过一篇文章,其中一个节点实例中有 chokidar,它正在发送请求以更新快速节点实例中的代码。知道了,所以在您的示例中,chokidar 和 express 应用程序将在同一进程中运行。在您的示例中,如何在手表回调中重新加载快速应用程序?需要每次都会创建服务器的“server.js”文件吗?并且在要求之前需要杀死正在运行的服务器?或者怎么做?
    【解决方案2】:

    做到了!如果你能分享你的想法,我会很高兴。

    因为我只能用谷歌搜索 nodemon 和 chokidar 解决方案,也许我在做一些奇怪的事情,这是我的解决方案:

    server.ts:

    import express from 'express'
    const app = express()
    const port = 3000
    
    app.listen(port, () =>
      console.log(`Example app listening at http://localhost:${port}`)
    )
    
    if (process.env.NODE_ENV === 'development') {
      const {cache} = require
      const persistentFiles: string[] = []
      const clearCache = (except: string[]) => {
        for (let key in cache)
          if (!except.includes(key) && key.indexOf('/node_modules/') === -1)
            delete cache[key]
      }
      app.use((req, res, next) => {
        clearCache(persistentFiles)
        const {router} = require('config/routes')
        router.handle(req, res, next)
      })
    } else {
      const router = require('config/routes')
      app.use(router.handle)
    }
    

    还有 routes.ts:

    import {Router, Request, Response} from 'express'
    export const router = Router()
    
    router.get('/', function (req: Request, res: Response) {
      res.send('Hello world')
    })
    

    用法:NODE_ENV=development NODE_PATH=src node src/server.js

    (我的IDE在编辑的时候把ts编译成js放在那里,如果你使用VS代码可能会更复杂,我猜)

    【讨论】:

      猜你喜欢
      • 2013-01-08
      • 2013-04-13
      • 2014-07-04
      • 1970-01-01
      • 2016-12-05
      • 1970-01-01
      • 2017-08-18
      • 1970-01-01
      • 2015-04-24
      相关资源
      最近更新 更多