You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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规范处理。简化示例如下:

  1. 在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();
}
  1. 在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'); 
// ... 原代码其余部分不变
  1. 在C++中创建上下文后调用ExposeReadFile(isolate, context);,将readFile函数暴露给JS。

这种方法需处理路径解析、循环依赖等细节,仅适合简单场景。

方法3:预编译模块为纯JS代码

用Webpack、Browserify等工具将jexl模块及其依赖打包成独立JS文件,移除require语句,再在V8中直接运行打包后的代码。此方法无需修改C++代码,仅需提前处理JS模块。


内容的提问来源于stack exchange,提问作者fgalan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 14:20:00