Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

hot-esm

Package Overview
Dependencies
Maintainers
1
Versions
17
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

hot-esm - npm Package Compare versions

Comparing version 1.4.1 to 1.5.0-alpha.1

hot.hmr.test.js

57

index.js

@@ -30,2 +30,4 @@ import process from 'process'

let messagePort
const watcher = chokidar

@@ -42,2 +44,4 @@ .watch([])

log('Invalidating %s', Array.from(invalidatedFiles).join(', '))
messagePort.postMessage(realFilePath)
})

@@ -81,3 +85,3 @@ .on('unlink', (relativeFilePath) => {

export function load(url, context, defaultLoad) {
export async function load(url, context, defaultLoad) {
const parsedUrl = new URL(url)

@@ -89,3 +93,52 @@

return defaultLoad(url, context, defaultLoad)
const result = await defaultLoad(url, context, defaultLoad)
if (result.format === 'module') {
const source = result.source.toString()
const newSource = source.replace(
/if\s*\(\s*import\.meta\.hot\s*\)/,
'if (globalThis.hotEsm.extendImportMeta(import.meta, () => import(import.meta.url)), import.meta.hot.accept)',
)
return {
...result,
source: newSource,
}
}
return result
}
export function globalPreload({port}) {
messagePort = port
return `
globalThis.hotEsm = {
extendImportMeta(importMeta, importModule) {
const filePath = new URL(importMeta.url).pathname
const handlers = this.handlers
importMeta.hot = {
accept(callback) {
if (!handlers[filePath]) {
handlers[filePath] = async () => {
callback(await importModule())
}
}
}
}
},
handlers: {}
}
port.onmessage = (event) => {
const path = event.data
const handlers = globalThis.hotEsm.handlers
if (handlers[path]) {
handlers[path]()
}
}
`
}

5

package.json
{
"name": "hot-esm",
"version": "1.4.1",
"version": "1.5.0-alpha.1",
"description": "ESM hot-reloading for Node.js",

@@ -49,4 +49,5 @@ "keywords": [

"verbose": true,
"timeout": "5m"
"timeout": "5m",
"concurrency": 1
}
}

@@ -16,2 +16,75 @@ # hot-esm

## In Development: Hot Module Replacement
```js
export let text = 'Hello World!'
if (import.meta.hot) {
import.meta.hot.accept((module) => {
text = module.text
})
}
```
The interface that hot-esm currently provides is pretty clunky:
- It requires manual re-importing of modules without knowledge about updates
- It requires manual cleanup of side-effects when a new version of a module is
imported
To address these problems, I'm experimenting with implementing an HMR interface
similar to those provided by bundlers. Namely, I'm taking inspiration from the
[HMR API](https://vitejs.dev/guide/api-hmr.html) provided by Vite.
### Implementation
Using the
[`globalPreload()`](https://nodejs.org/docs/latest-v17.x/api/esm.html#globalpreload)
loader hook, hot-esm creates a [global registry](/index.js#L128) to track
modules that can accept updates.
For each module that subscribes using `import.meta.hot.accept()`, hot-esm
tracks:
- The callback provided as argument
- The absolute path to the module, derived from `import.meta.url`
- A function defined within the module to re-`import()` that module. This is
necessary because the `globalPreload()` hook does not allow dynamic
`import()`.
In order to define `import.meta.hot.accept()` and allow it to collect the above
information, the [module source code is modified](/index.js#L95) via the
[`load()`](https://nodejs.org/docs/latest-v17.x/api/esm.html#loadurl-context-defaultload)
loader hook. In order to minimize the disruption to stack trace line numbers,
the first instance of
```js
if (import.meta.hot) {
// Code
}
```
is, without changing the line count, replaced with:
```js
if (globalThis.hotEsm.extendImportMeta(import.meta, () => import(import.meta.url)), import.meta.hot) {
// Code
}
```
[`globalThis.hotEsm.extendImportMeta()`](/index.js#L114-L127) then ensures that
the needed information is added to the global registry when
`import.meta.hot.accept()` is called.
When it comes to delivering updated modules to subscribers, when a module is updated,
[its file path is sent](/index.js#L44) [to the registry](/index.js#L131-L138).
From there, the callback passed to `import.meta.hot.accept()` is called with the
updated module.
### Ongoing Work
I plan to try this interface against a few usecases before:
- Looking for a more robust way to modify the module source code
- Potentially expanding the interface of `import.meta.hot.accept()` to allow
modules to accept updates for direct dependencies.
- Potentially implementing other methods from Vite's HMR API.
## Usage

@@ -18,0 +91,0 @@ hot-esm provides a

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc