-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improved HMR #3138
Improved HMR #3138
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
'astro': patch | ||
--- | ||
|
||
General HMR Improvements, including new HMR support for framework components that are only server-side rendered (do not have a `client:*` directive) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,8 @@ | ||
if (import.meta.hot) { | ||
// signal to Vite that we accept HMR | ||
import.meta.hot.accept((mod) => mod); | ||
import.meta.hot.accept(mod => mod); | ||
const parser = new DOMParser(); | ||
import.meta.hot.on('astro:update', async ({ file }) => { | ||
async function updatePage() { | ||
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'); | ||
|
||
|
@@ -17,6 +14,27 @@ if (import.meta.hot) { | |
root.innerHTML = current?.innerHTML; | ||
} | ||
} | ||
diff(document, doc); | ||
return diff(document, doc); | ||
} | ||
async function updateAll(files: any[]) { | ||
let hasAstroUpdate = false; | ||
for (const file of files) { | ||
if (file.acceptedPath.endsWith('.astro')) { | ||
hasAstroUpdate = true; | ||
continue; | ||
} | ||
if (file.acceptedPath.includes('vue&type=style')) { | ||
const link = document.querySelector(`link[href="${file.acceptedPath}"]`); | ||
if (link) { | ||
link.replaceWith(link.cloneNode(true)); | ||
} | ||
} | ||
} | ||
if (hasAstroUpdate) { | ||
return updatePage() | ||
} | ||
Comment on lines
+33
to
+35
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If an |
||
} | ||
import.meta.hot.on('vite:beforeUpdate', async (event) => { | ||
await updateAll(event.updates); | ||
}); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -82,18 +82,17 @@ export async function handleHotUpdate(ctx: HmrContext, config: AstroConfig, logg | |
invalidateCompilation(config, file); | ||
} | ||
|
||
const mod = ctx.modules.find((m) => m.file === ctx.file); | ||
// Bugfix: sometimes style URLs get normalized and end with `lang.css=` | ||
// These will cause full reloads, so filter them out here | ||
const mods = ctx.modules.filter(m => !m.url.endsWith('=')); | ||
Comment on lines
+85
to
+87
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was an edge case that was causing full reloads when they weren't called for. Sometimes |
||
const isSelfAccepting = mods.every(m => m.isSelfAccepting || m.url.endsWith('.svelte')); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Check all modules for |
||
|
||
// Note: this intentionally ONLY applies to Astro components | ||
// HMR is handled for other file types by their respective plugins | ||
const file = ctx.file.replace(config.root.pathname, '/'); | ||
if (ctx.file.endsWith('.astro')) { | ||
ctx.server.ws.send({ type: 'custom', event: 'astro:update', data: { file } }); | ||
} | ||
if (mod?.isSelfAccepting) { | ||
if (isSelfAccepting) { | ||
info(logging, 'astro', msg.hmr({ file })); | ||
} else { | ||
info(logging, 'astro', msg.reload({ file })); | ||
} | ||
return Array.from(filtered); | ||
|
||
return mods | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -174,7 +174,20 @@ export default function astro({ config, logging }: AstroPluginOptions): vite.Plu | |
let SUFFIX = ''; | ||
// Add HMR handling in dev mode. | ||
if (!resolvedConfig.isProduction) { | ||
SUFFIX += `\nif (import.meta.hot) import.meta.hot.accept((mod) => mod);`; | ||
// HACK: extract dependencies from metadata until compiler static extraction handles them | ||
const metadata = transformResult.code.split('$$createMetadata(')[1].split('});\n')[0] | ||
const pattern = /specifier:\s*'([^']*)'/g; | ||
const deps = new Set(); | ||
let match; | ||
while (match = pattern.exec(metadata)?.[1]) { | ||
deps.add(match); | ||
} | ||
// // import.meta.hot.accept(["${id}", "${Array.from(deps).join('","')}"], (...mods) => mods); | ||
// We need to be self-accepting, AND | ||
// we need an explicity array of deps to track changes for SSR-only components | ||
SUFFIX += `\nif (import.meta.hot) { | ||
import.meta.hot.accept(mod => mod); | ||
}`; | ||
Comment on lines
+177
to
+190
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Rather than trigger HMR for only updates to this Astro file, we want to catch HMR updates for any dependencies. This is a bit hacky and could be cleaned up in the compiler, but it works for now. |
||
} | ||
// Add handling to inject scripts into each page JS bundle, if needed. | ||
if (isPage) { | ||
|
@@ -242,7 +255,7 @@ export default function astro({ config, logging }: AstroPluginOptions): vite.Plu | |
} | ||
} | ||
|
||
throw err; | ||
throw err; | ||
} | ||
}, | ||
async handleHotUpdate(context) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Custom HMR events are gone! Everything is handled by Vite now.