refactor: move markdoc transform to build time

This commit is contained in:
bholmesdev 2023-03-01 13:35:53 -05:00
parent c7e4236ed7
commit d66ee0dcd0
4 changed files with 40 additions and 22 deletions

View file

@ -3,5 +3,20 @@ import markdoc from '@astrojs/markdoc';
// https://astro.build/config // https://astro.build/config
export default defineConfig({ export default defineConfig({
integrations: [markdoc()], integrations: [
markdoc({
variables: {
revealSecret: true,
},
tags: {
aside: {
render: 'Aside',
attributes: {
type: { type: String },
title: { type: String },
},
},
},
}),
],
}); });

View file

@ -11,19 +11,6 @@ const { Content } = await entry.render();
--- ---
<Content <Content
config={{
// Accepts all Markdoc configuration options
// See https://markdoc.dev/docs/config#full-example
tags: {
aside: {
render: 'Aside',
attributes: {
type: { type: String },
title: { type: String },
},
},
},
}}
components={{ components={{
// Pass a mapping from the component name // Pass a mapping from the component name
// To an Astro or UI component import // To an Astro or UI component import

View file

@ -1,20 +1,22 @@
import type { AstroIntegration } from 'astro'; import type { AstroIntegration } from 'astro';
import type { InlineConfig } from 'vite'; import type { InlineConfig } from 'vite';
import type { Config as _MarkdocConfig } from '@markdoc/markdoc'; import type { Config, Config as _MarkdocConfig } from '@markdoc/markdoc';
import _Markdoc from '@markdoc/markdoc'; import _Markdoc from '@markdoc/markdoc';
import { parseFrontmatter } from './utils.js'; import { parseFrontmatter } from './utils.js';
import { fileURLToPath } from 'node:url'; import { fileURLToPath } from 'node:url';
import fs from 'node:fs'; import fs from 'node:fs';
export default function markdoc(): AstroIntegration { export default function markdoc(markdocConfig: Config): AstroIntegration {
const entryBodyByFileIdCache = new Map<string, string>();
return { return {
name: '@astrojs/markdoc', name: '@astrojs/markdoc',
hooks: { hooks: {
'astro:config:setup': async ({ updateConfig, config, addContentEntryType, command }: any) => { 'astro:config:setup': async ({ updateConfig, config, addContentEntryType }: any) => {
const contentEntryType = { const contentEntryType = {
extensions: ['.mdoc'], extensions: ['.mdoc'],
async getEntryInfo({ fileUrl, contents }: { fileUrl: URL; contents: string }) { getEntryInfo({ fileUrl, contents }: { fileUrl: URL; contents: string }) {
const parsed = parseFrontmatter(contents, fileURLToPath(fileUrl)); const parsed = parseFrontmatter(contents, fileURLToPath(fileUrl));
entryBodyByFileIdCache.set(fileUrl.pathname, parsed.content);
return { return {
data: parsed.data, data: parsed.data,
body: parsed.content, body: parsed.content,
@ -35,9 +37,24 @@ export default function markdoc(): AstroIntegration {
name: '@astrojs/markdoc', name: '@astrojs/markdoc',
async transform(code, id) { async transform(code, id) {
if (!id.endsWith('.mdoc')) return; if (!id.endsWith('.mdoc')) return;
return `import { jsx as h } from 'astro/jsx-runtime';\nimport { Markdoc } from '@astrojs/markdoc';\nimport { Renderer } from '@astrojs/markdoc/components';\nexport const body = ${JSON.stringify(
code const body = entryBodyByFileIdCache.get(id);
)};\nexport function getParsed() { return Markdoc.parse(body); }\nexport function getTransformed(inlineConfig) { return Markdoc.transform(getParsed(), inlineConfig) }\nexport async function Content ({ config, components }) { return h(Renderer, { content: getTransformed(config), components }); }\nContent[Symbol.for('astro.needsHeadRendering')] = true;`; if (!body) {
// Cache entry should exist if `getCollection()` was called
// (see `getEntryInfo()` above)
// If not, the user probably tried to import directly.
throw new Error(
`Unable to render ${JSON.stringify(
id.replace(config.root.pathname, '')
)}. If you tried to import this file directly, please use a Content Collection query instead. See https://docs.astro.build/en/guides/content-collections/#rendering-content-to-html for more information.`
);
}
const rawAst = Markdoc.parse(body);
const ast = Markdoc.transform(rawAst, markdocConfig);
return `import { jsx as h } from 'astro/jsx-runtime';\nimport { Markdoc } from '@astrojs/markdoc';\nimport { Renderer } from '@astrojs/markdoc/components';\nconst ast = ${JSON.stringify(
ast
)};\nexport async function Content ({ components }) { return h(Renderer, { content: ast, components }); }\nContent[Symbol.for('astro.needsHeadRendering')] = true;`;
}, },
}, },
], ],

View file

@ -12,7 +12,6 @@ declare module 'astro:content' {
interface Render { interface Render {
'.mdoc': Promise<{ '.mdoc': Promise<{
Content(props: { Content(props: {
config?: import('@astrojs/markdoc').MarkdocConfig;
components?: Record<string, ComponentRenderer>; components?: Record<string, ComponentRenderer>;
}): import('astro').MarkdownInstance<{}>['Content']; }): import('astro').MarkdownInstance<{}>['Content'];
}>; }>;