您现在的位置是:亿华云 > 数据库

如何把 Node.js 嵌入自己的项目中

亿华云2025-10-02 23:18:07【数据库】2人已围观

简介Node.js 不仅可以单独运行,还可以以库的方式被使用,本文介绍下如何把 Node.js 嵌入到自己项目中。首先第一步下载 Node.js 源码,然后根据 Node.js 的文档进行编译安装。这样我

Node.js 不仅可以单独运行,何把还可以以库的嵌入方式被使用,本文介绍下如何把 Node.js 嵌入到自己项目中。自己首先第一步下载 Node.js 源码,目中然后根据 Node.js 的何把文档进行编译安装。这样我们就可以拿到 Node.js 提供的嵌入头文件和库文件了。接下来根据官方的自己 demo 写一个测试程序。

#include "node.h"

如何把 Node.js 嵌入自己的项目中

#include "uv.h"

如何把 Node.js 嵌入自己的项目中

#include

如何把 Node.js 嵌入自己的项目中

using node::CommonEnvironmentSetup;

using node::Environment;

using node::MultiIsolatePlatform;

using v8::Context;

using v8::HandleScope;

using v8::Isolate;

using v8::Locker;

using v8::MaybeLocal;

using v8::V8;

using v8::Value;

static int RunNodeInstance(MultiIsolatePlatform* platform,目中

const std::vector& args,

const std::vector& exec_args);

int main(int argc, char** argv) {

argv = uv_setup_args(argc, argv);

std::vectorargs(argv, argv + argc);

std::vectorexec_args;

std::vectorerrors;

int exit_code = node::InitializeNodeWithArgs(&args, &exec_args, &errors);

for (const std::string& error : errors)

fprintf(stderr, "%s: %s\n", args[0].c_str(), error.c_str());

if (exit_code != 0) {

return exit_code;

}

std::unique_ptrplatform =

MultiIsolatePlatform::Create(4);

V8::InitializePlatform(platform.get());

V8::Initialize();

int ret = RunNodeInstance(platform.get(), args, exec_args);

V8::Dispose();

// V8::DisposePlatform();

return ret;

}

int RunNodeInstance(MultiIsolatePlatform* platform,

const std::vector& args,

const std::vector& exec_args) {

int exit_code = 0;

std::vectorerrors;

std::unique_ptrsetup =

CommonEnvironmentSetup::Create(platform, &errors, args, exec_args);

if (!setup) {

for (const std::string& err : errors)

fprintf(stderr, "%s: %s\n", args[0].c_str(), err.c_str());

return 1;

}

Isolate* isolate = setup->isolate();

Environment* env = setup->env();

{

Locker locker(isolate);

Isolate::Scope isolate_scope(isolate);

HandleScope handle_scope(isolate);

Context::Scope context_scope(setup->context());

MaybeLocalloadenv_ret = node::LoadEnvironment(

env,

"const publicRequire ="

" require(module).createRequire(process.cwd() + /);"

"globalThis.require = publicRequire;"

"publicRequire(./test)");

if (loadenv_ret.IsEmpty()) // There has been a JS exception.

return 1;

exit_code = node::SpinEventLoop(env).FromMaybe(1);

node::Stop(env);

}

return exit_code;

}

大部分都是默认的流程,我们可以先不用关注,何把重点是嵌入 LoadEnvironment 函数的逻辑。LoadEnvironment 最后会执行我们传入的自己字符串代码。这段代码中,目中前面是香港云服务器何把 Node.js 提供的 demo,后面一句是嵌入我加的,test.js 里简单输出 hello world。自己下面来编译一下。

g++ Node.cc src/node_code_cache_stub.cc src/node_snapshot_stub.cc -I/node/v17.9.0/include/node -std=c++14 -L /node/out/Release -l v8_base_without_compiler -l v8_compiler -l v8_init -l v8_initializers -l v8_libbase -l v8_libplatform -l v8_snapshot -l brotli -l cares -l gtest -l gtest_main -l histogram -l icudata -l icui18n -l icutools -l icuucx -l llhttp -l nghttp2 -l nghttp3 -l ngtcp2 -l openssl -l torque_base -l uv -l uvwasi -l v8_zlib -l zlib -l pthread -l node

因为 code cache 和 快照函数的符号找不到的问题,这里先曲线救国一下,从 Node.js 源码里引入这两个文件,后续再去研究具体方案。编译完后就拿到了一个 a.out 文件,执行该文件就可以看到输出 hello world。cool,我们已经实现了把 Node.js 嵌入到我们的项目。下面具体来看一下涉及到的一些逻辑。从 LoadEnvironment 看起。云服务器

MaybeLocalLoadEnvironment(

Environment* env,

const char* main_script_source_utf8) {

Isolate* isolate = env->isolate();

return LoadEnvironment(

env,

[&](const StartExecutionCallbackInfo& info) -> MaybeLocal{

// 一会分析

});

}

LoadEnvironment 进一步调了另一个 LoadEnvironment。

MaybeLocalLoadEnvironment(

Environment* env,

StartExecutionCallback cb) {

env->InitializeLibuv();

env->InitializeDiagnostics();

return StartExecution(env, cb);

}

LoadEnvironment 进行了一些初始化,接着调 StartExecution。

MaybeLocalStartExecution(Environment* env, StartExecutionCallback cb) {

InternalCallbackScope callback_scope(

env,

Object::New(env->isolate()),

{ 1, 0 },

InternalCallbackScope::kSkipAsyncHooks);

if (cb != nullptr) {

EscapableHandleScope scope(env->isolate());

if (StartExecution(env, "internal/bootstrap/environment").IsEmpty())

return { };

StartExecutionCallbackInfo info = {

env->process_object(),

env->native_module_require(),

};

return scope.EscapeMaybe(cb(info));

}

}

StartExecution 最终执行了 第一个 LoadEnvironment 传入到回调,并传入了 process 和原生 JS 模块加载器。接着看回调函数的逻辑。

std::string name = "embedder_main_" + std::to_string(env->thread_id());

// 插入原生 JS 模块代码中

native_module::NativeModuleEnv::Add(

name.c_str(),

UnionBytes(**main_utf16, main_utf16->length()));

env->set_main_utf16(std::move(main_utf16));

std::vector> params = {

env->process_string(),

env->require_string()};

std::vector> args = {

env->process_object(),

env->native_module_require()};

// 执行我们的代码

return ExecuteBootstrapper(env, name.c_str(), ¶ms, &args);

}

回调函数通过 ExecuteBootstrapper 执行我们传入的代码。

MaybeLocalExecuteBootstrapper(Environment* env,

const char* id,

std::vector>* parameters,

std::vector>* arguments) {

EscapableHandleScope scope(env->isolate());

// 从原生 JS 模块代码中找到我们的代码

MaybeLocalmaybe_fn =

NativeModuleEnv::LookupAndCompile(env->context(), id, parameters, env);

Localfn;

if (!maybe_fn.ToLocal(&fn)) {

return MaybeLocal();

}

// 执行我们的代码

MaybeLocalresult = fn->Call(env->context(),

Undefined(env->isolate()),

arguments->size(),

arguments->data());

}

再回过头来看看我们的代码。

const publicRequire = require(module).createRequire(process.cwd() + /);

globalThis.require = publicRequire;

publicRequire(./test);

require 函数是原生 JS 模块加载器,可以用来加载 Node.js 原生 JS 模块。通过 module 模块可以创建一个用户 JS 模块加载器。通过用户 JS 模块加载器,我们就可以把我们的代码串起来了。亿华云计算

很赞哦!(621)