Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/patreeceeo/hot_mod
HMR for ES Modules
https://github.com/patreeceeo/hot_mod
deno developer-tools esm esmodules hmr hot-module-replacement javascript rapid-development rapid-prototyping typescript
Last synced: about 2 months ago
JSON representation
HMR for ES Modules
- Host: GitHub
- URL: https://github.com/patreeceeo/hot_mod
- Owner: patreeceeo
- Created: 2023-03-12T02:42:43.000Z (almost 2 years ago)
- Default Branch: main
- Last Pushed: 2023-03-19T23:22:12.000Z (almost 2 years ago)
- Last Synced: 2024-12-20T13:02:07.907Z (about 2 months ago)
- Topics: deno, developer-tools, esm, esmodules, hmr, hot-module-replacement, javascript, rapid-development, rapid-prototyping, typescript
- Language: TypeScript
- Homepage:
- Size: 48.8 KB
- Stars: 7
- Watchers: 1
- Forks: 0
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# hot_mod
https://user-images.githubusercontent.com/578371/224897357-0119a373-5f50-4b46-b3de-5f158d7c8591.mp4
An ESM-HMR client and server, allowing for hot-reloading client-side (and maybe server-side? untested) ESModules, as described by https://github.com/FredKSchott/esm-hmr.
## Usage with Deno
These modules are published at https://deno.land/x/hot_mod
In each client-side module:
```javascript
import { useClient } from "hot_mod/dist/client/mod.js";useClient(import.meta);
// The following is just my best idea so far of how to write hot-reloadable modules :)
export const hotExports = {
// Add more identifiers here
drawPlayers // example
}
if (import.meta.hot) {
import.meta.hot.accept([], ({ module }) => {
for(const key of Object.keys(hotExports) as Array) {
hotExports[key] = module.hotExports[key]
}
});
}
// In app code, write hotExports.drawPlayers() instead of drawPlayers()
````import.meta.hot` will available in development (well, as long as serving from localhost. I mean to support some kind of configuration or environment variables for deciding when HMR should be enabled.)
Then, in the dev server, import the HMR engine and wire it up:
```typescript
import { serve } from "http";
import { relative } from "path";
import { debounce } from "async";
import { EsmHmrEngine } from "hot_mod/src/server/mod.ts";interface ModuleEventHandler {
(paths: IterableIterator): void;
}let listenerCount = 0;
const modifiedModuleUrls = new Set();
async function addModuleEventHandler(
handler: ModuleEventHandler,
absPaths: Array,
) {
const watcher = Deno.watchFs(absPaths, { recursive: true });const debouncedListener = debounce(() => {
const copy = new Set(modifiedModuleUrls);
handler(copy.values());
modifiedModuleUrls.clear();
}, 200);listenerCount++;
console.log(
`Module event handler #${listenerCount} for ${absPaths.join(", ")}`,
);for await (const event of watcher) {
if (event.kind === "modify") {
for (const path of event.paths) {
// These strings must correspond to those created on the client:
// The pathname to the full URL to the module subject to hot reloading,
// e.g. new URL(import.meta.url).pathname;
const moduleId = "/" + relative(Deno.cwd(), path);
modifiedModuleUrls.add(moduleId);
}
}
if (modifiedModuleUrls.size > 0) {
debouncedListener();
}
}
}const engine = new EsmHmrEngine((emitModuleModifiedEvent) => {
addModuleEventHandler((paths) => {
for (const path of paths) {
emitModuleModifiedEvent(path);
}
}, [Deno.cwd() + "/public"]);
});
serve((request) => {
const { socket, response } = Deno.upgradeWebSocket(request);
engine.addClient(socket);
return response;
}, { port: 12321 });
```And run it with:
```sh
deno run --allow-net --allow-read --watch "path/to/dev_server.ts"
```## API
See https://github.com/FredKSchott/esm-hmr
## Contributing
GitHub issues and pull requests welcome!