v156 · feature detection · migration

Feature detection & fallback

New syntax cannot be feature-detected with typeof or in — the file will not parse at all on an old engine, taking the whole script down with it. This page shows the correct pattern: probe the grammar in isolation, then branch to either the real feature or a labelled, honest fallback.

The probe

Checking…

// You cannot write `if (supportsImportDefer)` inline: a file containing
// `import defer` throws a SyntaxError before any of it runs. So keep the
// syntax in a SEPARATE module and import it dynamically, catching the parse:
async function supportsImportDefer() {
  try {
    await import("data:text/javascript,import defer * as n from" +
                 " \"data:text/javascript,export const ok=true\";export{}");
    return true;                 // grammar parsed
  } catch (e) {
    if (e instanceof SyntaxError) return false;   // not understood here
    return true;                 // parsed, but the probe module failed to load
  }
}

Branch to the right path

Detecting…

The probe picks the path; press the button to load the module accordingly.

Migration shape

Because the fallback is dynamic import(), the deferred code path should be written so both branches converge on the same asynchronous-friendly call site during migration. Once import defer is your baseline, the synchronous form removes the await at every caller:

let inspector;
if (await supportsImportDefer()) {
  inspector = (await import("./defer-entry.js")).ns;   // synchronous first-use later
} else {
  inspector = null;                                    // load lazily via import() on use
}

async function open(selection) {
  const mod = inspector ?? await import("./inspector.js");
  mod.open(selection);
}

see also