Maybe you don't know that Javascript can conditionally import

For a side project, I was creating a personal blog starter. Without going into details, it's a Next.js project that use SSG to create every pages at build time. You can decide "how and where" you write and store your articles. The choice is between these datasources :

  • Flat File (version-controlled markdown file in a sub dir of the repo)
  • Notion Database

Both datasource are coded as an object with a type signature shared by every datasource, so that the view layer is decoupled from the real datasource implementation.

Both "flat-file" and "notion" strategies have code implementaion, this implementaion is located in different location inside the repo folder structure. In case you use "notion" strategies, it is not necessary that the code imports the "flat file" code becasue it will be never used, and viceversa.

To solve this problem, at the beginning you must open a file and comment/uncomment a line of code, like this:

// 1. when notion is the choice
// import { flatFileDatasource as datasource } from './strategies/flat-file';
import { notionDatasource as datasource } from './strategies/notion';

export datasource;

... or ...

// 2. when flat file is the choice
import { flatFileDatasource as datasource } from './strategies/flat-file';
// import { notionDatasource as datasource } from './strategies/notion';

export datasource;

It works. But is not comfortable.

What if I can conditionally import a module or an other ?!??
Well, Javascript covers this case.

Dynamic Import

This syntax

import {something} from './someplace';

is known as static import.

But javascript has also a dynamic and async import feature

import('./someplace').then(module=>console.log(module));

that returns a promise with the imported module object.

Of course when you export a promise, who imports it must await before utilizing its resolved value, so you must adjust some other code as well.

Here is a generic example

// file: ./fancy-lib.ts

export let getLib: () => Promise<FancyLibType>;

if (today === 'monday') {
  getLib = import('./monday').then(module => module);
}
else if (today === 'friday') {{
   getLib = import('./friday').then(module => module);
}
else {
  throw new Error(`No libraries for ${today} day`);
} 


// file: ./consumer-of-fancy-lib.ts
import { getLib } from './fancy-lib';

const manipulation = async () => {
  const myLib = await getLib();
  // ... rest of the code
}

Conclusion

Dynamic import lets you import modules based on conditions that are computed at runtime, opening the possibility to avoid loading unnecessary code.
Due to the nature of the feature, that utilizes Promise, some other code needs to be updated as async as well.


And you? Have you ever used dynamic import? Do you have a static alternative for conditional import? Feel free to share.

Resources

MDN - import - static
MDN - import() - dynamic