@@ -146,6 +146,49 @@ interface BrowserEnvironmentOptions {
146146
147147const createHooksCallback = createMembraneMarshall ( ) ;
148148
149+ interface RealmControls {
150+ cleanup : ( ) => { } ;
151+ evaluator : typeof eval ;
152+ needsManualCleanUp : boolean ;
153+ }
154+ // @ts -ignore: TypeScript doesn't know what a ShadowRealm is yet.
155+ const { ShadowRealm : ShadowRealmCtor } = globalThis ;
156+ function createRealmControls ( options : BrowserEnvironmentOptions ) : RealmControls {
157+ let cleanup = ( ) => { } ;
158+ let evaluator : typeof eval ;
159+ let needsManualCleanUp = false ;
160+
161+ if ( typeof ShadowRealmCtor === 'function' ) {
162+ // @ts -ignore: TypeScript doesn't know what a ShadowRealm is yet.
163+ const shadowRealm = new ShadowRealm ( ) ;
164+ evaluator = shadowRealm . evaluate . bind ( shadowRealm ) ;
165+ } else {
166+ const { keepAlive } = options ;
167+ const iframe = createDetachableIframe ( ) ;
168+ const redWindow = HTMLIFrameElementContentWindowGetter ( iframe ) ! . window ;
169+ const { document : redDocument } = redWindow ;
170+ cleanup = ( ) => {
171+ // Once we get the iframe info ready, and all mapped, we can proceed
172+ // to detach the iframe only if the keepAlive option isn't true.
173+ if ( keepAlive !== true ) {
174+ removeIframe ( iframe ) ;
175+ } else {
176+ // TODO: Temporary hack to preserve the document reference in Firefox.
177+ // https://bugzilla.mozilla.org/show_bug.cgi?id=543435
178+ DocumentOpen ( redDocument ) ;
179+ DocumentClose ( redDocument ) ;
180+ }
181+ } ;
182+ evaluator = redWindow . eval ;
183+ needsManualCleanUp = true ;
184+ }
185+ return {
186+ cleanup,
187+ evaluator,
188+ needsManualCleanUp,
189+ } as RealmControls ;
190+ }
191+
149192export default function createVirtualEnvironment (
150193 globalObjectShape : object ,
151194 globalObjectVirtualizationTarget : WindowProxy & typeof globalThis ,
@@ -164,12 +207,10 @@ export default function createVirtualEnvironment(
164207 providedOptions
165208 ) ;
166209 // eslint-disable-next-line prefer-object-spread
167- const { distortionCallback, endowments = { } , keepAlive, support, instrumentation } = options ;
168- const iframe = createDetachableIframe ( ) ;
169- const redWindow = HTMLIFrameElementContentWindowGetter ( iframe ) ! . window ;
170- const { document : redDocument } = redWindow ;
210+ const { distortionCallback, endowments = { } , support, instrumentation } = options ;
211+ const realmControls = createRealmControls ( options ) ;
171212 const blueConnector = createHooksCallback ;
172- const redConnector = createConnector ( redWindow . eval ) ;
213+ const redConnector = createConnector ( realmControls . evaluator ) ;
173214 // Extract the global references and descriptors before any interference.
174215 const blueRefs = getCachedBlueReferences ( globalObjectVirtualizationTarget ) ;
175216 // Create a new environment.
@@ -184,15 +225,9 @@ export default function createVirtualEnvironment(
184225 linkIntrinsics ( env , globalObjectVirtualizationTarget ) ;
185226 linkUnforgeables ( env , globalObjectVirtualizationTarget ) ;
186227 tameDOM ( env , blueRefs , getResolvedShapeDescriptors ( globalObjectShape , endowments ) ) ;
187- // Once we get the iframe info ready, and all mapped, we can proceed
188- // to detach the iframe only if the keepAlive option isn't true.
189- if ( keepAlive !== true ) {
190- removeIframe ( iframe ) ;
191- } else {
192- // TODO: Temporary hack to preserve the document reference in Firefox.
193- // https://bugzilla.mozilla.org/show_bug.cgi?id=543435
194- DocumentOpen ( redDocument ) ;
195- DocumentClose ( redDocument ) ;
228+
229+ if ( realmControls . needsManualCleanUp ) {
230+ realmControls . cleanup ( ) ;
196231 }
197232 return env ;
198233}
0 commit comments