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",
|
"htmlparser2": "^7.1.2",
|
||||||
"kleur": "^4.1.4",
|
"kleur": "^4.1.4",
|
||||||
"magic-string": "^0.25.7",
|
"magic-string": "^0.25.7",
|
||||||
|
"micromorph": "^0.0.2",
|
||||||
"mime": "^3.0.0",
|
"mime": "^3.0.0",
|
||||||
"morphdom": "^2.6.1",
|
|
||||||
"parse5": "^6.0.1",
|
"parse5": "^6.0.1",
|
||||||
"path-to-regexp": "^6.2.0",
|
"path-to-regexp": "^6.2.0",
|
||||||
"postcss": "^8.3.8",
|
"postcss": "^8.3.8",
|
||||||
|
|
|
@ -1,38 +1,20 @@
|
||||||
if (import.meta.hot) {
|
if (import.meta.hot) {
|
||||||
const parser = new DOMParser();
|
const parser = new DOMParser();
|
||||||
import.meta.hot.on('astro:reload', async ({ html }: { html: string }) => {
|
import.meta.hot.on('astro:update', async ({ file }) => {
|
||||||
const { default: morphdom } = await import('morphdom');
|
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');
|
const doc = parser.parseFromString(html, 'text/html');
|
||||||
|
|
||||||
morphdom(document.head, doc.head, {
|
// Match incoming islands to current state
|
||||||
onBeforeElUpdated(fromEl, toEl) {
|
for (const root of doc.querySelectorAll('astro-root')) {
|
||||||
// Do not update identical tags
|
const uid = root.getAttribute('uid');
|
||||||
if (fromEl.isEqualNode(toEl)) {
|
const current = document.querySelector(`astro-root[uid="${uid}"]`);
|
||||||
return false;
|
if (current) {
|
||||||
}
|
root.innerHTML = current?.innerHTML;
|
||||||
|
}
|
||||||
// Do not update <link> or <script> tags
|
}
|
||||||
// to avoid re-fetching their contents
|
diff(document, doc);
|
||||||
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;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,7 +112,6 @@ async function handleRequest(
|
||||||
routeCache: routeCache,
|
routeCache: routeCache,
|
||||||
viteServer: viteServer,
|
viteServer: viteServer,
|
||||||
});
|
});
|
||||||
info(logging, 'astro', msg.req({ url: pathname, statusCode, reqTime: performance.now() - reqStart }));
|
|
||||||
writeHtmlResponse(res, statusCode, html);
|
writeHtmlResponse(res, statusCode, html);
|
||||||
} catch (_err: any) {
|
} catch (_err: any) {
|
||||||
info(logging, 'astro', msg.req({ url: pathname, statusCode: 500 }));
|
info(logging, 'astro', msg.req({ url: pathname, statusCode: 500 }));
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
import type { AstroConfig } from '../@types/astro';
|
import type { AstroConfig } from '../@types/astro';
|
||||||
|
import type { LogOptions } from '../core/logger.js';
|
||||||
import type { ViteDevServer, ModuleNode, HmrContext } from 'vite';
|
import type { ViteDevServer, ModuleNode, HmrContext } from 'vite';
|
||||||
import type { PluginContext as RollupPluginContext, ResolvedId } from 'rollup';
|
import type { PluginContext as RollupPluginContext, ResolvedId } from 'rollup';
|
||||||
import { invalidateCompilation, isCached } from './compile.js';
|
import { invalidateCompilation, isCached } from './compile.js';
|
||||||
|
import { logger } from '../core/logger.js'
|
||||||
|
import { green } from 'kleur/colors';
|
||||||
|
|
||||||
interface TrackCSSDependenciesOptions {
|
interface TrackCSSDependenciesOptions {
|
||||||
viteDevServer: ViteDevServer | null;
|
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
|
// Invalidate the compilation cache so it recompiles
|
||||||
invalidateCompilation(config, ctx.file);
|
invalidateCompilation(config, ctx.file);
|
||||||
|
|
||||||
|
@ -70,5 +73,12 @@ export function handleHotUpdate(ctx: HmrContext, config: AstroConfig) {
|
||||||
invalidateCompilation(config, file);
|
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);
|
return Array.from(filtered);
|
||||||
}
|
}
|
||||||
|
|
|
@ -199,7 +199,7 @@ export default function astro({ config, logging }: AstroPluginOptions): vite.Plu
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async handleHotUpdate(context) {
|
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"
|
braces "^3.0.1"
|
||||||
picomatch "^2.2.3"
|
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:
|
mime@1.6.0:
|
||||||
version "1.6.0"
|
version "1.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
|
resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
|
||||||
|
|
Loading…
Reference in a new issue