Parameters for an ES6-import
I recently asked myself if it’s actually possible to use ES6-module system import-statements in Javascript in not only the common way (importing just a local module via relative path or name of the package), but with parameters.
My use case would be something like this: provide some sort of parameters during the import so the imported module can itself treat those parameters as flag for conditional imports or special code handling.
As it turns out, that’s totally possible!
ES6 imports are just URLs
Before we take a look at the code, it’s important to remember that import-statements in Node.js are practically just URLs. Node.js by default uses an algorithm to determine how the URLs actually look like when fully resolved. For instance if you only provide the relative path as the import specifier, Node.js still resolves the string to an absolute URL for the import behind the scenes.
Using URL query parameters for an import
And because the import resolves to a URL, we can use the common URL search parameters as well as URL-fragments in our imports.
First, make sure that ES6-modules are supported to test this feature. This requires a small change to our package.json, where the "type"-field has to be set to "module". Note that you have to use Node.js version 12 or higher.
{
"name": "es6-import-params",
"version": "1.0.0",
"main": "index.js",
"type": "module",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"description": ""
}
Next define two minimal modules for a simple demo.
//
// index.js
//
import {greet} from "./lib.js?name=Tom";
// This will print "Hello Tom".
greet();
//
// lib.js
//
// We're using Node's native 'URL'-module
// to transform the provided string into
// a usable representation.
//
// Note that 'import' here isn't part of
// an acutal import, but rather resolved
// to a global variable.
const url = new URL(import.meta.url);
// A simple greeter for demo purposes.
// We just access the map 'searchParams'
// from our usable 'url'-object and use
// a fallback if no params are provided.
export function greet() {
console.log(`Hello ${url.searchParams.get("name") || "World"}`);
}
Multiple imports with different parameters
As written in the Node.js documentation, each import gets cached at runtime for faster subsequent imports in other modules. Therefore it’s important to know that imports from the same module but with different parameters get each cached individually. Of course imports with a matching signature then still get read from the cache.
//
// index.js
//
// A small adaptation for the index.js
// file, this time importing the same
// module twice w/ different params. Each
// module gets cached twice, too.
import * as tomLib from "./lib.js?name=Tom";
import * as lukeLib from "./lib.js?name=Luke";
// 'Hello Tom'.
tomLib.greet();
// 'Hello Luke'.
lukeLib.greet();
// Still 'Hello Tom', as it's
// its own module.
tomLib.greet();
Use cases
The examples in this article are intentionally very short, but you get the idea. Depending on your requirements, using query parameters with imports can be quite an elegant option for setting “global” variables for each module. This eliminates the need to provider getters and setters to achieve the same goal.