diff options
author | 2023-05-31 19:18:07 -0400 | |
---|---|---|
committer | 2023-05-31 19:18:07 -0400 | |
commit | 339529fc820bac2d514b63198ecf54a1d88c0917 (patch) | |
tree | 8b553c0df30c1aa60a037fb915bcf7fdfaea945f /packages/integrations/markdoc/components/TreeNode.ts | |
parent | c4c086e5e70bdd347e1c7601212a04b4f523578e (diff) | |
download | astro-339529fc820bac2d514b63198ecf54a1d88c0917.tar.gz astro-339529fc820bac2d514b63198ecf54a1d88c0917.tar.zst astro-339529fc820bac2d514b63198ecf54a1d88c0917.zip |
Markdoc asset bleed, second try (#7185)
* Revert "revert: markdoc asset bleed (#7178)"
This reverts commit 57e65d247f67de61bcc3a585c2254feb61ed2e74.
* fix: missing result param on `renderUniqueStylesheet`
* test: bundled styles (fails!)
* fix: use `type: 'external'` for links
* fix: split Astro components from markdoc config
* test: style bleed (it fails...)
* chore: remove unused util
* fix: revert entry change
* Stop traversing the graph when you encounter a propagated asset
* chore: cleanup unused `entry` prop
* refactor: add isPropagatedAssetsMod check
* chore: remove unused import
* chore: changeset
* Normalize path using vite
* Update packages/integrations/markdoc/src/index.ts
Co-authored-by: Ben Holmes <hey@bholmes.dev>
---------
Co-authored-by: Matthew Phillips <matthew@skypack.dev>
Co-authored-by: bholmesdev <bholmesdev@gmail.com>
Co-authored-by: Matthew Phillips <matthew@matthewphillips.info>
Diffstat (limited to 'packages/integrations/markdoc/components/TreeNode.ts')
-rw-r--r-- | packages/integrations/markdoc/components/TreeNode.ts | 103 |
1 files changed, 92 insertions, 11 deletions
diff --git a/packages/integrations/markdoc/components/TreeNode.ts b/packages/integrations/markdoc/components/TreeNode.ts index d12180a18..8ad778063 100644 --- a/packages/integrations/markdoc/components/TreeNode.ts +++ b/packages/integrations/markdoc/components/TreeNode.ts @@ -6,6 +6,11 @@ import { createComponent, renderComponent, render, + renderScriptElement, + renderUniqueStylesheet, + createHeadAndContent, + unescapeHTML, + renderTemplate, HTMLString, isHTMLString, } from 'astro/runtime/server/index.js'; @@ -18,6 +23,9 @@ export type TreeNode = | { type: 'component'; component: AstroInstance['default']; + collectedLinks?: string[]; + collectedStyles?: string[]; + collectedScripts?: string[]; props: Record<string, any>; children: TreeNode[]; } @@ -39,20 +47,66 @@ export const ComponentNode = createComponent({ )}`, }; if (treeNode.type === 'component') { - return renderComponent( - result, - treeNode.component.name, - treeNode.component, - treeNode.props, - slots + let styles = '', + links = '', + scripts = ''; + if (Array.isArray(treeNode.collectedStyles)) { + styles = treeNode.collectedStyles + .map((style: any) => + renderUniqueStylesheet(result, { + type: 'inline', + content: style, + }) + ) + .join(''); + } + if (Array.isArray(treeNode.collectedLinks)) { + links = treeNode.collectedLinks + .map((link: any) => { + return renderUniqueStylesheet(result, { + type: 'external', + src: link[0] === '/' ? link : '/' + link, + }); + }) + .join(''); + } + if (Array.isArray(treeNode.collectedScripts)) { + scripts = treeNode.collectedScripts + .map((script: any) => renderScriptElement(script)) + .join(''); + } + + const head = unescapeHTML(styles + links + scripts); + + let headAndContent = createHeadAndContent( + head, + renderTemplate`${renderComponent( + result, + treeNode.component.name, + treeNode.component, + treeNode.props, + slots + )}` ); + + // Let the runtime know that this component is being used. + result.propagators.set( + {}, + { + init() { + return headAndContent; + }, + } + ); + + return headAndContent; } return renderComponent(result, treeNode.tag, treeNode.tag, treeNode.attributes, slots); }, - propagation: 'none', + propagation: 'self', }); -export function createTreeNode(node: RenderableTreeNode | RenderableTreeNode[]): TreeNode { +export async function createTreeNode(node: RenderableTreeNode | RenderableTreeNode[]): TreeNode { if (isHTMLString(node)) { return { type: 'text', content: node as HTMLString }; } else if (typeof node === 'string' || typeof node === 'number') { @@ -62,16 +116,17 @@ export function createTreeNode(node: RenderableTreeNode | RenderableTreeNode[]): type: 'component', component: Fragment, props: {}, - children: node.map((child) => createTreeNode(child)), + children: await Promise.all(node.map((child) => createTreeNode(child))), }; } else if (node === null || typeof node !== 'object' || !Markdoc.Tag.isTag(node)) { return { type: 'text', content: '' }; } + const children = await Promise.all(node.children.map((child) => createTreeNode(child))); + if (typeof node.name === 'function') { const component = node.name; const props = node.attributes; - const children = node.children.map((child) => createTreeNode(child)); return { type: 'component', @@ -79,12 +134,38 @@ export function createTreeNode(node: RenderableTreeNode | RenderableTreeNode[]): props, children, }; + } else if (isPropagatedAssetsModule(node.name)) { + const { collectedStyles, collectedLinks, collectedScripts } = node.name; + const component = (await node.name.getMod())?.default ?? Fragment; + const props = node.attributes; + + return { + type: 'component', + component, + collectedStyles, + collectedLinks, + collectedScripts, + props, + children, + }; } else { return { type: 'element', tag: node.name, attributes: node.attributes, - children: node.children.map((child) => createTreeNode(child)), + children, }; } } + +type PropagatedAssetsModule = { + __astroPropagation: true; + getMod: () => Promise<AstroInstance['default']>; + collectedStyles: string[]; + collectedLinks: string[]; + collectedScripts: string[]; +}; + +function isPropagatedAssetsModule(module: any): module is PropagatedAssetsModule { + return typeof module === 'object' && module != null && '__astroPropagation' in module; +} |