esm-reload

1.0.1 • Public • Published

ES module reload

This module lets you reload an ES module and its dependencies in Node.js. It does so by adding a module resolution hook.

Background

Per spec, ES modules are cached the first time they are imported, and subsequent import statements return the same object.

import {assert} from 'node:assert/strict'

const m1 = await import('./my-module.js')
const m2 = await import('./my-module.js')


assert.equal(m1, m2) // passes

This is desirable in most scenarios, but you can sometimes want to instantiate a module several times. For example, you may want to test a module that branches at load time depending on its environment. To some extent, that can be achieved by tacking a query string at the end of the import specifier:

import {assert} from 'node:assert/strict'

const m1 = await import('./my-module.js?dev')
process.env.NODE_ENV='production'
const m2 = await import('./my-module.js?prod')

assert.notEqual(mDev, mProd)  // passes

However, this doesn't work transitively. ./my-module.js?prod will import the dependencies that were cached when ./my-module.js?dev was loaded.

If you want to load a module multpile times from scratch with its dependencies you can use this module.

Usage:

The resolver hook gives a special meaning to ?instance=... and ?reload query strings.

If you want to retrieve a specific instance, use the former with an identifier of your choice.

import "esm-reload" // this registers the hook

const mDev = await import("./myModule.js?instance=dev")
process.env.NODE_ENV='production'
const mProd = await import("./myModule.js?instance=prod")
const mDev2 = await import("./myModule.js?instance=dev")

assert.equal(mDev, mDev2)              // passes
assert.notEqual(mDev, mProd)           // passes

If you just want a fresh instance you can use ?reload

const mReloaded = await import("./myModule.js?reload")
assert.notEqual(mDev, mReloaded)       // passes
assert.notEqual(mProd, mReloaded)      // passes

// ?reload is "magic"
const mReloaded2 = await import("./myModule.js?reload")
assert.notEqual(mReloaded, mReloaded2) // passes

In both cases, instances come with a fresh set of dependencies (except for the builtin node:xxx modules that don't support query strings at all).

With dependencies

Suppose these files:

// foo.js
export {x} from "./bar.js"

// bar.js
export const x = {}

We can then do

import "esm-reload"

const foo1 = await import("./foo.js?instance=1")
const bar1 = await import("./bar.js?instance=1")

const foo2 = await import("./foo.js?instance=2")
const bar2 = await import("./bar.js?instance=2")

assert.equal(foo1.x, bar1.x)
assert.equal(foo2.x, bar1.x)

assert.notEqual(bar1.x, bar2.x)

Credit:

The hook was originally written by Marcel Laverdet(@laverdet) then tweaked, tested and documented by yours truly.

License

ISC

Readme

Keywords

none

Package Sidebar

Install

npm i esm-reload

Weekly Downloads

99

Version

1.0.1

License

ISC

Unpacked Size

7.92 kB

Total Files

11

Last publish

Collaborators

  • pygy