Skip to content

Commit a93c81d

Browse files
authored
fix(content): reload markdown updates in dev (#15497)
* fix(content): reload markdown updates in dev * fix lint + comment * test: fix hmr markdown fixture
1 parent 913863a commit a93c81d

File tree

10 files changed

+110
-2
lines changed

10 files changed

+110
-2
lines changed

.changeset/fix-content-hmr.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"astro": patch
3+
---
4+
5+
Fix dev reloads for content collection Markdown updates under Vite 7.

packages/astro/src/content/vite-plugin-content-imports.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ export const _internal = {
163163
viteServer.watcher.on('all', async (event, entry) => {
164164
if (CHOKIDAR_MODIFIED_EVENTS.includes(event)) {
165165
const environment = viteServer.environments[ASTRO_VITE_ENVIRONMENT_NAMES.ssr];
166+
const timestamp = Date.now();
166167

167168
const entryType = getEntryType(entry, contentPaths, contentEntryExts, dataEntryExts);
168169
if (!COLLECTION_TYPES_TO_INVALIDATE_ON.includes(entryType)) return;
@@ -191,7 +192,8 @@ export const _internal = {
191192
try {
192193
const mod = await environment.moduleGraph.getModuleByUrl(modUrl);
193194
if (mod) {
194-
environment.moduleGraph.invalidateModule(mod);
195+
// Pass `true` to mark this as HMR invalidation so Vite drops cached SSR results.
196+
environment.moduleGraph.invalidateModule(mod, undefined, timestamp, true);
195197
}
196198
} catch (e: any) {
197199
// The server may be closed due to a restart caused by this file change

packages/astro/src/content/vite-plugin-content-virtual-mod.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@ function invalidateDataStore(viteServer: ViteDevServer) {
3535
const environment = viteServer.environments[ASTRO_VITE_ENVIRONMENT_NAMES.ssr];
3636
const module = environment.moduleGraph.getModuleById(RESOLVED_DATA_STORE_VIRTUAL_ID);
3737
if (module) {
38-
environment.moduleGraph.invalidateModule(module);
38+
const timestamp = Date.now();
39+
// Pass `true` to mark this as HMR invalidation so Vite drops cached SSR results.
40+
environment.moduleGraph.invalidateModule(module, undefined, timestamp, true);
3941
}
4042
viteServer.environments.client.hot.send({
4143
type: 'full-reload',
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { defineConfig } from 'astro/config';
2+
3+
export default defineConfig({});
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"name": "@test/hmr-markdown",
3+
"version": "0.0.0",
4+
"private": true,
5+
"dependencies": {
6+
"astro": "workspace:*"
7+
}
8+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { defineCollection } from 'astro:content';
2+
import { glob } from 'astro/loaders';
3+
import { z } from 'astro/zod';
4+
5+
const blog = defineCollection({
6+
loader: glob({ pattern: '**/*.md', base: './src/content/blog' }),
7+
schema: z.object({
8+
title: z.string(),
9+
}),
10+
});
11+
12+
export const collections = { blog };
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
title: HMR Markdown
3+
---
4+
5+
Original content
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
---
2+
import { getCollection } from 'astro:content';
3+
4+
const [post] = await getCollection('blog');
5+
---
6+
<html>
7+
<head>
8+
<title>HMR Markdown</title>
9+
</head>
10+
<body>
11+
<h1>Blog Posts</h1>
12+
{post ? (
13+
<>
14+
<h2>{post.data.title}</h2>
15+
<div id="post-body">{post.body}</div>
16+
</>
17+
) : (
18+
<p data-empty>Empty</p>
19+
)}
20+
</body>
21+
</html>
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import assert from 'node:assert/strict';
2+
import { after, before, describe, it } from 'node:test';
3+
import { isWindows, loadFixture } from './test-utils.js';
4+
5+
const UPDATED_CONTENT = '---\ntitle: HMR Markdown\n---\n\nUpdated content\n';
6+
7+
describe('HMR: Markdown updates', () => {
8+
/** @type {import('./test-utils').Fixture} */
9+
let fixture;
10+
/** @type {import('./test-utils').DevServer} */
11+
let devServer;
12+
/** @type {string} */
13+
let markdownPath;
14+
15+
before(async () => {
16+
fixture = await loadFixture({ root: './fixtures/hmr-markdown/' });
17+
devServer = await fixture.startDevServer();
18+
19+
markdownPath = '/src/content/blog/post.md';
20+
});
21+
22+
after(async () => {
23+
await devServer.stop();
24+
});
25+
26+
it(
27+
'should update HTML when markdown changes',
28+
{ skip: isWindows, todo: 'HMR tests hang on Windows' },
29+
async () => {
30+
let response = await fixture.fetch('/');
31+
assert.equal(response.status, 200);
32+
let html = await response.text();
33+
assert.ok(html.includes('Original content'));
34+
35+
await fixture.editFile(markdownPath, UPDATED_CONTENT);
36+
await fixture.onNextDataStoreChange();
37+
38+
response = await fixture.fetch('/');
39+
assert.equal(response.status, 200);
40+
html = await response.text();
41+
assert.ok(html.includes('Updated content'));
42+
},
43+
);
44+
});

pnpm-lock.yaml

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)