手动注册节点模块

题:

我在TypeScript中有一个项目,它使用了几个我在计算机上无法访问的API(它们存在于Web上)。 由于我拥有foo.d.ts文件中的所有API,因此代码将在本地编译,因此系统知道它们存在于某处。

不过,我想用NodeJS应用程序unit testing部分代码。 我可以将代码导入到节点中,但每当我到达从定义文件导入模块的代码时,都会出现以下错误:

 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', () => {...}); 

这样我可以编译和testingpolyfills?


这是一个示例应用程序

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编译就好了。


其他的事情,我试过了

  1. 更新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" } } 

正如你所提到的,编译工作正常 – 这只是一个.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) } }; 

该文件说有更好的select,但没有明确提到任何。

另一种可能性是看像沙盒模块应该帮助的项目(我没有testing过)