HMR hoisted scripts (#3336)

* HMR hoisted scripts

* Add to the dep graph

* Remove example change

* Adds changeset

* Fix markdown test
This commit is contained in:
Matthew Phillips 2022-05-11 09:23:11 -06:00 committed by GitHub
parent 3bb07a01e0
commit ccea6a0a1a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 42 additions and 9 deletions

View file

@ -0,0 +1,5 @@
---
'astro': patch
---
Fixes HMR of hoisted script tags

View file

@ -68,6 +68,7 @@ export async function handleHotUpdate(ctx: HmrContext, config: AstroConfig, logg
filtered.add(mod);
files.add(mod.file);
}
for (const imp of mod.importers) {
if (imp.file && isCached(config, imp.file)) {
filtered.add(imp);
@ -85,6 +86,15 @@ export async function handleHotUpdate(ctx: HmrContext, config: AstroConfig, logg
// 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('='));
// Add hoisted scripts so these get invalidated
for(const mod of mods) {
for(const imp of mod.importedModules) {
if(imp.id?.includes('?astro&type=script')) {
mods.push(imp);
}
}
}
const isSelfAccepting = mods.every((m) => m.isSelfAccepting || m.url.endsWith('.svelte'));
const file = ctx.file.replace(config.root.pathname, '/');

View file

@ -126,6 +126,12 @@ export default function astro({ config, logging }: AstroPluginOptions): vite.Plu
if (typeof query.index === 'undefined') {
throw new Error(`Requests for hoisted scripts must include an index`);
}
// HMR hoisted script only exists to make them appear in the module graph.
if(opts?.ssr) {
return {
code: `/* client hoisted script, empty in SSR: ${id} */`
};
}
const transformResult = await cachedCompilation(config, filename, source, viteTransform, {
ssr: Boolean(opts?.ssr),
@ -182,17 +188,28 @@ export default function astro({ config, logging }: AstroPluginOptions): vite.Plu
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
let i = 0;
while(i < transformResult.scripts.length) {
deps.add(`${id}?astro&type=script&index=${i}`);
SUFFIX += `import "${id}?astro&type=script&index=${i}";`;
i++;
}
// We only need to define deps if there are any
if(deps.size > 1) {
SUFFIX += `\nif(import.meta.hot) import.meta.hot.accept(["${id}", "${Array.from(deps).join('","')}"], (...mods) => mods);`
} else {
SUFFIX += `\nif (import.meta.hot) {
import.meta.hot.accept(mod => mod);
}`;
}
}
// Add handling to inject scripts into each page JS bundle, if needed.
if (isPage) {
SUFFIX += `\nimport "${PAGE_SSR_SCRIPT_ID}";`;
}
return {
code: `${code}${SUFFIX}`,
map,
@ -260,7 +277,7 @@ export default function astro({ config, logging }: AstroPluginOptions): vite.Plu
},
async handleHotUpdate(context) {
if (context.server.config.isProduction) return;
return handleHotUpdate(context, config, logging);
return handleHotUpdate.call(this, context, config, logging);
},
};
}

View file

@ -34,11 +34,12 @@ describe('Imported markdown CSS', function () {
});
describe('dev', () => {
let devServer;
let html;
let $;
before(async () => {
devServer = await fixture.startDevServer();
const html = await fixture.fetch('/').then((res) => res.text());
html = await fixture.fetch('/').then((res) => res.text());
$ = cheerio.load(html);
});