DEV Community

Andrew Elans
Andrew Elans

Posted on

Top-level await on iOS Safari/Chrome fails

Ref. caniuse

Had to dig a bit why on mobile Chrome/Safari behavior was different than on desktop and found that top level await fails in some scenarios.

Google WebKit bug top-level await.

Logic

Main module

Loading scripts in sequence, order is important.

await import('./msal-config.js');
await import('./public-assets.js');
await import('./msal-index.js');
await import('./assets/navbar-02.js')
Enter fullscreen mode Exit fullscreen mode

navbar-02.js

console.log('<<<<<<<<<<<< navbar-02.js start')
import { snippetsObj, navButtonsSet } from './whoami-01.js';

// snippetsObj and navButtonsSet are used to render SPA view

console.log('<<<<<<<<<<<< navbar-02.js end')
Enter fullscreen mode Exit fullscreen mode

whoami-01.js

console.log('<<<<<<<<<<<< whoami-01.js start')
const navButtonsSet = new Set();
const snippetsObj = {
    routesMap: new Map(),
    savedStates: new Map()
};

// some logic that checks user's access, 
// and loads right snippets into snippetsObj 
// and navButtonsSet
await m.pipeFn(fn1, fn2, fn3, ... fn10); 

export { snippetsObj, navButtonsSet }

console.log('<<<<<<<<<<<< whoami-01.js end')
Enter fullscreen mode Exit fullscreen mode

Flow in desktop browser

<<<<<<<<<<<< dynamic-01-whoami.js start
<<<<<<<<<<<< dynamic-01-whoami.js end
<<<<<<<<<<<< dynamic-02-navbar.js start
<<<<<<<<<<<< dynamic-02-navbar.js end
Enter fullscreen mode Exit fullscreen mode

Flow in iOS Safari

<<<<<<<<<<<< dynamic-01-whoami.js start
<<<<<<<<<<<< dynamic-02-navbar.js start
<<<<<<<<<<<< dynamic-02-navbar.js end
<<<<<<<<<<<< dynamic-01-whoami.js end
Enter fullscreen mode Exit fullscreen mode

Fix

The best option is to refactor to simplify import logic. Here is quick fix.

whoami-01.js rewritten

const navButtonsSet = new Set();
const snippetsObj = {
    routesMap: new Map(),
    savedStates: new Map()
};

const p = Promise.withResolvers();

// wrap in IIFE and export promise
(async () => {
    await m.pipeFn(
        fn1, 
        fn2, 
        fn3, 
        ..., 
        fn10, 
        () => p.resolve({navButtonsSet, snippetsObj}) // last fn added to resolve the promise with populated objects
    )
})()

export default p.promise
Enter fullscreen mode Exit fullscreen mode

navbar-02.js rewritten

Option 1

import defaultExport from './whoami-01.js';
const {snippetsObj, navButtonsSet } = await defaultExport;
Enter fullscreen mode Exit fullscreen mode

Option 2

const {snippetsObj, navButtonsSet } = await import('./dynamic-01-whoami.js')
.then(mod => mod.default);
Enter fullscreen mode Exit fullscreen mode

Top comments (0)