如何把 Node.js 嵌入自己的项目中
Node.js 不仅可以单独运行,还可以以库的方式被使用,本文介绍下如何把 Node.js 嵌入到自己项目中。
首先第一步下载 Node.js 源码,然后根据 Node.js 的文档进行编译安装。这样我们就可以拿到 Node.js 提供的头文件和库文件了。接下来根据官方的 demo 写一个测试程序。
#include "node.h"
#include "uv.h"
#include <assert.h>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<std::string>& args,const std::vector<std::string>& exec_args);int main(int argc, char** argv) {argv = uv_setup_args(argc, argv);std::vector<std::string> args(argv, argv + argc);std::vector<std::string> exec_args;std::vector<std::string> errors;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_ptr<MultiIsolatePlatform> platform =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<std::string>& args,const std::vector<std::string>& exec_args) {int exit_code = 0;std::vector<std::string> errors;std::unique_ptr<CommonEnvironmentSetup> setup =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());MaybeLocal<Value> loadenv_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 看起。
MaybeLocal<Value> LoadEnvironment(Environment* env,const char* main_script_source_utf8) {Isolate* isolate = env->isolate();return LoadEnvironment(env,[&](const StartExecutionCallbackInfo& info) -> MaybeLocal<Value> {// 一会分析});
}
LoadEnvironment 进一步调了另一个 LoadEnvironment。
MaybeLocal<Value> LoadEnvironment(Environment* env,StartExecutionCallback cb) {env->InitializeLibuv();env->InitializeDiagnostics();return StartExecution(env, cb);
}
LoadEnvironment 进行了一些初始化,接着调 StartExecution。
MaybeLocal<Value> StartExecution(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 模块加载器。接着看回调函数的逻辑。
[&](const StartExecutionCallbackInfo& info) -> MaybeLocal<Value> {// main_script_source_utf8 为我们传入到字符串代码Local<String> str =String::NewFromUtf8(isolate,main_script_source_utf8).ToLocalChecked();auto main_utf16 = std::make_unique<String::Value>(isolate, str);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<Local<String>> params = {env->process_string(),env->require_string()};std::vector<Local<Value>> args = {env->process_object(),env->native_module_require()};// 执行我们的代码return ExecuteBootstrapper(env, name.c_str(), ¶ms, &args);}
回调函数通过 ExecuteBootstrapper 执行我们传入的代码。
MaybeLocal<Value> ExecuteBootstrapper(Environment* env,const char* id,std::vector<Local<String>>* parameters,std::vector<Local<Value>>* arguments) {EscapableHandleScope scope(env->isolate());// 从原生 JS 模块代码中找到我们的代码MaybeLocal<Function> maybe_fn =NativeModuleEnv::LookupAndCompile(env->context(), id, parameters, env);Local<Function> fn;if (!maybe_fn.ToLocal(&fn)) {return MaybeLocal<Value>();}// 执行我们的代码MaybeLocal<Value> result = 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 模块加载器,我们就可以把我们的代码串起来了。
如何把 Node.js 嵌入自己的项目中相关推荐
- Node.js期中爬虫实验项目
Node.js期中爬虫实验项目 期中作业要求 基础概念引入 前期准备工作 安装node.js 安装数据库 安装Navicat Premium 15 正则表达式学习网站 课堂示例演示 示例一(显示在终端 ...
- helmet是一个保护Node.JS应用的安全项目
helmet是一个保护Node.JS应用的安全项目 14-11-15 banq #NodeJS #express #安全 Helmet是一系列帮助增强Node.JS之 ...
- 体验使用node.js创建vue+Element-UI项目
1.首先去node.js官网下载系统对应的node.js版本. 2.安装淘宝镜像 npm install -g cnpm --registry=https://registry.npm.taobao. ...
- Node.js结合Express框架项目搭建
一.简述 本次项目是用node.js写后台接口,前端使用vue.js分离的方法实现一个在线点咖啡的项目.本节教程只是一个简单的入门,关于实际用法后期继续更新. 二.搭建应用 1. 通过应用生成器工具 ...
- 使用node.js 脚手架搭建Vue项目
1.安装node.js https://nodejs.org/zh-cn/ 下载安装node.js在命令行测试 node -v 输出版本号说明安装成功 2.使用npm更新安装cpnm npm inst ...
- node.js+uni计算机毕设项目计算机配件价格查询微信小程序(程序+小程序+LW)
该项目含有源码.文档.程序.数据库.配套开发软件.软件安装教程.欢迎交流 项目运行 环境配置: Node.js+ Vscode + Mysql5.7 + HBuilderX+Navicat11+Vue ...
- node.js+uni计算机毕设项目基于微信小程序在线抽签系统(程序+小程序+LW)
该项目含有源码.文档.程序.数据库.配套开发软件.软件安装教程.欢迎交流 项目运行 环境配置: Node.js+ Vscode + Mysql5.7 + HBuilderX+Navicat11+Vue ...
- Vue2+Node.js前后端分离项目部署到云服务器
本文参考教程: NodeJS项目部署到阿里云ECS服务器全程详解 - 知乎本文详细介绍如何部署NodeJS项目到阿里云ECS上,以及本人在部署过程中所遇到的问题.坑点和解决办法,可以说是全网最全最详细 ...
- node.js+uni计算机毕设项目基于微信小程序的车位共享系统LWPPT(程序+小程序+LW)
该项目含有源码.文档.程序.数据库.配套开发软件.软件安装教程.欢迎交流 项目运行 环境配置: Node.js+ Vscode + Mysql5.7 + HBuilderX+Navicat11+Vue ...
最新文章
- 气泡图在开源监控工具中的应用效果
- 全球与中国人脸语音生物识别市场”十四“五规模状况与前景趋势分析报告2021-2027年版
- 若依微服务版新建业务模块后提示找不到mapper的解决方法
- 深度学习-Tensorflow2.2-深度学习基础和tf.keras{1}-tf.keras函数式API-08
- xshell连接虚拟机里的linux系统
- 使用 ABAP 开发的一个基于 Web Socket 的小工具,能提高程序员日常工作效率
- Netweaver和SAP云平台的quota管理
- HDU - 4497 GCD and LCM
- 第一阶段:前端开发_Mysql——表与表之间的关系
- [Leetcode][第32题][JAVA][最长有效括号][动态规划][栈][正向逆向结合]
- c常用算法程序集_10万赞的AI算法集:含python,java,C,C++多种语言
- C++---异常处理
- Predictably Irractional - 期望的效应
- python通过类名创建对象_如何在Python中为自动创建的类对象分配名称
- cd40系列芯片_CD40系列芯片大全
- 东北四省赛E-Minimum Spanning Tree-贡献求和
- 百度地图自定义图标动画
- 色即是空 空即是色_huadingjin_新浪博客
- 直击文印痛点 中小企业需要这样一台复合机
- printf 打印结构体成员函数出错原因分析
热门文章
- 汇顶科技外包java_【汇顶科技有限公司Java面试】2020春季校招后端Java-看准网
- 招人:没钱靠谱的我们想和你一起探索人生的可能性
- 分析Nginx是如何实现反向代理和负载均衡
- android app根目录下cache,Android 缓存目录 Context.getExternalFilesDir()和Context.getExternalCacheDir()方法...
- python入门基础002
- mysql中depart_mysql实训
- 优质开源:共享图书小程序3.0 全新UI 免费下载
- Prior Posterior和Likelihood的理解与几种表达方式
- RPG 游戏数值系统—1
- 云和恩墨大讲堂电子期刊第四期