ES proposal: import.meta – module metadata

[2017-11-05] dev, javascript, esnext, es proposal, jsmodules
(Ad, please don’t block)

The proposal “import.meta” by Domenic Denicola is currently at stage 3. This blog post explains how it works.

Module metadata  

When it comes to working with a module, you are normally interested in what’s inside it. But occasionally, you need information about the module – its metadata. One example of module metadata for Node.js modules is the global variable __dirname which contains the path of the directory in which the current module is stored.

The proposal introduces the pseudo-property import.meta which holds an object with metadata for the current module. Let’s look at uses cases for module metadata.

Use case: Path to module  

In Node.js, you can store data supporting a CommonJS module next to that module and get to it as follows:

const fs = require('fs');
const path = require('path');
const TEMPLATE_PATH = path.resolve(__dirname, 'template.txt'); // (A)
const TEMPLATE_TEXT = fs.readFileSync(
    TEMPLATE_PATH, { encoding: 'utf8' });

The key piece is the module metadata __dirname in line A.

This is how you can achieve something similar in a cross-platform way (on Node.js, you need a polyfill for the fetch() API).

async function main() {
    const TEMPLATE_URL = new URL('../template.txt', import.meta.url); // (A)
    const response = await fetch(TEMPLATE_URL);
    const TEMPLATE_TEXT = await response.text();
    ···
}
main();

Note the metaproperty import.meta.url (line A), which contains the URL of the current module.

Use case: Is the current module the execution entry point?  

On Node.js, a CommonJS module can play two roles:

  • If the module is imported, it acts as a library.
  • If the module is executed, it acts as an executable. For example, it could provide supporting tool functionality or run a demo.

You can handle the two roles as follows.

// Library stuff goes here

if (require.main === module) {
    // Executable stuff goes here
    // (uses library stuff)
}

At the moment, no concrete metaproperty has been proposed, but import.meta.entryUrl would work:

// Library stuff goes here

if (import.meta.entryUrl === import.meta.url) {
    // Executable stuff goes here
    // (uses library stuff)
}

Use case: Parameterizing modules via HTML attributes  

Browsers will have the metaproperty import.meta.scriptElement that gives modules access to the script element that loaded them.

// my-module.mjs
console.log(import.meta.scriptElement.dataset.foo); // "abc"

HTML:

<script type="module" src="my-module.mjs" data-foo="abc"></script>

Non-module scripts get this information via document.currentScript.

The object in import.meta  

As of now:

  • The object in import.meta will be extensible (you are able to add properties).
  • All properties will be writable, configurable and enumerable (you are able to change or delete them).

The rationale for keeping everything mutable is to enable polyfilling of upcoming features. Note that, by default, module metadata can only be accessed by the module. That is, unless the module passes the metadata object elsewhere, it is local.

What platforms support import.meta?  

Further reading