首页 > 解决方案 > 通过动态导入仅动态重新加载后端的一部分

问题描述

在我的节点后端,我有以下文件结构:

project
|-- expensive
|   |-- index.ts
|-- files
|   |-- foo.ts
|   |-- bar.ts
|   `-- baz.ts
|-- tsconfig.json
|-- package.json
`-- index.ts

我只想重新加载我的项目(./files/*)的一部分,而不必重新启动整个项目。我所做的是使用动态导入:

// inside index.ts...
const client = new Client() as Client;

client.expensive = new Map();
client.files = new Map()

// load each file under the `files` dir
client.loadFiles = async () => {
  const fileNames = readdirSync('./files/')
  fileNames.forEach(async name => {
    const module = await import('./files/' + name); // dynamic import
    client.files.set(module.default.name, module.default)
  })
}

// client.loadExpensive...

// load everything
async function loadAll(reload: boolean = false) {
  await client.loadFiles(reload);
  await client.loadExpensive(reload);
}

loadAll();
startApp();

然后重新加载功能将是:

// reload all or the specified dir
client.reload = async (dir?: string | undefined) => {
  if (dir) {
    dir = dir.replace(/^\w/, c => c.toUpperCase()); // capitalize
    if (client.hasOwnProperty('load'+dir)) client['load'+dir]();
    else console.error('no such dir')
  } else {
    await loadAll();
  }
}

问题是项目加载和重新加载时没有错误。在 下添加或删除文件.files/*,然后调用.reload()似乎不会产生任何变化。这是为什么?

在转换为 TS 之前,我使用了 require 和 cache busting:

// additional reload arg
client.loadFiles = async (reload) => {
  const fileNames = readdirSync('./files/')
  fileNames.forEach(async name => {
    // delete require cache then require the file
    if (reload) delete require.cache[require.resolve(`./${dir}/${name}.ts`)];
    client.files.set(module.default.name, module.default)
  })
}

所以我查看了转译的 js 代码,它看起来像import()在下面使用 require 。

const module = yield Promise.resolve().then(() => __importStar(require('./files/' + name)));

我究竟做错了什么?或者这甚至是一个很好的模式。

标签: javascriptnode.jstypescriptdynamic-import

解决方案


因为import()编译为require()(大致),所以您需要像使用 TS 之前那样删除 require 缓存。

client.loadFiles = async (reload: boolean) => {
  const fileNames = readdirSync('./files/')
  fileNames.forEach(async name => {
    // Note that if you're using ts-node the extension will be ts not js
    if (reload) delete require.cache[require.resolve(`./files/${name}.js`)]
    const module = await import('./files/' + name); // dynamic import
    client.files.set(module.default.name, module.default)
  })
}

推荐阅读