mirror of
https://github.com/withastro/astro.git
synced 2024-12-16 21:46:22 -05:00
Fix HMR in MDX deps in Content Collections (#9956)
Co-authored-by: Florian Lefebvre <contact@florian-lefebvre.dev> Co-authored-by: bluwy <bjornlu.dev@gmail.com>
This commit is contained in:
parent
6e30bef652
commit
81acac24a3
13 changed files with 124 additions and 10 deletions
5
.changeset/soft-bags-flash.md
Normal file
5
.changeset/soft-bags-flash.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
"astro": patch
|
||||
---
|
||||
|
||||
Fixes HMR for MDX dependencies in Content Collections
|
32
packages/astro/e2e/content-collections.test.js
Normal file
32
packages/astro/e2e/content-collections.test.js
Normal file
|
@ -0,0 +1,32 @@
|
|||
import { expect } from '@playwright/test';
|
||||
import { testFactory } from './test-utils.js';
|
||||
|
||||
const test = testFactory({ root: './fixtures/content-collections/' });
|
||||
|
||||
let devServer;
|
||||
|
||||
test.beforeAll(async ({ astro }) => {
|
||||
devServer = await astro.startDevServer();
|
||||
});
|
||||
|
||||
test.afterAll(async ({ astro }) => {
|
||||
await devServer.stop();
|
||||
astro.resetAllFiles();
|
||||
});
|
||||
|
||||
test.describe('Content Collections', () => {
|
||||
test('HMR', async ({ page, astro }) => {
|
||||
await page.goto(astro.resolveUrl('/'));
|
||||
|
||||
await astro.editFile('./src/components/MyComponent.astro', (original) =>
|
||||
original.replace('red', 'green')
|
||||
);
|
||||
|
||||
const h1 = page.locator('#my-heading');
|
||||
|
||||
await expect(h1, 'should have green color').toHaveCSS(
|
||||
'color',
|
||||
'rgb(0, 128, 0)'
|
||||
);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,9 @@
|
|||
import { defineConfig } from 'astro/config';
|
||||
import mdx from '@astrojs/mdx';
|
||||
|
||||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
integrations: [
|
||||
mdx(),
|
||||
],
|
||||
});
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"name": "@e2e/content-collections",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@astrojs/mdx": "workspace:*",
|
||||
"astro": "workspace:*"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
<h1 id="my-heading">
|
||||
Some text here
|
||||
</h1>
|
||||
|
||||
|
||||
<style>
|
||||
h1 {
|
||||
color: red;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
---
|
||||
|
||||
import MyComponent from '../../components/MyComponent.astro';
|
||||
|
||||
<MyComponent />
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
import { getEntryBySlug } from 'astro:content'
|
||||
|
||||
const post = await getEntryBySlug('posts', 'post-1')
|
||||
const { Content } = await post.render();
|
||||
---
|
||||
|
||||
<Content/>
|
|
@ -64,13 +64,29 @@ export function astroContentAssetPropagationPlugin({
|
|||
if (!devModuleLoader.getModuleById(basePath)?.ssrModule) {
|
||||
await devModuleLoader.import(basePath);
|
||||
}
|
||||
const { styles, urls } = await getStylesForURL(pathToFileURL(basePath), devModuleLoader);
|
||||
const {
|
||||
styles,
|
||||
urls,
|
||||
crawledFiles: styleCrawledFiles,
|
||||
} = await getStylesForURL(pathToFileURL(basePath), devModuleLoader);
|
||||
|
||||
const hoistedScripts = await getScriptsForURL(
|
||||
pathToFileURL(basePath),
|
||||
settings.config.root,
|
||||
devModuleLoader
|
||||
);
|
||||
const { scripts: hoistedScripts, crawledFiles: scriptCrawledFiles } =
|
||||
await getScriptsForURL(pathToFileURL(basePath), settings.config.root, devModuleLoader);
|
||||
|
||||
// Register files we crawled to be able to retrieve the rendered styles and scripts,
|
||||
// as when they get updated, we need to re-transform ourselves.
|
||||
// We also only watch files within the user source code, as changes in node_modules
|
||||
// are usually also ignored by Vite.
|
||||
for (const file of styleCrawledFiles) {
|
||||
if (!file.includes('node_modules')) {
|
||||
this.addWatchFile(file);
|
||||
}
|
||||
}
|
||||
for (const file of scriptCrawledFiles) {
|
||||
if (!file.includes('node_modules')) {
|
||||
this.addWatchFile(file);
|
||||
}
|
||||
}
|
||||
|
||||
stringifiedLinks = JSON.stringify([...urls]);
|
||||
stringifiedStyles = JSON.stringify(styles.map((s) => s.content));
|
||||
|
|
|
@ -41,6 +41,7 @@ export interface ModuleLoader {
|
|||
export interface ModuleNode {
|
||||
id: string | null;
|
||||
url: string;
|
||||
file: string | null;
|
||||
ssrModule: Record<string, any> | null;
|
||||
ssrTransformResult: {
|
||||
deps?: string[];
|
||||
|
|
|
@ -13,12 +13,16 @@ interface ImportedStyle {
|
|||
export async function getStylesForURL(
|
||||
filePath: URL,
|
||||
loader: ModuleLoader
|
||||
): Promise<{ urls: Set<string>; styles: ImportedStyle[] }> {
|
||||
): Promise<{ urls: Set<string>; styles: ImportedStyle[]; crawledFiles: Set<string> }> {
|
||||
const importedCssUrls = new Set<string>();
|
||||
// Map of url to injected style object. Use a `url` key to deduplicate styles
|
||||
const importedStylesMap = new Map<string, ImportedStyle>();
|
||||
const crawledFiles = new Set<string>();
|
||||
|
||||
for await (const importedModule of crawlGraph(loader, viteID(filePath), true)) {
|
||||
if (importedModule.file) {
|
||||
crawledFiles.add(importedModule.file);
|
||||
}
|
||||
if (isBuildableCSSRequest(importedModule.url)) {
|
||||
// In dev, we inline all styles if possible
|
||||
let css = '';
|
||||
|
@ -60,5 +64,6 @@ export async function getStylesForURL(
|
|||
return {
|
||||
urls: importedCssUrls,
|
||||
styles: [...importedStylesMap.values()],
|
||||
crawledFiles,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -393,7 +393,7 @@ async function getScriptsAndStyles({ pipeline, filePath }: GetScriptsAndStylesPa
|
|||
const settings = pipeline.getSettings();
|
||||
const mode = pipeline.getEnvironment().mode;
|
||||
// Add hoisted script tags
|
||||
const scripts = await getScriptsForURL(filePath, settings.config.root, moduleLoader);
|
||||
const { scripts } = await getScriptsForURL(filePath, settings.config.root, moduleLoader);
|
||||
|
||||
// Inject HMR scripts
|
||||
if (isPage(filePath, settings) && mode === 'development') {
|
||||
|
|
|
@ -9,12 +9,16 @@ export async function getScriptsForURL(
|
|||
filePath: URL,
|
||||
root: URL,
|
||||
loader: ModuleLoader
|
||||
): Promise<Set<SSRElement>> {
|
||||
): Promise<{ scripts: Set<SSRElement>; crawledFiles: Set<string> }> {
|
||||
const elements = new Set<SSRElement>();
|
||||
const crawledFiles = new Set<string>();
|
||||
const rootID = viteID(filePath);
|
||||
const modInfo = loader.getModuleInfo(rootID);
|
||||
addHoistedScripts(elements, modInfo, root);
|
||||
for await (const moduleNode of crawlGraph(loader, rootID, true)) {
|
||||
if (moduleNode.file) {
|
||||
crawledFiles.add(moduleNode.file);
|
||||
}
|
||||
const id = moduleNode.id;
|
||||
if (id) {
|
||||
const info = loader.getModuleInfo(id);
|
||||
|
@ -22,7 +26,7 @@ export async function getScriptsForURL(
|
|||
}
|
||||
}
|
||||
|
||||
return elements;
|
||||
return { scripts: elements, crawledFiles };
|
||||
}
|
||||
|
||||
function addHoistedScripts(set: Set<SSRElement>, info: ModuleInfo | null, root: URL) {
|
||||
|
|
|
@ -935,6 +935,15 @@ importers:
|
|||
specifier: workspace:*
|
||||
version: link:../../..
|
||||
|
||||
packages/astro/e2e/fixtures/content-collections:
|
||||
dependencies:
|
||||
'@astrojs/mdx':
|
||||
specifier: workspace:*
|
||||
version: link:../../../../integrations/mdx
|
||||
astro:
|
||||
specifier: workspace:*
|
||||
version: link:../../..
|
||||
|
||||
packages/astro/e2e/fixtures/css:
|
||||
dependencies:
|
||||
astro:
|
||||
|
|
Loading…
Reference in a new issue