diff --git a/NativeScript/NativeScript.mm b/NativeScript/NativeScript.mm index 11f8ae80..caf37186 100644 --- a/NativeScript/NativeScript.mm +++ b/NativeScript/NativeScript.mm @@ -10,10 +10,7 @@ using namespace v8; using namespace tns; -namespace tns { -// External flag from Runtime.mm to track JavaScript errors -extern bool jsErrorOccurred; -} +namespace tns {} @implementation Config @@ -44,19 +41,6 @@ - (void)runScriptString:(NSString*)script runLoop:(BOOL)runLoop { - (void)runMainApplication { runtime_->RunMainScript(); - // In debug mode, if JavaScript errors occurred, keep the app alive indefinitely - // This prevents iOS from terminating the app and allows hot-reload to work - if (RuntimeConfig.IsDebug && jsErrorOccurred) { - // Log(@"Debug mode - JavaScript errors detected, entering infinite run loop to prevent app termination"); - - while (true) { - CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, true); - tns::Tasks::Drain(); - } - // Note: This line is never reached in debug mode with errors - } - - // Normal execution path (no errors or release mode) CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true); tns::Tasks::Drain(); } diff --git a/NativeScript/runtime/ModuleInternal.mm b/NativeScript/runtime/ModuleInternal.mm index b55a5cb2..ae56a9bf 100644 --- a/NativeScript/runtime/ModuleInternal.mm +++ b/NativeScript/runtime/ModuleInternal.mm @@ -6,10 +6,10 @@ #include #include #include "Caches.h" +#include "DevFlags.h" #include "Helpers.h" #include "ModuleInternalCallbacks.h" // for ResolveModuleCallback #include "NativeScriptException.h" -#include "DevFlags.h" #include "Runtime.h" // for GetAppConfigValue #include "RuntimeConfig.h" @@ -17,9 +17,6 @@ namespace tns { -// External flag from Runtime.mm to track JavaScript errors -extern bool jsErrorOccurred; - // Helper function to check if a module name looks like an optional external module bool IsLikelyOptionalModule(const std::string& moduleName) { // Check if it's a bare module name (no path separators) that could be an npm package @@ -171,27 +168,15 @@ bool IsESModule(const std::string& path) { Local moduleNamespace; try { moduleNamespace = ModuleInternal::LoadESModule(isolate, path); - } catch (const NativeScriptException& ex) { + } catch (NativeScriptException& ex) { if (RuntimeConfig.IsDebug) { - Log(@"***** JavaScript exception occurred - detailed stack trace follows *****"); Log(@"Error loading ES module: %s", path.c_str()); Log(@"Exception: %s", ex.getMessage().c_str()); - Log(@"***** End stack trace - continuing execution *****"); - Log(@"Debug mode - ES module loading failed, but telling iOS it succeeded to prevent app termination"); - return true; // avoid termination in debug - } else { - return false; - } - } - if (moduleNamespace.IsEmpty()) { - if (RuntimeConfig.IsDebug) { - Log(@"Debug mode - ES module returned empty namespace, but telling iOS it succeeded"); - return true; - } else { - return false; } + ex.ReThrowToV8(isolate); + return false; } - return true; // ES module loaded successfully + return true; } // For CommonJS modules (.js), use the traditional require() approach @@ -211,31 +196,17 @@ bool IsESModule(const std::string& path) { if (!success || tc.HasCaught()) { if (RuntimeConfig.IsDebug) { - Log(@"***** JavaScript exception occurred - detailed stack trace follows *****"); Log(@"Error in require() call:"); Log(@" Requested module: '%s'", path.c_str()); Log(@" Called from: %s", RuntimeConfig.ApplicationPath.c_str()); - if (tc.HasCaught()) { tns::LogError(isolate, tc); } - - Log(@"***** End stack trace - continuing execution *****"); - Log(@"Debug mode - Main script execution failed, but telling iOS it succeeded to prevent " - @"app termination"); - - // Add a small delay to ensure error modal has time to render before we return - dispatch_after( - dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), - dispatch_get_main_queue(), ^{ - Log(@"πŸ›‘οΈ Debug mode - Crash prevention complete, app should remain stable"); - }); - - return true; // LIE TO iOS - return success to prevent app termination - } else { - // In release mode, still fail as before - return false; } + if (tc.HasCaught()) { + tc.ReThrow(); + } + return false; } return success; @@ -255,33 +226,13 @@ bool IsESModule(const std::string& path) { bool success = requireFuncFactory->Call(context, thiz, 2, args).ToLocal(&result); if (!success || tc.HasCaught()) { if (tc.HasCaught()) { - tns::LogError(isolate, tc); + throw NativeScriptException(isolate, tc, "Failed to call require factory function"); } - Log(@"FATAL: Failed to call require factory function"); - // Return a dummy function to avoid further crashes - result = v8::Function::New(context, [](const v8::FunctionCallbackInfo& info) { - if (RuntimeConfig.IsDebug) { - Log(@"Debug mode - Require function unavailable (factory failed)"); - info.GetReturnValue().SetUndefined(); - } else { - info.GetIsolate()->ThrowException(v8::Exception::Error( - tns::ToV8String(info.GetIsolate(), "Require function unavailable"))); - } - }).ToLocalChecked(); + throw NativeScriptException(isolate, "Failed to call require factory function"); } if (result.IsEmpty() || !result->IsFunction()) { - Log(@"FATAL: Require factory did not return a function"); - // Return a dummy function - result = v8::Function::New(context, [](const v8::FunctionCallbackInfo& info) { - if (RuntimeConfig.IsDebug) { - Log(@"Debug mode - Require function unavailable (no function returned)"); - info.GetReturnValue().SetUndefined(); - } else { - info.GetIsolate()->ThrowException(v8::Exception::Error( - tns::ToV8String(info.GetIsolate(), "Require function unavailable"))); - } - }).ToLocalChecked(); + throw NativeScriptException(isolate, "Require factory did not return a function"); } return result.As(); @@ -302,7 +253,9 @@ bool IsESModule(const std::string& path) { if (*s) { moduleName.assign(*s, s.length()); if (moduleName.rfind("http://", 0) == 0 || moduleName.rfind("https://", 0) == 0) { - std::string msg = std::string("NativeScript: require() of URL module is not supported: ") + moduleName + ". Use dynamic import() instead."; + std::string msg = + std::string("NativeScript: require() of URL module is not supported: ") + moduleName + + ". Use dynamic import() instead."; throw NativeScriptException(msg.c_str()); } } @@ -357,7 +310,6 @@ bool IsESModule(const std::string& path) { fullPath = [NSString stringWithUTF8String:moduleName.c_str()]; } - NSString* fileNameOnly = [fullPath lastPathComponent]; NSString* pathOnly = [fullPath stringByDeletingLastPathComponent]; @@ -531,62 +483,13 @@ bool IsESModule(const std::string& path) { // Compile/load the JavaScript/ESM source Local scriptValue = LoadScript(isolate, modulePath); - // Check if script loading failed (debug mode graceful returns) - if (scriptValue.IsEmpty()) { - if (RuntimeConfig.IsDebug) { - // NSLog(@"Debug mode - Script loading returned empty value, returning gracefully: %s", - // modulePath.c_str()); - return Local(); - } else { - throw NativeScriptException(isolate, "Script loading failed for " + modulePath); - } - } - // Check if this is an ES module bool isESM = IsESModule(modulePath); std::shared_ptr cache = Caches::Get(isolate); if (isESM) { - // For ES modules, the returned value is the namespace object - - // First check if scriptValue is empty (from debug mode graceful returns) - if (scriptValue.IsEmpty()) { - if (RuntimeConfig.IsDebug) { - Log(@"Debug mode - ES module returned empty value, returning gracefully: %s", - modulePath.c_str()); - return Local(); - } else { - throw NativeScriptException(isolate, "ES module load returned empty value " + modulePath); - } - } - if (!scriptValue->IsObject()) { - if (RuntimeConfig.IsDebug) { - Log(@"Debug mode - ES module load failed, returning gracefully: %s", modulePath.c_str()); - // Return empty module object to prevent crashes - return Local(); - } else { - throw NativeScriptException(isolate, "Failed to load ES module " + modulePath); - } - } - - // Debug: Check if we're in a worker context and if self.onmessage is set - std::shared_ptr cache = Caches::Get(isolate); - if (cache->isWorker) { - Local context = isolate->GetCurrentContext(); - Local global = context->Global(); - - // Check if self exists - Local selfValue; - if (global->Get(context, ToV8String(isolate, "self")).ToLocal(&selfValue)) { - if (selfValue->IsObject()) { - Local selfObj = selfValue.As(); - Local onmessageValue; - if (selfObj->Get(context, ToV8String(isolate, "onmessage")).ToLocal(&onmessageValue)) { - // onmessage exists - } - } - } + throw NativeScriptException(isolate, "Failed to load ES module " + modulePath); } // Handle exports differently for ES modules vs worker scripts @@ -640,7 +543,8 @@ throw NativeScriptException(isolate, // Shorten the parentDir for GetRequireFunction to avoid V8 parsing issues with long paths std::string shortParentDir; if (parentDir.length() >= RuntimeConfig.ApplicationPath.length() && - parentDir.compare(0, RuntimeConfig.ApplicationPath.length(), RuntimeConfig.ApplicationPath) == 0) { + parentDir.compare(0, RuntimeConfig.ApplicationPath.length(), RuntimeConfig.ApplicationPath) == + 0) { shortParentDir = "/app" + parentDir.substr(RuntimeConfig.ApplicationPath.length()); } else { // Fallback: use the entire path if it doesn't start with ApplicationPath @@ -713,65 +617,19 @@ throw NativeScriptException(isolate, Local