# Optional imports

**URL:** <https://es.discourse.group/t/optional-imports/1628>\
**Category:** 💡 Ideas\
**Tags:** proposal\
**Created:** [March 3, 2023, 8:53pm UTC](https://es.discourse.group/t/optional-imports/1628 "2023-03-03T20:53:29Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![LeaVerou](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/leaverou/32/1660_2.png) [@LeaVerou](https://es.discourse.group/u/LeaVerou)\
**Post date:** [March 3, 2023, 8:53pm UTC](https://es.discourse.group/t/optional-imports/1628/1 "2023-03-03T20:53:29Z")

</div>

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:

```js
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 💩 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:

```js

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

// foo is now null

```

There is precedent in other languages:

- PHP's [`include()`](https://www.php.net/manual/en/function.include.php) vs [`require()`](https://www.php.net/manual/en/function.require.php)
- [Lua](https://twitter.com/RogersKonnor/status/1631437519081336833)
- [Perl?](https://twitter.com/garrett_wollman/status/1630795013029343233)
- (I'm sure there are more)

---

<div class="post-metadata">

**Author:** ![ljharb](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/ljharb/32/8_2.png) [@ljharb](https://es.discourse.group/u/ljharb)\
**Post date:** [March 3, 2023, 9:07pm UTC](https://es.discourse.group/t/optional-imports/1628/2 "2023-03-03T21:07:52Z")

</div>

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?

---

<div class="post-metadata">

**Author:** ![LeaVerou](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/leaverou/32/1660_2.png) [@LeaVerou](https://es.discourse.group/u/LeaVerou)\
**Post date:** [March 3, 2023, 9:19pm UTC](https://es.discourse.group/t/optional-imports/1628/3 "2023-03-03T21:19:40Z")

</div>

Good point!

In my [Weak imports](https://es.discourse.group/t/weak-imports/1629/1) 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.

---

<div class="post-metadata">

**Author:** ![aclaymore](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/aclaymore/32/501_2.png) [@aclaymore](https://es.discourse.group/u/aclaymore)\
**Post date:** [March 4, 2023, 8:02am UTC](https://es.discourse.group/t/optional-imports/1628/4 "2023-03-04T08:02:24Z")

</div>

> [@LeaVerou](#):
>
> and you lose the benefits of static analysis.

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".

---

<div class="post-metadata">

**Author:** ![theScottyJam](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/thescottyjam/32/616_2.png) [@theScottyJam](https://es.discourse.group/u/theScottyJam)\
**Post date:** [March 4, 2023, 8:09am UTC](https://es.discourse.group/t/optional-imports/1628/5 "2023-03-04T08:09:08Z")

</div>

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

```javascript
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".

So

```javascript
// 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';

```

---

<div class="post-metadata">

**Author:** ![claudiameadows](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/claudiameadows/32/126_2.png) [@claudiameadows](https://es.discourse.group/u/claudiameadows)\
**Post date:** [October 10, 2023, 11:41pm UTC](https://es.discourse.group/t/optional-imports/1628/6 "2023-10-10T23:41:25Z")

</div>

What about this syntax?

```js
// Required
import x from "foo" ?? "bar" ?? ...;

// Optional
import? x from "foo" ?? "bar" ?? ...;

```

And import fallbacks would be resolved at link time, if either the module itself _or_ the requested exports are missing. This would allow for use at build time, not just runtime, and make fallbacks more statically analyzable (and manageable) for bundlers.

Wrapper modules could be used for more complicated fallbacks, so no alternatives are provided for that.

Leaving dynamic import out, since that's a whole can of worms itself that has better ways to handle it.

---

<div class="post-metadata">

**Author:** ![jithujoshyjy](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/jithujoshyjy/32/399_2.png) [@jithujoshyjy](https://es.discourse.group/u/jithujoshyjy)\
**Post date:** [November 3, 2023, 1:20pm UTC](https://es.discourse.group/t/optional-imports/1628/7 "2023-11-03T13:20:04Z")

</div>

Why not utilise the existing import syntax?

```javascript
import xyz from "./scriptX.js" assert { optional: true }
import xyz from "./scriptY.js" assert { optional: true }
import xyz from "./scriptZ.js" assert { optional: true }

// 'xyz' will be whichever import first resolve successfully or undefined if non of them succeed.

```

Or maybe

```javascript
import xyz from ["./scriptX.js", "./scriptY.js", "./scriptZ.js", {}]

// the last member of the array can be an object literal or undefined or the throw keyword, if not specified undefined by default.
// If undefined then all the imported items will be undefined.

```
