Install globalEvalWithSourceUrl on bridgeless ReactInstance - #58718
abzokhattab wants to merge 4 commits into
Conversation
Bridge mode already exposes this helper from JSIExecutor so Metro debug loaders can evaluate fetched JS via JSI. Hermes rejects JS eval() of Metro __d(...) source, so lazy chunks fail on New Architecture.
|
Hi @abzokhattab! Thank you for your pull request and welcome to our community. Action RequiredIn order to merge any pull request (code, docs, etc.), we require contributors to sign our Contributor License Agreement, and we don't seem to have one on file for you. ProcessIn order for us to review and merge your suggested changes, please sign at https://code.facebook.com/cla. If you are contributing on behalf of someone else (eg your employer), the individual CLA may not be sufficient and your employer may need to sign the corporate CLA. Once the CLA is signed, our tooling will perform checks and validations. Afterwards, the pull request will be tagged with If you have received this in error or have any questions, please contact us at cla@meta.com. Thanks! |
|
Thank you for signing our Contributor License Agreement. We can now accept your code for this (and any) Meta Open Source project. Thanks! |
|
@fabriziocucci has imported this pull request. If you are a Meta employee, you can view this in D122329977. |
|
I don't think this addresses your problem. "Parsing source code unsupported" comes from Hermes and means the engine was built without eval support (HERMESVM_LEAN) |
|
Thanks for taking a look. I agree that message is Hermes rejecting runtime parse (no compiler /
typeof global.globalEvalWithSourceUrl
// bridgeless: "undefined"
// bridge: "function"If this VM were fully unable to compile source, the main Metro bundle would fail the same way. It does not. The gap is only that split-bundle loaders fall back to JS Happy to add a more targeted test if you want (call the helper with a small |
|
Please add a test (eg fantom?) documenting the difference in behaviour between eval and the globalEval |
Document that the helper is installed on the New Architecture runtime and can evaluate Metro-shaped source, including how that compares to JS eval().
|
Added the following test:
The first assertion is the bridgeless gap (helper missing → fail; installed → pass). |
The Fantom test now asserts eval()'s result and the source URL attribution difference. The C++ test builds a runtime with RuntimeConfig::EnableEval=false to show eval() throws while globalEvalWithSourceUrl still evaluates source.
Use unknown instead of the deprecated mixed, and read the host function untyped in the arity test so Flow does not reject the deliberate bad call.
Summary:
Problem: On the New Architecture (bridgeless), fetching and evaluating a Metro split bundle in development (
lazy=true,import(),React.lazy()) can fail with:The main bundle still loads.
Root cause:
global.globalEvalWithSourceUrlis never installed on bridgeless. Bridge mode installs it inJSIExecutor::initializeRuntime.The debug loader (
Libraries/Core/Devtools/loadBundleFromServer.js) prefers that helper and only falls back to JSeval()when it is missing. The two paths are not equivalent in Hermes:eval()/Functiongo throughevalInEnvironment, which raisesParsing source code unsupportedwhenRuntimeConfig::EnableEvalis false (and, on legacy Hermes, when the engine is built lean).globalEvalWithSourceUrlgoes throughRuntime::evaluateJavaScript, the same entry point used to run the main bundle. It is not gated byEnableEval, and it attaches the given source URL to stack traces.So on a runtime where
EnableEvalis off (or the engine is lean), the main bundle loads but every split bundle falls intoeval()and throws. Bridgeless has no way to reach the JSI path from JS today.Fix: Port the existing
JSIExecutorbinding intoReactInstance::initializeRuntimeso bridgeless exposes the same helper.Changelog:
[General] [Fixed] - Install globalEvalWithSourceUrl on bridgeless ReactInstance so debug bundle loaders can evaluate split bundles via JSI instead of eval()
Test Plan:
ReactInstanceTest.testGlobalEvalWithSourceUrlIsInstalled: helper is absent beforeinitializeRuntimeand present after.ReactInstanceTest.testGlobalEvalWithSourceUrlMatchesEvalWhenEvalIsEnabled: with the defaultRuntimeConfig,eval('1 + 2')andglobalEvalWithSourceUrl('1 + 2', 'chunk.js')both return3.ReactInstanceWithoutEvalTest.testGlobalEvalWithSourceUrlWorksWhenEvalIsDisabled: runtime built withRuntimeConfig::Builder().withEnableEval(false);eval('1 + 2')throwsParsing source code unsupported,globalEvalWithSourceUrl('1 + 2', 'chunk.js')returns3.Libraries/Core/Devtools/__tests__/globalEvalWithSourceUrl-itest.js: helper is installed on bridgeless;eval()and the helper evaluate the same source to the same result; an error thrown from the helper carries the given source URL in its stack while theeval()one does not; wrong arity throws.typeof global.globalEvalWithSourceUrlis'function'and aReact.lazy(() => import('./SomeModule'))split bundle loads withoutParsing source code unsupported.