Skip to content

Commit 7782720

Browse files
authored
feat: http loaded es module realms + HMR DX enrichments (#1883)
1 parent 90ab54a commit 7782720

File tree

11 files changed

+1386
-442
lines changed

11 files changed

+1386
-442
lines changed

test-app/app/src/main/assets/app/mainpage.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,4 +75,4 @@ require('./tests/testQueueMicrotask');
7575

7676
// ES MODULE TESTS
7777
__log("=== Running ES Modules Tests ===");
78-
require("./tests/testESModules");
78+
require("./tests/testESModules.mjs");

test-app/app/src/main/assets/app/tests/testESModules.js

Lines changed: 0 additions & 103 deletions
This file was deleted.
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
async function runESModuleTests() {
2+
let passed = 0;
3+
let failed = 0;
4+
const failureDetails = [];
5+
6+
const recordPass = (message, ...args) => {
7+
console.log(`✅ PASS: ${message}`, ...args);
8+
passed++;
9+
};
10+
11+
const recordFailure = (message, options = {}) => {
12+
const { error, details = [] } = options;
13+
const fullMessage = error?.message
14+
? `${message}: ${error.message}`
15+
: message;
16+
console.log(`❌ FAIL: ${fullMessage}`);
17+
details.forEach((detail) => console.log(detail));
18+
if (error?.stack) {
19+
console.log("Stack trace:", error.stack);
20+
}
21+
failed++;
22+
failureDetails.push(fullMessage);
23+
};
24+
25+
const logFinalSummary = () => {
26+
console.log("\n=== ES MODULE TEST RESULTS ===");
27+
console.log("Tests passed:", passed);
28+
console.log("Tests failed:", failed);
29+
console.log("Total tests:", passed + failed);
30+
31+
if (failed === 0) {
32+
console.log("ALL ES MODULE TESTS PASSED!");
33+
} else {
34+
console.log("SOME ES MODULE TESTS FAILED!");
35+
console.log("FAILURE DETECTED: Starting failure logging");
36+
failureDetails.forEach((detail) => {
37+
console.log(` ❌ ${detail}`);
38+
});
39+
}
40+
};
41+
42+
try {
43+
// Test 1: Load .mjs files as ES modules
44+
console.log("\n--- Test 1: Loading .mjs files as ES modules ---");
45+
try {
46+
const moduleExports = await import("~/testSimpleESModule.mjs");
47+
if (moduleExports) {
48+
recordPass("Module exports:", JSON.stringify(moduleExports));
49+
} else {
50+
recordFailure("ES Module loaded but exports are null");
51+
}
52+
53+
if (moduleExports?.moduleType === "ES Module") {
54+
recordPass("moduleType check passed");
55+
} else {
56+
recordFailure("moduleType check failed");
57+
}
58+
} catch (e) {
59+
recordFailure("Error loading ES module", { error: e });
60+
}
61+
62+
// Test 2: Test import.meta functionality
63+
console.log("\n--- Test 2: Testing import.meta functionality ---");
64+
try {
65+
const importMetaModule = await import("~/testImportMeta.mjs");
66+
if (
67+
importMetaModule &&
68+
importMetaModule.default &&
69+
typeof importMetaModule.default === "function"
70+
) {
71+
const metaResults = importMetaModule.default();
72+
console.log(
73+
"import.meta test results:",
74+
JSON.stringify(metaResults, null, 2)
75+
);
76+
77+
if (
78+
metaResults &&
79+
metaResults.hasImportMeta &&
80+
metaResults.hasUrl &&
81+
metaResults.hasDirname
82+
) {
83+
recordPass("import.meta properties present");
84+
console.log(" - import.meta.url:", metaResults.url);
85+
console.log(" - import.meta.dirname:", metaResults.dirname);
86+
} else {
87+
recordFailure("import.meta properties missing", {
88+
details: [
89+
` - hasImportMeta: ${metaResults?.hasImportMeta}`,
90+
` - hasUrl: ${metaResults?.hasUrl}`,
91+
` - hasDirname: ${metaResults?.hasDirname}`,
92+
],
93+
});
94+
}
95+
} else {
96+
recordFailure("import.meta module has no default export function");
97+
}
98+
} catch (e) {
99+
recordFailure("Error testing import.meta", { error: e });
100+
}
101+
102+
// Test 3: Test Worker enhancements
103+
console.log("\n--- Test 3: Testing Worker enhancements ---");
104+
try {
105+
const workerModule = await import("~/testWorkerFeatures.mjs");
106+
if (
107+
workerModule &&
108+
workerModule.testWorkerFeatures &&
109+
typeof workerModule.testWorkerFeatures === "function"
110+
) {
111+
const workerResults = workerModule.testWorkerFeatures();
112+
console.log(
113+
"Worker features test results:",
114+
JSON.stringify(workerResults, null, 2)
115+
);
116+
117+
if (
118+
workerResults &&
119+
workerResults.stringPathSupported &&
120+
workerResults.urlObjectSupported &&
121+
workerResults.tildePathSupported
122+
) {
123+
recordPass("Worker enhancement features present");
124+
console.log(
125+
" - String path support:",
126+
workerResults.stringPathSupported
127+
);
128+
console.log(
129+
" - URL object support:",
130+
workerResults.urlObjectSupported
131+
);
132+
console.log(
133+
" - Tilde path support:",
134+
workerResults.tildePathSupported
135+
);
136+
} else {
137+
recordFailure("Worker enhancement features missing", {
138+
details: [
139+
` - stringPathSupported: ${workerResults?.stringPathSupported}`,
140+
` - urlObjectSupported: ${workerResults?.urlObjectSupported}`,
141+
` - tildePathSupported: ${workerResults?.tildePathSupported}`,
142+
],
143+
});
144+
}
145+
} else {
146+
recordFailure(
147+
"Worker features module has no testWorkerFeatures function"
148+
);
149+
}
150+
} catch (e) {
151+
recordFailure("Error testing Worker features", { error: e });
152+
}
153+
} catch (unexpectedError) {
154+
recordFailure("Unexpected ES module test harness failure", {
155+
error: unexpectedError,
156+
});
157+
} finally {
158+
logFinalSummary();
159+
}
160+
161+
return { passed, failed };
162+
}
163+
164+
// Run the tests immediately (avoid top-level await for broader runtime support)
165+
runESModuleTests().catch((e) => {
166+
console.error("ES Module top-level failure:", e?.message ?? e);
167+
});
Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,32 @@
11
describe("Runtime exposes", function () {
2-
it("__time a low overhead, high resolution, time in ms.", function() {
2+
it("__time a low overhead, high resolution, time in ms.", function () {
33
// Try to get the times using Date.now and __time and compare the results, expect them to be somewhat "close".
44
// Sometimes GC hits after Date.now is captured but before __time or the vice-versa and the test fails,
55
// so we are giving it several attempts.
6-
for(var i = 0; i < 5; i++) {
6+
for (var i = 0; i < 5; i++) {
77
try {
88
var dateTimeStart = Date.now();
99
var timeStart = __time();
1010
var acc = 0;
1111
var s = android.os.SystemClock.elapsedRealtime();
1212
for (var i = 0; i < 1000; i++) {
1313
var c = android.os.SystemClock.elapsedRealtime();
14-
acc += (c - s);
14+
acc += c - s;
1515
s = c;
1616
}
1717
var dateTimeEnd = Date.now();
1818
var timeEnd = __time();
1919
var dateDelta = dateTimeEnd - dateTimeStart;
2020
var timeDelta = timeEnd - timeStart;
21-
expect(Math.abs(dateDelta - timeDelta) < dateDelta * 0.25).toBe(true);
21+
var tolerance = Math.max(10, dateDelta * 0.5);
22+
expect(timeDelta > 0).toBe(true);
23+
expect(Math.abs(dateDelta - timeDelta) < tolerance).toBe(true);
2224
break;
23-
} catch(e) {
25+
} catch (e) {
2426
if (i == 4) {
2527
throw e;
2628
}
2729
}
2830
}
2931
});
30-
});
32+
});

test-app/runtime/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,8 @@ add_library(
147147
src/main/cpp/URLImpl.cpp
148148
src/main/cpp/URLSearchParamsImpl.cpp
149149
src/main/cpp/URLPatternImpl.cpp
150+
src/main/cpp/HMRSupport.cpp
151+
src/main/cpp/DevFlags.cpp
150152

151153
# V8 inspector source files will be included only in Release mode
152154
${INSPECTOR_SOURCES}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// DevFlags.cpp
2+
#include "DevFlags.h"
3+
#include "JEnv.h"
4+
#include <atomic>
5+
#include <mutex>
6+
7+
namespace tns {
8+
9+
bool IsScriptLoadingLogEnabled() {
10+
static std::atomic<int> cached{-1}; // -1 unknown, 0 false, 1 true
11+
int v = cached.load(std::memory_order_acquire);
12+
if (v != -1) {
13+
return v == 1;
14+
}
15+
16+
static std::once_flag initFlag;
17+
std::call_once(initFlag, []() {
18+
bool enabled = false;
19+
try {
20+
JEnv env;
21+
jclass runtimeClass = env.FindClass("com/tns/Runtime");
22+
if (runtimeClass != nullptr) {
23+
jmethodID mid = env.GetStaticMethodID(runtimeClass, "getLogScriptLoadingEnabled", "()Z");
24+
if (mid != nullptr) {
25+
jboolean res = env.CallStaticBooleanMethod(runtimeClass, mid);
26+
enabled = (res == JNI_TRUE);
27+
}
28+
}
29+
} catch (...) {
30+
// keep default false
31+
}
32+
cached.store(enabled ? 1 : 0, std::memory_order_release);
33+
});
34+
35+
return cached.load(std::memory_order_acquire) == 1;
36+
}
37+
38+
} // namespace tns
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// DevFlags.h
2+
#pragma once
3+
4+
namespace tns {
5+
6+
// Fast cached flag: whether to log script loading diagnostics.
7+
// First call queries Java once; subsequent calls are atomic loads only.
8+
bool IsScriptLoadingLogEnabled();
9+
10+
}

0 commit comments

Comments
 (0)