From a9a32a48dbe652c9e9b008159d0409148220aefb Mon Sep 17 00:00:00 2001 From: Julien Ripouteau Date: Tue, 9 Apr 2024 02:20:56 +0200 Subject: [PATCH] feat: import.meta.hot.dump function --- packages/hot_hook/src/dependency_tree.ts | 16 ++++++++++++++++ packages/hot_hook/src/hot.ts | 23 +++++++++++++++++++---- packages/hot_hook/src/loader.ts | 20 +++++++++++++++++--- 3 files changed, 52 insertions(+), 7 deletions(-) diff --git a/packages/hot_hook/src/dependency_tree.ts b/packages/hot_hook/src/dependency_tree.ts index 895d0f2..79eabc9 100644 --- a/packages/hot_hook/src/dependency_tree.ts +++ b/packages/hot_hook/src/dependency_tree.ts @@ -1,3 +1,5 @@ +import { dirname, relative } from 'node:path' + /** * Represent a file node in the dependency tree. */ @@ -179,4 +181,18 @@ export default class DependencyTree { const result = checkPathToRoot(node) return result } + + dump() { + const rootDirname = dirname(this.#tree.path) + const isNodeModule = (path: string) => path.includes('node_modules') + + return Array.from(this.#pathMap.values()).map((node) => ({ + path: relative(rootDirname, node.path), + boundary: node.reloadable, + reloadable: isNodeModule(node.path) ? false : this.isReloadable(node.path), + version: node.version, + dependencies: Array.from(node.dependencies).map((n) => relative(rootDirname, n.path)), + dependents: Array.from(node.dependents).map((n) => relative(rootDirname, n.path)), + })) + } } diff --git a/packages/hot_hook/src/hot.ts b/packages/hot_hook/src/hot.ts index bcbaa32..b0b11b8 100644 --- a/packages/hot_hook/src/hot.ts +++ b/packages/hot_hook/src/hot.ts @@ -1,8 +1,11 @@ import { register } from 'node:module' +import { MessageChannel } from 'node:worker_threads' + import { InitOptions, InitializeHookOptions, MessageChannelMessage } from './types.js' class Hot { #options!: InitOptions + #messageChannel!: MessageChannel #declinePaths = new Set() #disposeCallbacks = new Map void>() @@ -49,20 +52,20 @@ class Hot { * between the hook and the application process since hooks * are running in a worker thread */ - const { port1, port2 } = new MessageChannel() + this.#messageChannel = new MessageChannel() register('hot-hook/loader', { parentURL: import.meta.url, - transferList: [port2], + transferList: [this.#messageChannel.port2], data: { - messagePort: port2, + messagePort: this.#messageChannel.port2, root: this.#options.root, ignore: this.#options.ignore, boundaries: this.#options.boundaries, } satisfies InitializeHookOptions, }) - port1.on('message', this.#onMessage.bind(this)) + this.#messageChannel.port1.on('message', this.#onMessage.bind(this)) } /** @@ -83,6 +86,18 @@ class Hot { decline(url: string) { this.#declinePaths.add(new URL(url).pathname) } + + /** + * Dump the current state hot hook + */ + async dump() { + this.#messageChannel.port1.postMessage({ type: 'hot-hook:dump' }) + const result = await new Promise((resolve) => + this.#messageChannel.port1.once('message', (message) => resolve(message)) + ) + + return result + } } // @ts-ignore diff --git a/packages/hot_hook/src/loader.ts b/packages/hot_hook/src/loader.ts index 5b321b0..3eae7a5 100644 --- a/packages/hot_hook/src/loader.ts +++ b/packages/hot_hook/src/loader.ts @@ -26,9 +26,18 @@ export class HotHookLoader { this.#pathIgnoredMatcher = new Matcher(this.#projectRoot, options.ignore) this.#hardcodedBoundaryMatcher = new Matcher(this.#projectRoot, options.boundaries) - this.#dependencyTree = new DependencyTree({ - root: options.root, - }) + this.#dependencyTree = new DependencyTree({ root: options.root }) + this.#messagePort?.on('message', (message) => this.#onMessage(message)) + } + + /** + * When a message is received from the main thread + */ + #onMessage(message: any) { + if (message.type !== 'hot-hook:dump') return + + const dump = this.#dependencyTree.dump() + this.#messagePort?.postMessage({ type: 'hot-hook:dump', dump }) } /** @@ -89,6 +98,11 @@ export class HotHookLoader { hot.decline(import.meta.url); }; + import.meta.hot.dump = async () => { + const { hot } = await import('hot-hook'); + return hot.dump(); + }; + import.meta.hot.boundary = { with: { hot: 'true' } }; `