|
2 | 2 | #include <Foundation/Foundation.h>
|
3 | 3 | #include <sys/stat.h>
|
4 | 4 | #include <time.h>
|
| 5 | +#include <unistd.h> |
5 | 6 | #include <utime.h>
|
6 | 7 | #include <string>
|
7 | 8 | #include "Caches.h"
|
@@ -71,6 +72,9 @@ bool IsLikelyOptionalModule(const std::string& moduleName) {
|
71 | 72 | }
|
72 | 73 |
|
73 | 74 | bool ModuleInternal::RunModule(Isolate* isolate, std::string path) {
|
| 75 | + // Debug: Log module loading |
| 76 | + printf("ModuleInternal::RunModule: Loading module: %s\n", path.c_str()); |
| 77 | + |
74 | 78 | std::shared_ptr<Caches> cache = Caches::Get(isolate);
|
75 | 79 | Local<Context> context = cache->GetContext();
|
76 | 80 | Local<Object> globalObject = context->Global();
|
@@ -309,12 +313,45 @@ bool IsLikelyOptionalModule(const std::string& moduleName) {
|
309 | 313 |
|
310 | 314 | bool isESM = modulePath.size() >= 4 && modulePath.compare(modulePath.size() - 4, 4, ".mjs") == 0;
|
311 | 315 |
|
| 316 | + // Debug: Log ES module detection |
| 317 | + printf("LoadModule: Module path: %s, isESM: %s\n", modulePath.c_str(), isESM ? "true" : "false"); |
| 318 | + |
312 | 319 | if (isESM) {
|
313 | 320 | // For ES modules the returned value is the module namespace object, not a
|
314 | 321 | // factory function. Wire it as the exports and skip CommonJS invocation.
|
| 322 | + printf("LoadModule: Processing as ES module\n"); |
315 | 323 | if (!scriptValue->IsObject()) {
|
| 324 | + printf("LoadModule: ES module failed - scriptValue is not an object\n"); |
316 | 325 | throw NativeScriptException(isolate, "Failed to load ES module " + modulePath);
|
317 | 326 | }
|
| 327 | + printf("LoadModule: ES module loaded successfully\n"); |
| 328 | + |
| 329 | + // Debug: Check if we're in a worker context and if self.onmessage is set |
| 330 | + std::shared_ptr<Caches> cache = Caches::Get(isolate); |
| 331 | + if (cache->isWorker) { |
| 332 | + printf("LoadModule: In worker context, checking self.onmessage\n"); |
| 333 | + Local<Context> context = isolate->GetCurrentContext(); |
| 334 | + Local<Object> global = context->Global(); |
| 335 | + |
| 336 | + // Check if self exists |
| 337 | + Local<Value> selfValue; |
| 338 | + if (global->Get(context, ToV8String(isolate, "self")).ToLocal(&selfValue)) { |
| 339 | + printf("LoadModule: self exists: %s\n", selfValue->IsObject() ? "object" : "not object"); |
| 340 | + if (selfValue->IsObject()) { |
| 341 | + Local<Object> selfObj = selfValue.As<Object>(); |
| 342 | + Local<Value> onmessageValue; |
| 343 | + if (selfObj->Get(context, ToV8String(isolate, "onmessage")).ToLocal(&onmessageValue)) { |
| 344 | + printf("LoadModule: self.onmessage exists: %s\n", |
| 345 | + onmessageValue->IsFunction() ? "function" : "not function"); |
| 346 | + } else { |
| 347 | + printf("LoadModule: self.onmessage does not exist\n"); |
| 348 | + } |
| 349 | + } |
| 350 | + } else { |
| 351 | + printf("LoadModule: self does not exist\n"); |
| 352 | + } |
| 353 | + } |
| 354 | + |
318 | 355 | exportsObj = scriptValue.As<Object>();
|
319 | 356 | bool succ =
|
320 | 357 | moduleObj->Set(context, tns::ToV8String(isolate, "exports"), exportsObj).FromMaybe(false);
|
@@ -513,9 +550,41 @@ ScriptOrigin origin(
|
513 | 550 | Local<Value> result;
|
514 | 551 | {
|
515 | 552 | TryCatch tcEval(isolate);
|
| 553 | + printf("LoadESModule: About to evaluate module: %s\n", path.c_str()); |
516 | 554 | if (!module->Evaluate(context).ToLocal(&result)) {
|
| 555 | + printf("LoadESModule: Evaluation failed for module: %s\n", path.c_str()); |
517 | 556 | throw NativeScriptException(isolate, tcEval, "Cannot evaluate module " + path);
|
518 | 557 | }
|
| 558 | + printf("LoadESModule: Evaluation completed successfully for module: %s\n", path.c_str()); |
| 559 | + |
| 560 | + // Handle the case where evaluation returns a Promise (for top-level await) |
| 561 | + if (result->IsPromise()) { |
| 562 | + printf("LoadESModule: Module evaluation returned a Promise, waiting for resolution\n"); |
| 563 | + Local<Promise> promise = result.As<Promise>(); |
| 564 | + |
| 565 | + // For worker context, we need to wait for the promise to resolve |
| 566 | + // This is important for modules that use top-level await or have async initialization |
| 567 | + std::shared_ptr<Caches> cache = Caches::Get(isolate); |
| 568 | + if (cache->isWorker) { |
| 569 | + printf("LoadESModule: In worker context, processing promise resolution\n"); |
| 570 | + |
| 571 | + // Run the microtask queue to allow the promise to resolve |
| 572 | + while (promise->State() == Promise::kPending) { |
| 573 | + isolate->PerformMicrotaskCheckpoint(); |
| 574 | + // Add a small delay to prevent busy waiting |
| 575 | + usleep(1000); // 1ms |
| 576 | + } |
| 577 | + |
| 578 | + if (promise->State() == Promise::kRejected) { |
| 579 | + printf("LoadESModule: Promise was rejected\n"); |
| 580 | + Local<Value> reason = promise->Result(); |
| 581 | + isolate->ThrowException(reason); |
| 582 | + throw NativeScriptException(isolate, tcEval, "Module evaluation promise rejected"); |
| 583 | + } |
| 584 | + |
| 585 | + printf("LoadESModule: Promise resolved successfully\n"); |
| 586 | + } |
| 587 | + } |
519 | 588 | }
|
520 | 589 |
|
521 | 590 | // 7) Return the namespace
|
@@ -554,6 +623,22 @@ ScriptOrigin origin(
|
554 | 623 | if (path.size() >= 4 && path.compare(path.size() - 4, 4, ".mjs") == 0) {
|
555 | 624 | // Read raw text without wrapping.
|
556 | 625 | std::string sourceText = tns::ReadText(path);
|
| 626 | + |
| 627 | + // For ES modules in worker context, we need to provide access to global objects |
| 628 | + // since ES modules run in their own scope |
| 629 | + std::shared_ptr<Caches> cache = Caches::Get(isolate); |
| 630 | + if (cache && cache->isWorker) { |
| 631 | + // Prepend global declarations to make worker globals available in ES module scope |
| 632 | + std::string globalDeclarations = "const self = globalThis.self || globalThis;\n" |
| 633 | + "const postMessage = globalThis.postMessage;\n" |
| 634 | + "const close = globalThis.close;\n" |
| 635 | + "const importScripts = globalThis.importScripts;\n" |
| 636 | + "const console = globalThis.console;\n" |
| 637 | + "\n"; |
| 638 | + |
| 639 | + sourceText = globalDeclarations + sourceText; |
| 640 | + } |
| 641 | + |
557 | 642 | return tns::ToV8String(isolate, sourceText);
|
558 | 643 | }
|
559 | 644 |
|
|
0 commit comments