JavaScript V8 C++应用中'require is not defined'错误求助
问题:V8 C++ 环境中无法识别
require 语句 我用V8 C++编写了一个运行含require语句JS代码的程序,代码如下:
// compile: g++ -std=c++14 simplest.cpp -g -o simplest -I/usr/include/v8 -L/path/to/v8/lib -lv8 -lv8_libplatform -pthread #include <iostream> #include <libplatform/libplatform.h> #include <v8.h> using namespace v8; char const* js_code = " \nconst { Jexl } = require('jexl'); \nconst jexl = new Jexl(); \nconst context = { \n x: 5, \n y: 10 \n}; \nconst expression = 'x * y + 2'; \njexl.eval(expression, context) \n .then(result => { \n console.log('Result:', result); \n }) \n .catch(error => { \n console.error('Error:', error); \n }); \n"; int main(int argc, char* argv[]) { // Initialize V8. V8::InitializeICUDefaultLocation(argv[0]); V8::InitializeExternalStartupData(argv[0]); std::unique_ptr<Platform> platform = platform::NewDefaultPlatform(); V8::InitializePlatform(platform.get()); V8::Initialize(); // Create a new Isolate and enter it. Isolate::CreateParams create_params; create_params.array_buffer_allocator = v8::ArrayBuffer::Allocator::NewDefaultAllocator(); Isolate* isolate = Isolate::New(create_params); { Isolate::Scope isolate_scope(isolate); HandleScope handle_scope(isolate); // Create a new context. Local<Context> context = Context::New(isolate); // Enter the created context for compiling and // running the JavaScript code. Context::Scope context_scope(context); // Create a string containing the JavaScript source code. Local<String> source = String::NewFromUtf8( isolate, js_code, NewStringType::kNormal).ToLocalChecked(); // Compile the source code. Local<Script> script = Script::Compile(context, source).ToLocalChecked(); // Run the script to get the result. Local<Value> result = script->Run(context).ToLocalChecked(); // Convert the result to a string and print it. String::Utf8Value utf8(isolate, result); printf("%s\n", *utf8); } // Dispose the isolate and tear down V8. isolate->Dispose(); V8::Dispose(); V8::ShutdownPlatform(); return 0; }
运行程序时出现错误:
<unknown>:18: Uncaught ReferenceError: require is not defined # # Fatal error in v8::ToLocalChecked # Empty MaybeLocal. #
相同的JS代码在Node.js中可正常执行:
// calculate_expression.js file const { Jexl } = require("jexl"); const jexl = new Jexl(); const context = { x: 5, y: 10 }; const expression = "x * y + 2"; jexl.eval(expression, context) .then(result => { console.log("Result:", result); }) .catch(error => { console.error("Error:", error); });
执行命令:
$ node calculate_expression.js Result: 52
环境信息:
- 操作系统:Debian 12.4
- libnode-dev包版本:18.19.0+dfsg-6~deb12u1
- Node.js版本:v18.19.0
解决方案
原因说明
require是Node.js提供的模块加载机制,并非V8引擎原生API。纯V8环境只提供JS执行核心,没有Node.js的CommonJS模块系统、文件IO等能力,因此直接运行含require的代码会报错。
方法1:基于Node.js C++ API开发(推荐)
既然已安装libnode-dev,直接使用Node.js的C++ API替代纯V8,可直接复用Node.js的模块系统。修改后的代码示例:
// compile: g++ -std=c++14 node_embed.cpp -o node_embed $(pkg-config --cflags --libs nodejs) #include <node.h> using namespace v8; void RunJS(const FunctionCallbackInfo<Value>& args) { Isolate* isolate = args.GetIsolate(); HandleScope scope(isolate); const char* js_code = R"( const { Jexl } = require('jexl'); const jexl = new Jexl(); const context = { x: 5, y: 10 }; const expression = 'x * y + 2'; jexl.eval(expression, context) .then(result => { console.log('Result:', result); }) .catch(error => { console.error('Error:', error); }); )"; Local<String> source = String::NewFromUtf8(isolate, js_code, NewStringType::kNormal).ToLocalChecked(); Local<Script> script = Script::Compile(isolate->GetCurrentContext(), source).ToLocalChecked(); script->Run(isolate->GetCurrentContext()).ToLocalChecked(); } void Initialize(Local<Object> exports) { NODE_SET_METHOD(exports, "run", RunJS); } NODE_MODULE(NODE_GYP_MODULE_NAME, Initialize)
编译时用pkg-config自动获取Node.js的编译参数,运行生成的二进制文件即可,也可作为Node.js模块加载执行。
方法2:在纯V8环境中手动实现简单的require
如果必须用纯V8,需自行实现模块加载逻辑,包括文件读取、模块缓存、CommonJS规范处理。简化示例如下:
- 在C++中添加文件读取函数并暴露给V8上下文:
// 添加头文件 #include <fstream> #include <string> // 读取文件内容的函数 Local<String> ReadFile(Isolate* isolate, const std::string& path) { std::ifstream file(path); if (!file.is_open()) { isolate->ThrowException(Exception::TypeError( String::NewFromUtf8(isolate, "Failed to open file").ToLocalChecked() )); return Local<String>(); } std::string content((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>()); return String::NewFromUtf8(isolate, content.c_str(), NewStringType::kNormal).ToLocalChecked(); } // 将函数暴露给V8上下文 void ExposeReadFile(Isolate* isolate, Local<Context> context) { Local<Object> global = context->Global(); Local<FunctionTemplate> read_file_tpl = FunctionTemplate::New(isolate, [](const FunctionCallbackInfo<Value>& args) { Isolate* isolate = args.GetIsolate(); if (args.Length() != 1 || !args[0]->IsString()) { isolate->ThrowException(Exception::TypeError( String::NewFromUtf8(isolate, "Expected a string path").ToLocalChecked() )); return; } String::Utf8Value path(isolate, args[0]); Local<String> content = ReadFile(isolate, std::string(*path)); args.GetReturnValue().Set(content); }); global->Set(context, String::NewFromUtf8(isolate, "readFile").ToLocalChecked(), read_file_tpl->GetFunction(context).ToLocalChecked()).Check(); }
- 在JS代码中添加
require实现:
const moduleCache = {}; function require(modulePath) { if (moduleCache[modulePath]) { return moduleCache[modulePath].exports; } const module = { exports: {} }; moduleCache[modulePath] = module; const code = readFile(modulePath); // 模拟CommonJS模块包装 const wrapper = `(function(module, exports) { ${code} })`; eval(wrapper)(module, module.exports); return module.exports; } // 注意使用模块的实际路径 const { Jexl } = require('./node_modules/jexl/lib/Jexl.js'); // ... 原代码其余部分不变
- 在C++中创建上下文后调用
ExposeReadFile(isolate, context);,将readFile函数暴露给JS。
这种方法需处理路径解析、循环依赖等细节,仅适合简单场景。
方法3:预编译模块为纯JS代码
用Webpack、Browserify等工具将jexl模块及其依赖打包成独立JS文件,移除require语句,再在V8中直接运行打包后的代码。此方法无需修改C++代码,仅需提前处理JS模块。
内容的提问来源于stack exchange,提问作者fgalan
相关产品推荐
相关产品推荐

