Skip to content

Commit b4432cd

Browse files
authored
[Content collections] Load MDX hoisted scripts in dev (#6035)
* chore: script, rename delayed -> propagated * fix: consistent propagatedAssets flag * feat: inject those scripts in dev! * test: scripts included in dev and build * chore: add TODO for prod build fix * chore: changeset
1 parent 9bb0bfa commit b4432cd

21 files changed

Lines changed: 264 additions & 115 deletions

.changeset/eight-kids-attack.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: Astro component scripts now load in development when using MDX + Content Collections
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
export const contentFileExts = ['.md', '.mdx'];
2-
export const DELAYED_ASSET_FLAG = 'astroAssetSsr';
2+
export const PROPAGATED_ASSET_FLAG = 'astroPropagatedAssets';
33
export const CONTENT_FLAG = 'astroContent';
44
export const VIRTUAL_MODULE_ID = 'astro:content';
55
export const LINKS_PLACEHOLDER = '@@ASTRO-LINKS@@';
66
export const STYLES_PLACEHOLDER = '@@ASTRO-STYLES@@';
7+
export const SCRIPTS_PLACEHOLDER = '@@ASTRO-SCRIPTS@@';
78

89
export const CONTENT_TYPES_FILE = 'types.d.ts';
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
export { createContentTypesGenerator } from './types-generator.js';
22
export { contentObservable, getContentPaths, getDotAstroTypeReference } from './utils.js';
33
export {
4-
astroBundleDelayedAssetPlugin,
5-
astroDelayedAssetPlugin,
4+
astroContentProdBundlePlugin,
5+
astroContentAssetPropagationPlugin,
66
} from './vite-plugin-content-assets.js';
77
export { astroContentServerPlugin } from './vite-plugin-content-server.js';
88
export { astroContentVirtualModPlugin } from './vite-plugin-content-virtual-mod.js';

packages/astro/src/content/internal.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
createHeadAndContent,
66
renderComponent,
77
renderStyleElement,
8+
renderScriptElement,
89
renderTemplate,
910
renderUniqueStylesheet,
1011
unescapeHTML,
@@ -127,7 +128,8 @@ async function render({
127128
const Content = createComponent({
128129
factory(result, props, slots) {
129130
let styles = '',
130-
links = '';
131+
links = '',
132+
scripts = '';
131133
if (Array.isArray(mod?.collectedStyles)) {
132134
styles = mod.collectedStyles.map((style: any) => renderStyleElement(style)).join('');
133135
}
@@ -140,9 +142,12 @@ async function render({
140142
})
141143
.join('');
142144
}
145+
if (Array.isArray(mod?.collectedScripts)) {
146+
scripts = mod.collectedScripts.map((script: any) => renderScriptElement(script)).join('');
147+
}
143148

144149
return createHeadAndContent(
145-
unescapeHTML(styles + links) as any,
150+
unescapeHTML(styles + links + scripts) as any,
146151
renderTemplate`${renderComponent(result, 'Content', mod.Content, props, slots)}`
147152
);
148153
},

packages/astro/src/content/template/virtual-mod.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ const collectionToEntryMap = createCollectionToGlobResultMap({
2222
});
2323

2424
const renderEntryGlob = import.meta.glob('@@RENDER_ENTRY_GLOB_PATH@@', {
25-
query: { astroAssetSsr: true },
25+
query: { astroPropagatedAssets: true },
2626
});
2727
const collectionToRenderEntryMap = createCollectionToGlobResultMap({
2828
globResult: renderEntryGlob,

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

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,45 +5,48 @@ import { BuildInternals, getPageDataByViteID } from '../core/build/internal.js';
55
import type { ModuleLoader } from '../core/module-loader/loader.js';
66
import { createViteLoader } from '../core/module-loader/vite.js';
77
import { getStylesForURL } from '../core/render/dev/css.js';
8+
import { getScriptsForURL } from '../core/render/dev/scripts.js';
89
import {
910
contentFileExts,
10-
DELAYED_ASSET_FLAG,
11+
PROPAGATED_ASSET_FLAG,
1112
LINKS_PLACEHOLDER,
13+
SCRIPTS_PLACEHOLDER,
1214
STYLES_PLACEHOLDER,
1315
} from './consts.js';
1416

15-
function isDelayedAsset(viteId: string): boolean {
17+
function isPropagatedAsset(viteId: string): boolean {
1618
const url = new URL(viteId, 'file://');
1719
return (
18-
url.searchParams.has(DELAYED_ASSET_FLAG) &&
20+
url.searchParams.has(PROPAGATED_ASSET_FLAG) &&
1921
contentFileExts.some((ext) => url.pathname.endsWith(ext))
2022
);
2123
}
2224

23-
export function astroDelayedAssetPlugin({ mode }: { mode: string }): Plugin {
25+
export function astroContentAssetPropagationPlugin({ mode }: { mode: string }): Plugin {
2426
let devModuleLoader: ModuleLoader;
2527
return {
26-
name: 'astro-delayed-asset-plugin',
28+
name: 'astro:content-asset-propagation',
2729
enforce: 'pre',
2830
configureServer(server) {
2931
if (mode === 'dev') {
3032
devModuleLoader = createViteLoader(server);
3133
}
3234
},
3335
load(id) {
34-
if (isDelayedAsset(id)) {
36+
if (isPropagatedAsset(id)) {
3537
const basePath = id.split('?')[0];
3638
const code = `
3739
export { Content, getHeadings, frontmatter } from ${JSON.stringify(basePath)};
3840
export const collectedLinks = ${JSON.stringify(LINKS_PLACEHOLDER)};
3941
export const collectedStyles = ${JSON.stringify(STYLES_PLACEHOLDER)};
42+
export const collectedScripts = ${JSON.stringify(SCRIPTS_PLACEHOLDER)};
4043
`;
4144
return { code };
4245
}
4346
},
4447
async transform(code, id, options) {
4548
if (!options?.ssr) return;
46-
if (devModuleLoader && isDelayedAsset(id)) {
49+
if (devModuleLoader && isPropagatedAsset(id)) {
4750
const basePath = id.split('?')[0];
4851
if (!devModuleLoader.getModuleById(basePath)?.ssrModule) {
4952
await devModuleLoader.import(basePath);
@@ -54,23 +57,22 @@ export function astroDelayedAssetPlugin({ mode }: { mode: string }): Plugin {
5457
'development'
5558
);
5659

60+
const hoistedScripts = await getScriptsForURL(pathToFileURL(basePath), devModuleLoader);
61+
5762
return {
5863
code: code
5964
.replace(JSON.stringify(LINKS_PLACEHOLDER), JSON.stringify([...urls]))
60-
.replace(JSON.stringify(STYLES_PLACEHOLDER), JSON.stringify([...stylesMap.values()])),
65+
.replace(JSON.stringify(STYLES_PLACEHOLDER), JSON.stringify([...stylesMap.values()]))
66+
.replace(JSON.stringify(SCRIPTS_PLACEHOLDER), JSON.stringify([...hoistedScripts])),
6167
};
6268
}
6369
},
6470
};
6571
}
6672

67-
export function astroBundleDelayedAssetPlugin({
68-
internals,
69-
}: {
70-
internals: BuildInternals;
71-
}): Plugin {
73+
export function astroContentProdBundlePlugin({ internals }: { internals: BuildInternals }): Plugin {
7274
return {
73-
name: 'astro-bundle-delayed-asset-plugin',
75+
name: 'astro:content-prod-bundle',
7476
async generateBundle(_options, bundle) {
7577
for (const [_, chunk] of Object.entries(bundle)) {
7678
if (chunk.type === 'chunk' && chunk.code.includes(LINKS_PLACEHOLDER)) {

packages/astro/src/core/build/static-build.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import fs from 'fs';
44
import { bgGreen, bgMagenta, black, dim } from 'kleur/colors';
55
import { fileURLToPath } from 'url';
66
import * as vite from 'vite';
7-
import { astroBundleDelayedAssetPlugin } from '../../content/index.js';
7+
import { astroContentProdBundlePlugin } from '../../content/index.js';
88
import {
99
BuildInternals,
1010
createBuildInternals,
@@ -165,7 +165,7 @@ async function ssrBuild(opts: StaticBuildOptions, internals: BuildInternals, inp
165165
}),
166166
vitePluginPrerender(opts, internals),
167167
...(viteConfig.plugins || []),
168-
astroBundleDelayedAssetPlugin({ internals }),
168+
astroContentProdBundlePlugin({ internals }),
169169
// SSR needs to be last
170170
ssr && vitePluginSSR(internals, settings.adapter!),
171171
],

packages/astro/src/core/build/vite-plugin-css.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { isCSSRequest } from '../render/util.js';
66
import type { BuildInternals } from './internal';
77
import type { PageBuildData, StaticBuildOptions } from './types';
88

9-
import { DELAYED_ASSET_FLAG } from '../../content/consts.js';
9+
import { PROPAGATED_ASSET_FLAG } from '../../content/consts.js';
1010
import * as assetName from './css-asset-name.js';
1111
import { moduleIsTopLevelPage, walkParentInfos } from './graph.js';
1212
import {
@@ -79,7 +79,7 @@ export function rollupPluginAstroBuildCSS(options: PluginOptions): VitePlugin[]
7979
for (const [pageInfo] of walkParentInfos(id, {
8080
getModuleInfo: args[0].getModuleInfo,
8181
})) {
82-
if (new URL(pageInfo.id, 'file://').searchParams.has(DELAYED_ASSET_FLAG)) {
82+
if (new URL(pageInfo.id, 'file://').searchParams.has(PROPAGATED_ASSET_FLAG)) {
8383
// Split delayed assets to separate modules
8484
// so they can be injected where needed
8585
return createNameHash(id, [id]);
@@ -172,10 +172,10 @@ export function rollupPluginAstroBuildCSS(options: PluginOptions): VitePlugin[]
172172
id,
173173
this,
174174
function until(importer) {
175-
return new URL(importer, 'file://').searchParams.has(DELAYED_ASSET_FLAG);
175+
return new URL(importer, 'file://').searchParams.has(PROPAGATED_ASSET_FLAG);
176176
}
177177
)) {
178-
if (new URL(pageInfo.id, 'file://').searchParams.has(DELAYED_ASSET_FLAG)) {
178+
if (new URL(pageInfo.id, 'file://').searchParams.has(PROPAGATED_ASSET_FLAG)) {
179179
for (const parent of walkParentInfos(id, this)) {
180180
const parentInfo = parent[0];
181181
if (moduleIsTopLevelPage(parentInfo)) {

packages/astro/src/core/create-vite.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { crawlFrameworkPkgs } from 'vitefu';
88
import {
99
astroContentServerPlugin,
1010
astroContentVirtualModPlugin,
11-
astroDelayedAssetPlugin,
11+
astroContentAssetPropagationPlugin,
1212
} from '../content/index.js';
1313
import astroPostprocessVitePlugin from '../vite-plugin-astro-postprocess/index.js';
1414
import { vitePluginAstroServer } from '../vite-plugin-astro-server/index.js';
@@ -106,7 +106,7 @@ export async function createVite(
106106
astroInjectEnvTsPlugin({ settings, logging, fs }),
107107
astroContentVirtualModPlugin({ settings }),
108108
astroContentServerPlugin({ fs, settings, logging, mode }),
109-
astroDelayedAssetPlugin({ mode }),
109+
astroContentAssetPropagationPlugin({ mode }),
110110
],
111111
publicDir: fileURLToPath(settings.config.publicDir),
112112
root: fileURLToPath(settings.config.root),

packages/astro/src/core/render/dev/vite.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { ModuleLoader, ModuleNode } from '../../module-loader/index';
22

33
import npath from 'path';
4-
import { DELAYED_ASSET_FLAG } from '../../../content/consts.js';
4+
import { PROPAGATED_ASSET_FLAG } from '../../../content/consts.js';
55
import { SUPPORTED_MARKDOWN_FILE_EXTENSIONS } from '../../constants.js';
66
import { unwrapId } from '../../util.js';
77
import { STYLE_EXTENSIONS } from '../util.js';
@@ -23,7 +23,7 @@ export async function* crawlGraph(
2323
): AsyncGenerator<ModuleNode, void, unknown> {
2424
const id = unwrapId(_id);
2525
const importedModules = new Set<ModuleNode>();
26-
if (new URL(id, 'file://').searchParams.has(DELAYED_ASSET_FLAG)) return;
26+
if (new URL(id, 'file://').searchParams.has(PROPAGATED_ASSET_FLAG)) return;
2727

2828
const moduleEntriesForId = isRootFile
2929
? // "getModulesByFile" pulls from a delayed module cache (fun implementation detail),

0 commit comments

Comments
 (0)