Add fine-grained HMR support (#2649)
* feat: add fine-grained HMR support * chore: lint * chore: lint * fix: handle hmr with custom event handler * refactor: cleanup hmr script
This commit is contained in:
parent
0cffbfff39
commit
5091d788f6
7 changed files with 37 additions and 36 deletions
5
.changeset/tasty-tigers-flow.md
Normal file
5
.changeset/tasty-tigers-flow.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
'astro': patch
|
||||
---
|
||||
|
||||
Add fine-grained HMR support for Astro files
|
|
@ -85,8 +85,8 @@
|
|||
"htmlparser2": "^7.1.2",
|
||||
"kleur": "^4.1.4",
|
||||
"magic-string": "^0.25.7",
|
||||
"micromorph": "^0.0.2",
|
||||
"mime": "^3.0.0",
|
||||
"morphdom": "^2.6.1",
|
||||
"parse5": "^6.0.1",
|
||||
"path-to-regexp": "^6.2.0",
|
||||
"postcss": "^8.3.8",
|
||||
|
|
|
@ -1,38 +1,20 @@
|
|||
if (import.meta.hot) {
|
||||
const parser = new DOMParser();
|
||||
import.meta.hot.on('astro:reload', async ({ html }: { html: string }) => {
|
||||
const { default: morphdom } = await import('morphdom');
|
||||
import.meta.hot.on('astro:update', async ({ file }) => {
|
||||
const { default: diff } = await import('micromorph');
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(`[vite] hot updated: ${file}`);
|
||||
const html = await fetch(`${window.location}`).then(res => res.text());
|
||||
const doc = parser.parseFromString(html, 'text/html');
|
||||
|
||||
morphdom(document.head, doc.head, {
|
||||
onBeforeElUpdated(fromEl, toEl) {
|
||||
// Do not update identical tags
|
||||
if (fromEl.isEqualNode(toEl)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Do not update <link> or <script> tags
|
||||
// to avoid re-fetching their contents
|
||||
if (fromEl.tagName === toEl.tagName && (toEl.tagName === 'LINK' || toEl.tagName === 'SCRIPT')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
});
|
||||
|
||||
morphdom(document.body, doc.body, {
|
||||
onBeforeElUpdated(fromEl, toEl) {
|
||||
if (fromEl.localName === 'astro-root') {
|
||||
return fromEl.getAttribute('uid') !== toEl.getAttribute('uid');
|
||||
}
|
||||
|
||||
if (fromEl.isEqualNode(toEl)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
});
|
||||
// Match incoming islands to current state
|
||||
for (const root of doc.querySelectorAll('astro-root')) {
|
||||
const uid = root.getAttribute('uid');
|
||||
const current = document.querySelector(`astro-root[uid="${uid}"]`);
|
||||
if (current) {
|
||||
root.innerHTML = current?.innerHTML;
|
||||
}
|
||||
}
|
||||
diff(document, doc);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -112,7 +112,6 @@ async function handleRequest(
|
|||
routeCache: routeCache,
|
||||
viteServer: viteServer,
|
||||
});
|
||||
info(logging, 'astro', msg.req({ url: pathname, statusCode, reqTime: performance.now() - reqStart }));
|
||||
writeHtmlResponse(res, statusCode, html);
|
||||
} catch (_err: any) {
|
||||
info(logging, 'astro', msg.req({ url: pathname, statusCode: 500 }));
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
import type { AstroConfig } from '../@types/astro';
|
||||
import type { LogOptions } from '../core/logger.js';
|
||||
import type { ViteDevServer, ModuleNode, HmrContext } from 'vite';
|
||||
import type { PluginContext as RollupPluginContext, ResolvedId } from 'rollup';
|
||||
import { invalidateCompilation, isCached } from './compile.js';
|
||||
import { logger } from '../core/logger.js'
|
||||
import { green } from 'kleur/colors';
|
||||
|
||||
interface TrackCSSDependenciesOptions {
|
||||
viteDevServer: ViteDevServer | null;
|
||||
|
@ -43,7 +46,7 @@ export async function trackCSSDependencies(this: RollupPluginContext, opts: Trac
|
|||
}
|
||||
}
|
||||
|
||||
export function handleHotUpdate(ctx: HmrContext, config: AstroConfig) {
|
||||
export function handleHotUpdate(ctx: HmrContext, config: AstroConfig, logging: LogOptions) {
|
||||
// Invalidate the compilation cache so it recompiles
|
||||
invalidateCompilation(config, ctx.file);
|
||||
|
||||
|
@ -70,5 +73,12 @@ export function handleHotUpdate(ctx: HmrContext, config: AstroConfig) {
|
|||
invalidateCompilation(config, file);
|
||||
}
|
||||
|
||||
if (ctx.file.endsWith('.astro')) {
|
||||
const file = ctx.file.replace(config.projectRoot.pathname, '/');
|
||||
logger.info('astro', green('hmr'), `${file}`)
|
||||
ctx.server.ws.send({ type: "custom", event: "astro:update", data: { file } })
|
||||
return []
|
||||
}
|
||||
|
||||
return Array.from(filtered);
|
||||
}
|
||||
|
|
|
@ -199,7 +199,7 @@ export default function astro({ config, logging }: AstroPluginOptions): vite.Plu
|
|||
}
|
||||
},
|
||||
async handleHotUpdate(context) {
|
||||
return handleHotUpdate(context, config);
|
||||
return handleHotUpdate(context, config, logging);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -5867,6 +5867,11 @@ micromatch@^4.0.2, micromatch@^4.0.4:
|
|||
braces "^3.0.1"
|
||||
picomatch "^2.2.3"
|
||||
|
||||
micromorph@^0.0.2:
|
||||
version "0.0.2"
|
||||
resolved "https://registry.yarnpkg.com/micromorph/-/micromorph-0.0.2.tgz#5cfbaea66ae5fb8629c8041897e88d9e827afc2f"
|
||||
integrity sha512-hfy/OA8rtwI/vPRm4L6a3/u6uDvqsPmTok7pPmtfv2a7YfaTVfxd9HX2Kdn/SZ8rGMKkKVJ9A0WcBnzs0bjLXw==
|
||||
|
||||
mime@1.6.0:
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
|
||||
|
|
Loading…
Reference in a new issue