Skip to content

Commit f7be089

Browse files
committed
fix: bare specifier handling in debug vs release
1 parent 8aebe4c commit f7be089

2 files changed

Lines changed: 16 additions & 12 deletions

File tree

NativeScript/runtime/ModuleInternalCallbacks.mm

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1291,15 +1291,24 @@ static bool IsDocumentsPath(const std::string& path) {
12911291
absPath = builtinPath;
12921292
}
12931293
} else if (IsLikelyOptionalModule(spec)) {
1294-
// Create a placeholder file on disk that bundler can resolve to
1294+
// In debug/test builds, surface a clear unresolved bare specifier error instead of
1295+
// synthesizing a placeholder module; more helpful signal during development.
1296+
if (RuntimeConfig.IsDebug) {
1297+
std::string msg = "Cannot resolve bare specifier '" + spec + "'";
1298+
isolate->ThrowException(v8::Exception::Error(tns::ToV8String(isolate, msg.c_str())));
1299+
return v8::MaybeLocal<v8::Module>();
1300+
}
1301+
1302+
// In release builds, create a placeholder that throws on use,
1303+
// so apps can guard optional imports without crashing at import time.
12951304
std::string appPath = RuntimeConfig.ApplicationPath;
12961305
std::string placeholderPath = NormalizePath(appPath + "/" + spec + ".mjs");
12971306

12981307
// Check if placeholder file already exists
12991308
if (!isFile(placeholderPath)) {
13001309
// Create placeholder content
1301-
std::string placeholderContent = "const error = new Error('Module \\'" + spec +
1302-
"\\' is not available. This is an optional module.');\n"
1310+
std::string placeholderContent = "const error = new Error('Module \\\'" + spec +
1311+
"\\\' is not available. This is an optional module.');\n"
13031312
"const proxy = new Proxy({}, {\n"
13041313
" get: function(target, prop) { throw error; },\n"
13051314
" set: function(target, prop, value) { throw error; },\n"
@@ -1323,14 +1332,8 @@ static bool IsDocumentsPath(const std::string& path) {
13231332
} else {
13241333
// Failed to create file, fall back to throwing error
13251334
std::string msg = "Cannot find module " + spec + " (tried " + absPath + ")";
1326-
if (RuntimeConfig.IsDebug) {
1327-
Log(@"Debug mode - Optional module placeholder creation failed: %s", msg.c_str());
1328-
// Return empty instead of crashing in debug mode
1329-
return v8::MaybeLocal<v8::Module>();
1330-
} else {
1331-
isolate->ThrowException(v8::Exception::Error(tns::ToV8String(isolate, msg)));
1332-
return v8::MaybeLocal<v8::Module>();
1333-
}
1335+
isolate->ThrowException(v8::Exception::Error(tns::ToV8String(isolate, msg)));
1336+
return v8::MaybeLocal<v8::Module>();
13341337
}
13351338
} else {
13361339
// Placeholder file already exists, use it

TestRunner/app/tests/HttpEsmLoaderTests.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,11 @@ describe("HTTP ESM Loader", function() {
1717
});
1818
it("should surface helpful errors for unresolved bare specifiers", function(done) {
1919
import("bare-spec-example").then(function() {
20-
fail("Bare specifier should not have resolved successfully");
20+
(done.fail ? done.fail : fail)("Bare specifier should not have resolved successfully");
2121
done();
2222
}).catch(function(error) {
2323
const message = (error && error.message) ? error.message : String(error);
24+
// Expect our thrown helpful message containing the specifier name
2425
expect(message).toContain("bare-spec-example");
2526
done();
2627
});

0 commit comments

Comments
 (0)