Skip to content

[UE] Issue: 使用nodejs后端时,node_modules的存放位置 #2278

@llint

Description

@llint

前置阅读 | Pre-reading

Puer的版本 | Puer Version

1.0.9

UE的版本 | UE Version

5.7.1

发生在哪个平台 | Platform

Editor(win)

错误信息 | Error Message

Error: can not find @protobufjs/aspromise in D:/Projects/CoreGame/node_modules/protobufjs/src/util

问题重现 | Bug reproduce

CoreGame 是一个UE5.7.1的项目,集成了PureTS在Plugins目录下,JsEnv.Build.cs配置(使用NodeJs backend):

    private SupportedV8Versions UseV8Version = 
#if UE_4_25_OR_LATER
        SupportedV8Versions.V9_4_146_24;
#else
        SupportedV8Versions.VDeprecated;
#endif

    private bool UseNodejs = true;

    private bool Node16 = true;

    private bool UseQuickjs = false;

    private bool QjsNamespaceSuffix = false;

    private bool WithFFI = false;
    
    private bool ForceStaticLibInEditor = false;

    private bool ThreadSafe = false;

    private bool FTextAsString = true;
    
    private bool bEditorSuffix = true;

    // v8 9.4+
    private bool SingleThreaded = false;
    
    public static bool WithSourceControl = false;

    public bool WithByteCode = false;

    private bool WithWebsocket = false;

系统node/npm版本:
$ node --version
v22.21.1
$ npm --version
10.9.4

因为项目需要,需要使用protobufjs库,在项目根目录(CoreGame)的node_modules下能够发现protobufjs及相关依赖正常安装,使用protobufjs的方式如下(使用Mixin方式加载):

import { toDelegate } from 'puerts';
import * as UE from 'ue'

import { load } from "protobufjs";  // <---------------------------------- 应该是这里对应的JavaScript解析node_modules出错

interface GM_NscmSessionTest_C extends UE.Game.TestMaps.GM_NscmSessionTest.GM_NscmSessionTest_C {}

class GM_NscmSessionTest_C {
    NscmSession: UE.NscmSession

    ReceiveBeginPlay() {
        console.log(`****************** GM_NscmSessionTest_C.ReceiveBeginPlay: from GM_NscmSessionTest_C.ts`);
        this.Print("****************** GM_NscmSessionTest_C.ReceiveBeginPlay: from GM_NscmSessionTest_C.ts");
        let NscmSessionSubsystem = UE.SubsystemBlueprintLibrary.GetGameInstanceSubsystem(this.GetWorld(), UE.NscmSessionSubsystem.StaticClass()) as UE.NscmSessionSubsystem
        this.NscmSession = NscmSessionSubsystem.CreateNscmSession("127.0.0.1", 8888)
        function OnMessage(session: UE.NscmSession, msg: ArrayBuffer) {
            let u8a1 = new Uint8Array(msg);
            // todo: this should be a protobuf message, so use protobufjs to unmarshal it
        }
        this.NscmSession.SetOnMessageDelegate(toDelegate(this, OnMessage))

        load("Proto/HeartBeat.proto", function (err, root) { // <============== this should trigger protobufjs library resolution, and thus the error
            if (err)
                throw err;

            // Lookup types (no package name in your proto)
            const HeartBeatRequest  = root.lookupType("HeartBeatRequest");
            const HeartBeatResponse = root.lookupType("HeartBeatResponse");

            // ----------------------------
            // Encode HeartBeatRequest
            // ----------------------------
            const requestPayload = {
                key: "conn-12345",
                time: Date.now()          // int64
            };

            // Optional but recommended
            const reqErr = HeartBeatRequest.verify(requestPayload);
            if (reqErr)
                throw Error(reqErr);

            const requestMessage = HeartBeatRequest.create(requestPayload);
            console.log("requestMessage =", requestMessage);

            const requestBuffer = HeartBeatRequest.encode(requestMessage).finish();
            console.log("requestBuffer =", Array.prototype.toString.call(requestBuffer));

            // ----------------------------
            // Decode HeartBeatRequest
            // ----------------------------
            const decodedRequest = HeartBeatRequest.decode(requestBuffer);
            console.log("decodedRequest =", decodedRequest);

            // Convert to plain object (important for int64)
            const requestObject = HeartBeatRequest.toObject(decodedRequest, {
                longs: String,
                defaults: true
            });
            console.log("requestObject =", requestObject);

            // ----------------------------
            // Encode HeartBeatResponse
            // ----------------------------
            const responsePayload = {
                key: requestObject.key,
                time: Date.now()
            };

            const responseMessage = HeartBeatResponse.create(responsePayload);
            const responseBuffer = HeartBeatResponse.encode(responseMessage).finish();

            // ----------------------------
            // Decode HeartBeatResponse
            // ----------------------------
            const decodedResponse = HeartBeatResponse.decode(responseBuffer);
            const responseObject = HeartBeatResponse.toObject(decodedResponse, {
                longs: String,
                defaults: true
            });

            console.log("responseObject =", responseObject);
        });
    }

    ReceiveTick() {
        console.log("ReceiveOnTick ...")
    }

    ReceiveEndPlay() {
        this.NscmSession.Shutdown()
    }
}

export { GM_NscmSessionTest_C }

几个问题吧:

  1. node_modules的位置:currently it's under the project root directory (CoreGame), 但是实际运行的时候(either under PIE or packaged game),我猜测node_modules somehow 应该在CoreGame/Content/JavaScript目录下面,然而文档里面我并没有找到当使用NodeJs backend的时候,有什么额外的步骤来将项目根目录下的node_modules目录引入到CoreGame/Content/JavaScript目录下面?或者有什么其他的设置可以让实际生成的JavaScript代码来找到protobufjs库和相关依赖?
  2. PuerTS内部使用NodeJs应该是Node16?但是我的系统NodeJs的版本是22(如上面所示),不同的Node版本安装的protobufjs包是否可以在不同的NodeJs版本之间使用?
  3. 目前我对整体TypeScript/JavaScript生态还不是很熟,但是我比较好奇,为什么最终生成的在CoreGame/Content/JavaScript目录下的代码还是找到了根目录下面的node_modules目录?是在哪里配置了吗?
  4. 因为我的报错信息还是在PIE模式下运行的时候出现的,那么如果在打包的时候,可能会更需要protobufjs在正确的位置才能在最终运行时正确加载使用,那这个其实和第一个问题是强相关的:使用nodejs后端的时候需要如何保证node_modules能够在packaged game模式下能够被正确找到?

谢谢解答!

Metadata

Metadata

Assignees

Labels

UnrealbugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions