Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Content collections] Load MDX hoisted scripts in dev #6035

Merged
merged 6 commits into from
Jan 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/eight-kids-attack.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'astro': patch
---

Fix: Astro component scripts now load in development when using MDX + Content Collections
3 changes: 2 additions & 1 deletion packages/astro/src/content/consts.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
export const contentFileExts = ['.md', '.mdx'];
export const DELAYED_ASSET_FLAG = 'astroAssetSsr';
export const PROPAGATED_ASSET_FLAG = 'astroPropagatedAssets';
export const CONTENT_FLAG = 'astroContent';
export const VIRTUAL_MODULE_ID = 'astro:content';
export const LINKS_PLACEHOLDER = '@@ASTRO-LINKS@@';
export const STYLES_PLACEHOLDER = '@@ASTRO-STYLES@@';
export const SCRIPTS_PLACEHOLDER = '@@ASTRO-SCRIPTS@@';

export const CONTENT_TYPES_FILE = 'types.d.ts';
4 changes: 2 additions & 2 deletions packages/astro/src/content/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
export { createContentTypesGenerator } from './types-generator.js';
export { contentObservable, getContentPaths, getDotAstroTypeReference } from './utils.js';
export {
astroBundleDelayedAssetPlugin,
astroDelayedAssetPlugin,
astroContentProdBundlePlugin,
astroContentAssetPropagationPlugin,
} from './vite-plugin-content-assets.js';
export { astroContentServerPlugin } from './vite-plugin-content-server.js';
export { astroContentVirtualModPlugin } from './vite-plugin-content-virtual-mod.js';
9 changes: 7 additions & 2 deletions packages/astro/src/content/internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
createHeadAndContent,
renderComponent,
renderStyleElement,
renderScriptElement,
renderTemplate,
renderUniqueStylesheet,
unescapeHTML,
Expand Down Expand Up @@ -127,7 +128,8 @@ async function render({
const Content = createComponent({
factory(result, props, slots) {
let styles = '',
links = '';
links = '',
scripts = '';
if (Array.isArray(mod?.collectedStyles)) {
styles = mod.collectedStyles.map((style: any) => renderStyleElement(style)).join('');
}
Expand All @@ -140,9 +142,12 @@ async function render({
})
.join('');
}
if (Array.isArray(mod?.collectedScripts)) {
scripts = mod.collectedScripts.map((script: any) => renderScriptElement(script)).join('');
}

return createHeadAndContent(
unescapeHTML(styles + links) as any,
unescapeHTML(styles + links + scripts) as any,
renderTemplate`${renderComponent(result, 'Content', mod.Content, props, slots)}`
);
},
Expand Down
2 changes: 1 addition & 1 deletion packages/astro/src/content/template/virtual-mod.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const collectionToEntryMap = createCollectionToGlobResultMap({
});

const renderEntryGlob = import.meta.glob('@@RENDER_ENTRY_GLOB_PATH@@', {
query: { astroAssetSsr: true },
query: { astroPropagatedAssets: true },
});
const collectionToRenderEntryMap = createCollectionToGlobResultMap({
globResult: renderEntryGlob,
Expand Down
30 changes: 16 additions & 14 deletions packages/astro/src/content/vite-plugin-content-assets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,45 +5,48 @@ import { BuildInternals, getPageDataByViteID } from '../core/build/internal.js';
import type { ModuleLoader } from '../core/module-loader/loader.js';
import { createViteLoader } from '../core/module-loader/vite.js';
import { getStylesForURL } from '../core/render/dev/css.js';
import { getScriptsForURL } from '../core/render/dev/scripts.js';
import {
contentFileExts,
DELAYED_ASSET_FLAG,
PROPAGATED_ASSET_FLAG,
LINKS_PLACEHOLDER,
SCRIPTS_PLACEHOLDER,
STYLES_PLACEHOLDER,
} from './consts.js';

function isDelayedAsset(viteId: string): boolean {
function isPropagatedAsset(viteId: string): boolean {
const url = new URL(viteId, 'file://');
return (
url.searchParams.has(DELAYED_ASSET_FLAG) &&
url.searchParams.has(PROPAGATED_ASSET_FLAG) &&
contentFileExts.some((ext) => url.pathname.endsWith(ext))
);
}

export function astroDelayedAssetPlugin({ mode }: { mode: string }): Plugin {
export function astroContentAssetPropagationPlugin({ mode }: { mode: string }): Plugin {
let devModuleLoader: ModuleLoader;
return {
name: 'astro-delayed-asset-plugin',
name: 'astro:content-asset-propagation',
enforce: 'pre',
configureServer(server) {
if (mode === 'dev') {
devModuleLoader = createViteLoader(server);
}
},
load(id) {
if (isDelayedAsset(id)) {
if (isPropagatedAsset(id)) {
const basePath = id.split('?')[0];
const code = `
export { Content, getHeadings, frontmatter } from ${JSON.stringify(basePath)};
export const collectedLinks = ${JSON.stringify(LINKS_PLACEHOLDER)};
export const collectedStyles = ${JSON.stringify(STYLES_PLACEHOLDER)};
export const collectedScripts = ${JSON.stringify(SCRIPTS_PLACEHOLDER)};
`;
return { code };
}
},
async transform(code, id, options) {
if (!options?.ssr) return;
if (devModuleLoader && isDelayedAsset(id)) {
if (devModuleLoader && isPropagatedAsset(id)) {
const basePath = id.split('?')[0];
if (!devModuleLoader.getModuleById(basePath)?.ssrModule) {
await devModuleLoader.import(basePath);
Expand All @@ -54,23 +57,22 @@ export function astroDelayedAssetPlugin({ mode }: { mode: string }): Plugin {
'development'
);

const hoistedScripts = await getScriptsForURL(pathToFileURL(basePath), devModuleLoader);

return {
code: code
.replace(JSON.stringify(LINKS_PLACEHOLDER), JSON.stringify([...urls]))
.replace(JSON.stringify(STYLES_PLACEHOLDER), JSON.stringify([...stylesMap.values()])),
.replace(JSON.stringify(STYLES_PLACEHOLDER), JSON.stringify([...stylesMap.values()]))
.replace(JSON.stringify(SCRIPTS_PLACEHOLDER), JSON.stringify([...hoistedScripts])),
};
}
},
};
}

export function astroBundleDelayedAssetPlugin({
internals,
}: {
internals: BuildInternals;
}): Plugin {
export function astroContentProdBundlePlugin({ internals }: { internals: BuildInternals }): Plugin {
return {
name: 'astro-bundle-delayed-asset-plugin',
name: 'astro:content-prod-bundle',
async generateBundle(_options, bundle) {
for (const [_, chunk] of Object.entries(bundle)) {
if (chunk.type === 'chunk' && chunk.code.includes(LINKS_PLACEHOLDER)) {
Expand Down
4 changes: 2 additions & 2 deletions packages/astro/src/core/build/static-build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import fs from 'fs';
import { bgGreen, bgMagenta, black, dim } from 'kleur/colors';
import { fileURLToPath } from 'url';
import * as vite from 'vite';
import { astroBundleDelayedAssetPlugin } from '../../content/index.js';
import { astroContentProdBundlePlugin } from '../../content/index.js';
import {
BuildInternals,
createBuildInternals,
Expand Down Expand Up @@ -165,7 +165,7 @@ async function ssrBuild(opts: StaticBuildOptions, internals: BuildInternals, inp
}),
vitePluginPrerender(opts, internals),
...(viteConfig.plugins || []),
astroBundleDelayedAssetPlugin({ internals }),
astroContentProdBundlePlugin({ internals }),
// SSR needs to be last
ssr && vitePluginSSR(internals, settings.adapter!),
],
Expand Down
8 changes: 4 additions & 4 deletions packages/astro/src/core/build/vite-plugin-css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { isCSSRequest } from '../render/util.js';
import type { BuildInternals } from './internal';
import type { PageBuildData, StaticBuildOptions } from './types';

import { DELAYED_ASSET_FLAG } from '../../content/consts.js';
import { PROPAGATED_ASSET_FLAG } from '../../content/consts.js';
import * as assetName from './css-asset-name.js';
import { moduleIsTopLevelPage, walkParentInfos } from './graph.js';
import {
Expand Down Expand Up @@ -79,7 +79,7 @@ export function rollupPluginAstroBuildCSS(options: PluginOptions): VitePlugin[]
for (const [pageInfo] of walkParentInfos(id, {
getModuleInfo: args[0].getModuleInfo,
})) {
if (new URL(pageInfo.id, 'file://').searchParams.has(DELAYED_ASSET_FLAG)) {
if (new URL(pageInfo.id, 'file://').searchParams.has(PROPAGATED_ASSET_FLAG)) {
// Split delayed assets to separate modules
// so they can be injected where needed
return createNameHash(id, [id]);
Expand Down Expand Up @@ -172,10 +172,10 @@ export function rollupPluginAstroBuildCSS(options: PluginOptions): VitePlugin[]
id,
this,
function until(importer) {
return new URL(importer, 'file://').searchParams.has(DELAYED_ASSET_FLAG);
return new URL(importer, 'file://').searchParams.has(PROPAGATED_ASSET_FLAG);
}
)) {
if (new URL(pageInfo.id, 'file://').searchParams.has(DELAYED_ASSET_FLAG)) {
if (new URL(pageInfo.id, 'file://').searchParams.has(PROPAGATED_ASSET_FLAG)) {
for (const parent of walkParentInfos(id, this)) {
const parentInfo = parent[0];
if (moduleIsTopLevelPage(parentInfo)) {
Expand Down
4 changes: 2 additions & 2 deletions packages/astro/src/core/create-vite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { crawlFrameworkPkgs } from 'vitefu';
import {
astroContentServerPlugin,
astroContentVirtualModPlugin,
astroDelayedAssetPlugin,
astroContentAssetPropagationPlugin,
} from '../content/index.js';
import astroPostprocessVitePlugin from '../vite-plugin-astro-postprocess/index.js';
import { vitePluginAstroServer } from '../vite-plugin-astro-server/index.js';
Expand Down Expand Up @@ -106,7 +106,7 @@ export async function createVite(
astroInjectEnvTsPlugin({ settings, logging, fs }),
astroContentVirtualModPlugin({ settings }),
astroContentServerPlugin({ fs, settings, logging, mode }),
astroDelayedAssetPlugin({ mode }),
astroContentAssetPropagationPlugin({ mode }),
],
publicDir: fileURLToPath(settings.config.publicDir),
root: fileURLToPath(settings.config.root),
Expand Down
4 changes: 2 additions & 2 deletions packages/astro/src/core/render/dev/vite.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { ModuleLoader, ModuleNode } from '../../module-loader/index';

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

const moduleEntriesForId = isRootFile
? // "getModulesByFile" pulls from a delayed module cache (fun implementation detail),
Expand Down
1 change: 1 addition & 0 deletions packages/astro/src/runtime/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export {
renderPage,
renderSlot,
renderStyleElement,
renderScriptElement,
renderTemplate as render,
renderTemplate,
renderToString,
Expand Down
2 changes: 1 addition & 1 deletion packages/astro/src/runtime/server/render/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@ export { renderHTMLElement } from './dom.js';
export { maybeRenderHead, renderHead } from './head.js';
export { renderPage } from './page.js';
export { renderSlot } from './slot.js';
export { renderStyleElement, renderUniqueStylesheet } from './tags.js';
export { renderStyleElement, renderScriptElement, renderUniqueStylesheet } from './tags.js';
export type { RenderInstruction } from './types';
export { addAttribute, defineScriptVars, voidElementNames } from './util.js';
9 changes: 8 additions & 1 deletion packages/astro/src/runtime/server/render/tags.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { SSRResult } from '../../../@types/astro';
import { SSRElement, SSRResult } from '../../../@types/astro';
import { renderElement } from './util.js';

const stylesheetRel = 'stylesheet';
Expand All @@ -10,6 +10,13 @@ export function renderStyleElement(children: string) {
});
}

export function renderScriptElement({ props, children }: SSRElement) {
return renderElement('script', {
props,
children,
});
}

export function renderStylesheet({ href }: { href: string }) {
return renderElement(
'link',
Expand Down
Loading