import-optional
v2.0.0
Published
A tiny library to help deal with optional dependencies without the hassle of needing to `.catch` for dynamic imports
Maintainers
Readme
import-optional
A tiny library to help deal with optional dependencies without the hassle of needing to
.catchfor dynamic imports
Usage
Array
// some-config.js
import { optional } from 'import-optional';
// import your optional dependencies
const optionalPlugins = await Promise.all([
optional(import('my-dependency-1'), m => m.default),
optional(import('my-dependency-2'), m => m.default),
// Importing is still done manually for type safety
]);
// then use them as if you did `import * as myDependency from 'my-dependency'`:
export default {
plugins: [
plugin1,
plugin2,
// ...
...optionalPlugins
]
}Object
// some-config.js
import { importOptional } from 'import-optional';
// import your optional dependencies
const optional = await importOptional({
myDependency: import('my-dependency')
// Importing is still done manually for type safety
});
// then use them as if you did `import * as myDependency from 'my-dependency'`:
optional.myDependency?.default('some default exported function');Object with fallbacks
It's possible to define fallbacks that trigger per-dependency,
just like with regular .catch:
// some-config.js
import { importOptional } from 'import-optional';
const optional = await importOptional({
myDependency: import('my-dependency')
}, {
myDependency: (error) => {
console.error('Oh no... Anyway');
return import('my-alt-dependency');
}
});
optional.myDependency?.default('some default exported function');Reasoning
This is a tiny library, but it simplifies the mental gymnastics needed to work with multiple optional npm dependencies or just many imports that may fail for some reason.
It is rather redundant and opinionated, but makes the code look nice.
My personal reason for this came from needing to use optional dependencies in vite config plugins:
import { defineConfig } from 'vite';
// This breaks the config if the dependency is missing
import * as somePlugin from 'some-optional-dep';
// - Very tiring to do for every dependency
// - Not very idiomatic
// - Looks chaotic in bulk: each import spans over multiple lines
const somePlugin = await import('some-optional-dep')
.catch(() => null);
export default defineConfig({
// Imagine a couple hundred lines of configuration here...
plugins: [
// Not clear that this is optional at all
somePlugin.default()
]
})Now, with optional:
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [
// Clear that it's an optional dependency
await optional(import('some-optional-dep'), m => m.default())
]
})