手动注册节点模块

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 之类的项目,这应该会有所帮助(我还没有测试过)

【讨论】:

我尝试了两种解决方案,但似乎都不起作用。扩展不允许我称其为“超级”,并且沙盒模块从未对我有用。它没有注入任何东西。

以上是关于手动注册节点模块的主要内容,如果未能解决你的问题,请参考以下文章

向未注册的用户显示节点标题

ice框架应用记录-框架说明

将包管理器与 Domino 和节点模块的位置一起使用

如何使用 CCK API 创建节点引用字段?

用于 OAuth2 访问令牌生成的节点模块?

十二docker swarm监控