Зарегистрировать модуль Node в ручном режиме
Вопрос:
У меня есть проект в TypeScript, который использует несколько API, с которыми у меня нет доступа на моем компьютере (они существуют в Интернете). Код будет компилироваться нормально локально, так как у меня есть все API-интерфейсы в файлах foo.d.ts
, и поэтому система знает, что они где-то существуют.
Однако я хочу unit test части кода с помощью приложения NodeJS. Я могу импортировать код в node просто отлично, но всякий раз, когда я достигаю кода, который импортирует модуль из файла определения, я получаю следующую ошибку:
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', () => {...});
, чтобы я мог скомпилировать и протестировать с помощью полиполнений?
Здесь пример приложения
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, которые должны помочь (я его не тестировал)