如何在 Node.js 中从不同的应用程序注入模块

How to inject module from different app in Node.js

我有两个节点 apps/services 运行 在一起, 1.主应用 2. 第二个应用

主应用负责在最后显示来自不同应用的所有数据。现在我将第二个应用程序的一些代码放在主应用程序中,现在它可以工作了,但我希望它被解耦。我的意思是 secnod 应用程序的代码不会在主应用程序中(通过某种方式在运行时注入它)

就像第二个服务注册到主应用程序一样,注入它的代码。 它的代码只有两个模块,可以在nodejs中实现吗?

const Socket = require('socket.io-client');
const client = require("./config.json");

module.exports =  (serviceRegistry, wsSocket) =>{
    var ws = null;
    var consumer = () => {
        var registration = serviceRegistry.get("tweets");
        console.log("Service: " + registration);
        //Check if service is online
        if (registration === null) {
            if (ws != null) {
                ws.close();
                ws = null;
                console.log("Closed websocket");
            }
            return
        }
        var clientName = `ws://localhost:${registration.port}/`
        if (client.hosted) {
            clientName = `ws://${client.client}/`;
        }
        //Create a websocket to communicate with the client
        if (ws == null) {
            console.log("Created");
            ws = Socket(clientName, {
                reconnect: false
            });
            ws.on('connect', () => {
                console.log("second service is connected");
            });
            ws.on('tweet', function (data) {
                wsSocket.emit('tweet', data);
            });
            ws.on('disconnect', () => {
                console.log("Disconnected from blog-twitter")
            });
            ws.on('error', (err) => {
                console.log("Error connecting socket: " + err);
            });
        }
    }
    //Check service availability
    setInterval(consumer, 20 * 1000);
}

我在主模块中放置了这段代码,我想通过在运行时以某种方式注入它来解耦它?示例将非常有帮助...

您可以从您的一个应用程序创建包,然后在另一个应用程序中引用该包。

https://docs.npmjs.com/getting-started/creating-node-modules

您将不得不使用 vm 模块来实现此目的。更多技术信息在这里 https://nodejs.org/api/vm.html。让我解释一下如何使用它:

  1. 您可以使用 API vm.script 从您稍后需要的代码创建编译后的 js 代码 运行。参见官方文档中的描述

Creating a new vm.Script object compiles code but does not run it. The compiled vm.Script can be run later multiple times. It is important to note that the code is not bound to any global object; rather, it is bound before each run, just for that run.

  1. 现在当你想插入或运行这段代码时,你可以使用script.runInContextAPI。

官方文档中的另一个很好的例子:

'use strict';
const vm = require('vm');

let code =
`(function(require) {

   const http = require('http');

   http.createServer( (request, response) => {
     response.writeHead(200, {'Content-Type': 'text/plain'});
     response.end('Hello World\n');
   }).listen(8124);

   console.log('Server running at http://127.0.0.1:8124/');
 })`;

 vm.runInThisContext(code)(require);

再一个直接使用js文件的例子:

var app = fs.readFileSync(__dirname + '/' + 'app.js');
vm.runInThisContext(app);

您可以将此方法用于要插入的条件代码。

有多种方法可以解耦两个应用程序。一种简单的方法是使用 pub/sub 模式(如果您不需要响应)。
(现在如果你有一个非常耦合的应用程序,除非你做一些重构,否则很难解耦它。)
zeromq 提供了 pub/sub 的一个很好的实现,而且速度非常快。
例如

import zmq from "zmq";
socket.connect('tcp://127.0.0.1:5545');
socket.subscribe('sendConfirmation');

socket.on('message', function (topic, message) {
    // you can get the data from message.
    // something like:
    const msg = message.toString('ascii');
    const data = JSON.parse(msg);
    // do some actions.
    // .....

});

//don't forget to close the socket.
process.on('SIGINT', () => {
    debug("... closing the socket ....");
    socket.close();
    process.exit();
});

//-----------------------------------------
import zmq from "zmq";
socket.bind('tcp://127.0.0.1:5545');
socket.send(['sendConfirmation', someData]);

process.on('SIGINT', function() {
  socket.close();
});

这样你的模块可以有两个不同的容器 (docker),只要确保打开相应的端口即可。
我不明白的是,为什么要注入 wsSocket 并创建一个新的套接字。可能我要做的就是发送 socket id,然后像这样使用它:

const _socketId = "/#" + data.socketId;     
io.sockets.connected[socketId].send("some message");

你也可以使用另一种解决方案,比如 kafka 而不是 zmq,只是考虑到它速度较慢,但​​它会保留日志。
希望这能让您了解如何解决您的问题。

您可以使用 npm link 功能。

linking 过程包括两个步骤:

  1. 通过 运行 npm link 在模块的根文件夹中 link 将模块声明为全局 link
  2. 通过 运行 npm link 在目标文件夹中安装 linked 模块

除非您的某个本地模块依赖于另一个本地模块,否则它工作得很好。在这种情况下,linking 失败,因为它找不到依赖模块。为了解决这个问题,需要link依赖模块到父模块,然后将父模块安装到应用程序中。

https://docs.npmjs.com/cli/link