手动注册节点模块
Posted
技术标签:
【中文标题】手动注册节点模块【英文标题】:Register Node Module Manually 【发布时间】:2018-03-14 00:59:09 【问题描述】:问题:
我在 TypeScript 中有一个项目,它使用了几个我在计算机上无法访问的 API(它们存在于网络上)。代码将在本地编译良好,因为我在 foo.d.ts
文件中拥有所有 API,因此系统知道它们存在于某个地方。
但是,我想使用 NodeJS 应用程序对部分代码进行单元测试。我可以很好地将代码导入节点,但是每当我到达从定义文件导入模块的代码时,我都会收到以下错误:
Error: Cannot find module 'messages'
at Function.Module._resolveFilename (module.js:527:15)
at Function.Module._load (module.js:476:23)
at Module.require (module.js:568:17)
at require (internal/module.js:11:18)
at Object.<anonymous> (~/dev/repos/sample_typescript_fail/App.js:3:18)
at Module._compile (module.js:624:30)
at Object.Module._extensions..js (module.js:635:10)
at Module.load (module.js:545:32)
at tryModuleLoad (module.js:508:12)
at Function.Module._load (module.js:500:3)
...
这是有道理的,因为该代码只是在本地定义的,并不存在。
我可以手动将模块注册到 NodeJS,比如
Registry.register('messages', () => ...);
以便我可以使用 polyfill 进行编译和测试?
这是一个示例应用
package.json
"name": "sample_typescript_declare_issue",
"version": "1.0.0",
"description": "",
"main": "index.ts",
"scripts":
"start": "ts-node index.ts"
,
"author": "",
"license": "MIT"
index.ts
import App from "./App";
console.log("Starting program");
// How do I fake "import MessageSender from "messages";"
// here so that I can run this node app as a test?
let app: App = new App();
console.log("Ending program");
App.ts
import MessageSender from "messages";
export class App
constructor()
let messageSender: MessageSender = new MessageSender();
messageSender.sendMessage("foo!");
node_modules/@types/messages/index.d.ts
export = Messages;
export as namespace Messages;
declare module Messages
class MessageSender
constructor();
sendMessage(message: any): void;
运行示例应用程序
使用npm start
运行会出现上述错误消息。
运行tsc *.tsc
编译就好了。
我尝试过的其他事情
更新 package.json 以包含一个 bin:
"name": "sample_typescript_declare_issue",
"version": "1.0.0",
"description": "",
"main": "index.ts",
"scripts":
"start": "ts-node index.ts"
,
"author": "",
"license": "MIT",
"bin":
"messages": "./polyfills/messages/index.ts"
【问题讨论】:
【参考方案1】:正如您所提到的,编译工作正常 - 这只是 .d.ts
文件的可用性问题。
您要做的是在运行时更改模块导入,换句话说,更改 nodejs require
函数的行为,因为
import MessageSender from "messages";
将在 javascript (ES6) 中转译为类似
const messages_1 = require("messages");
...
messages_1.MessageSender
要修改该行为,首先想到的是使用 已弃用 - 但仍然可用 - require.extensions
对象。
在本地运行时,你必须先注入类似的东西
require.extensions['.js'] = (module, filename) =>
if (filename === 'messages')
// then load mock module/polyfill using the passed module object
// see (https://nodejs.org/api/modules.html#modules_the_module_object)
;
文档说有更好的选择,但没有明确提及。
另一种可能性是查看 sandboxed-module 之类的项目,这应该会有所帮助(我还没有测试过)
【讨论】:
我尝试了两种解决方案,但似乎都不起作用。扩展不允许我称其为“超级”,并且沙盒模块从未对我有用。它没有注入任何东西。以上是关于手动注册节点模块的主要内容,如果未能解决你的问题,请参考以下文章