Include astro components for HMR invalidation (#4240)
* Include astro components for HMR invalidation * Changeset * remove extra vite server passing
This commit is contained in:
parent
d186c406b9
commit
561a34d912
9 changed files with 86 additions and 2 deletions
5
.changeset/nasty-gifts-push.md
Normal file
5
.changeset/nasty-gifts-push.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'astro': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Properly invalidate Astro modules when a child script updates in HMR
|
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"name": "@e2e/invalidate-script-deps",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"private": true,
|
||||||
|
"devDependencies": {
|
||||||
|
"astro": "workspace:*"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Test</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1></h1>
|
||||||
|
<script>
|
||||||
|
import '../scripts/heading.js';
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,2 @@
|
||||||
|
|
||||||
|
document.querySelector('h1').textContent = 'before';
|
31
packages/astro/e2e/invalidate-script-deps.test.js
Normal file
31
packages/astro/e2e/invalidate-script-deps.test.js
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
import { expect } from '@playwright/test';
|
||||||
|
import { testFactory } from './test-utils.js';
|
||||||
|
|
||||||
|
const test = testFactory({
|
||||||
|
root: './fixtures/invalidate-script-deps/',
|
||||||
|
});
|
||||||
|
|
||||||
|
let devServer;
|
||||||
|
|
||||||
|
test.beforeEach(async ({ astro }) => {
|
||||||
|
devServer = await astro.startDevServer();
|
||||||
|
});
|
||||||
|
|
||||||
|
test.afterEach(async () => {
|
||||||
|
await devServer.stop();
|
||||||
|
});
|
||||||
|
|
||||||
|
test.describe('Scripts with dependencies', () => {
|
||||||
|
test('refresh with HMR', async ({ page, astro }) => {
|
||||||
|
await page.goto(astro.resolveUrl('/'));
|
||||||
|
|
||||||
|
const h = page.locator('h1');
|
||||||
|
await expect(h, 'original text set').toHaveText('before');
|
||||||
|
|
||||||
|
await astro.editFile('./src/scripts/heading.js', (original) =>
|
||||||
|
original.replace('before', 'after')
|
||||||
|
);
|
||||||
|
|
||||||
|
await expect(h, 'text changed').toHaveText('after');
|
||||||
|
});
|
||||||
|
});
|
|
@ -6,6 +6,7 @@ import type { LogOptions } from '../core/logger/core.js';
|
||||||
import { info } from '../core/logger/core.js';
|
import { info } from '../core/logger/core.js';
|
||||||
import * as msg from '../core/messages.js';
|
import * as msg from '../core/messages.js';
|
||||||
import { cachedCompilation, invalidateCompilation, isCached } from './compile.js';
|
import { cachedCompilation, invalidateCompilation, isCached } from './compile.js';
|
||||||
|
import { isAstroScript } from './query.js';
|
||||||
|
|
||||||
interface TrackCSSDependenciesOptions {
|
interface TrackCSSDependenciesOptions {
|
||||||
viteDevServer: ViteDevServer | null;
|
viteDevServer: ViteDevServer | null;
|
||||||
|
@ -141,12 +142,23 @@ export async function handleHotUpdate(
|
||||||
// Add hoisted scripts so these get invalidated
|
// Add hoisted scripts so these get invalidated
|
||||||
for (const mod of mods) {
|
for (const mod of mods) {
|
||||||
for (const imp of mod.importedModules) {
|
for (const imp of mod.importedModules) {
|
||||||
if (imp.id?.includes('?astro&type=script')) {
|
if (imp.id && isAstroScript(imp.id)) {
|
||||||
mods.push(imp);
|
mods.push(imp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If this is a module that is imported from a <script>, invalidate the Astro
|
||||||
|
// component so that it is cached by the time the script gets transformed.
|
||||||
|
for(const mod of filtered) {
|
||||||
|
if(mod.id && isAstroScript(mod.id) && mod.file) {
|
||||||
|
const astroMod = ctx.server.moduleGraph.getModuleById(mod.file);
|
||||||
|
if(astroMod) {
|
||||||
|
mods.unshift(astroMod);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Svelte files should be marked as `isSelfAccepting` but they don't appear to be
|
// TODO: Svelte files should be marked as `isSelfAccepting` but they don't appear to be
|
||||||
const isSelfAccepting = mods.every((m) => m.isSelfAccepting || m.url.endsWith('.svelte'));
|
const isSelfAccepting = mods.every((m) => m.isSelfAccepting || m.url.endsWith('.svelte'));
|
||||||
if (isSelfAccepting) {
|
if (isSelfAccepting) {
|
||||||
|
|
|
@ -359,7 +359,11 @@ ${source}
|
||||||
pluginContext: this,
|
pluginContext: this,
|
||||||
};
|
};
|
||||||
const compile = () => cachedCompilation(compileProps);
|
const compile = () => cachedCompilation(compileProps);
|
||||||
return handleHotUpdate.call(this, context, { config, logging, compile });
|
return handleHotUpdate.call(this, context, {
|
||||||
|
config,
|
||||||
|
logging,
|
||||||
|
compile
|
||||||
|
});
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,3 +35,8 @@ export function parseAstroRequest(id: string): ParsedRequestResult {
|
||||||
query,
|
query,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isAstroScript(id: string): boolean {
|
||||||
|
const parsed = parseAstroRequest(id);
|
||||||
|
return parsed.query.type === 'script';
|
||||||
|
}
|
||||||
|
|
|
@ -659,6 +659,12 @@ importers:
|
||||||
react: 18.2.0
|
react: 18.2.0
|
||||||
react-dom: 18.2.0_react@18.2.0
|
react-dom: 18.2.0_react@18.2.0
|
||||||
|
|
||||||
|
packages/astro/e2e/fixtures/invalidate-script-deps:
|
||||||
|
specifiers:
|
||||||
|
astro: workspace:*
|
||||||
|
devDependencies:
|
||||||
|
astro: link:../../..
|
||||||
|
|
||||||
packages/astro/e2e/fixtures/lit-component:
|
packages/astro/e2e/fixtures/lit-component:
|
||||||
specifiers:
|
specifiers:
|
||||||
'@astrojs/lit': workspace:*
|
'@astrojs/lit': workspace:*
|
||||||
|
|
Loading…
Reference in a new issue