Optional imports

These could also be called "graceful imports" but I think "optional imports" is a nice parallel to "optional chaining".

Currently, when even a single import fails to load, the entire module containing that import fails to load, which has a domino effect on all modules importing that and so on. The result is ES apps that can be pretty fragile, especially when loading modules over HTTP: Every time one imports from a URL they risk their entire app breaking if some third party server is down or some file gets moved.
This is less of an issue for bare specifiers, but it can still happen.

Sure, one can already use dynamic import() for this:

let foo = null;

try {
  foo = await import("https://path.to/my/nonexistent-module.js");
} catch (e) {}

// foo is now null

However, this is so heavyweight that it reflects fundamentally different expectations. It's more "I expect this to fail and plan ahead" not "this is one of my dependencies and don't expect it to fail, but this is the Web and :poop: happens". Also, it's more awkward to type, and you lose the benefits of static analysis.

What about a more resilient import, where if the request fails for whatever reason, no error is thrown and all imports simply become null (or undefined?).

It could look like this:

import? foo from "https://path.to/my/nonexistent-module.js";

// foo is now null

There is precedent in other languages:

I can see lots of use cases where i'd also want a fallback in case that did fail - can you see that working in somehow?

Good point!

In my Weak imports proposal I proposed the idea of "specifier stacks" (akin to font stacks in CSS), these could be useful here too; if you agree I could post a separate proposal.

Would you be able to expand on this? While the import is named "dynamic" it is being called with a string literal in a non-conditional way. So it is technically just as "static".

When getting a fallback module, it could be nice to have the fallback be stored in a separate variable.

So, instead of import x from 'firstTryMe,thenTryMe';, it might be nice to have something akin to

import? x from 'firstTryMe'
else import? y from 'thenTryMe';

i.e. first you import from the first location. If that fails, import, but into a different variable, from the second location.

Maybe we could even drop the question marks, and just use the else entirely. else import means "if the previous import fails, try this one instead", and "else skip" means "if the previous import fails, just don't worry about it".


// Optional import
import x from 'optionalImport' else skip;

// Optional import with one fallback
import x from 'firstTryMe'
else import y from 'thenTryMe'
else skip;

// Optional import with one fallback. One or the other must succeed.
import x from 'firstTryMe'
else import y from 'thenTryMe';