Skip to content

Commit ed7bbd9

Browse files
authored
fix(markdoc): use astro components defined with extends (#11846)
1 parent 543e8f5 commit ed7bbd9

File tree

11 files changed

+176
-2
lines changed

11 files changed

+176
-2
lines changed

.changeset/good-adults-punch.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@astrojs/markdoc': patch
3+
---
4+
5+
Fixes an issue preventing to use Astro components as Markdoc tags and nodes when configured using the `extends` property.

packages/integrations/markdoc/src/content-entry-type.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,13 +78,13 @@ export async function getContentEntryType({
7878
// Only include component imports for tags used in the document.
7979
// Avoids style and script bleed.
8080
for (const tag of usedTags) {
81-
const render = userMarkdocConfig.tags?.[tag]?.render;
81+
const render = markdocConfig.tags?.[tag]?.render;
8282
if (isComponentConfig(render)) {
8383
componentConfigByTagMap[tag] = render;
8484
}
8585
}
8686
let componentConfigByNodeMap: Record<string, ComponentConfig> = {};
87-
for (const [nodeType, schema] of Object.entries(userMarkdocConfig.nodes ?? {})) {
87+
for (const [nodeType, schema] of Object.entries(markdocConfig.nodes ?? {})) {
8888
const render = schema?.render;
8989
if (isComponentConfig(render)) {
9090
componentConfigByNodeMap[nodeType] = render;
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import markdoc from '@astrojs/markdoc';
2+
import { defineConfig } from 'astro/config';
3+
4+
// https://astro.build/config
5+
export default defineConfig({
6+
integrations: [markdoc()],
7+
});
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { component, defineMarkdocConfig } from '@astrojs/markdoc/config';
2+
3+
export default defineMarkdocConfig({
4+
extends: [preset()],
5+
});
6+
7+
function preset() {
8+
return {
9+
nodes: {
10+
fence: {
11+
render: component('./src/components/Code.astro'),
12+
attributes: {
13+
language: { type: String },
14+
content: { type: String },
15+
},
16+
},
17+
},
18+
tags: {
19+
'marquee-element': {
20+
render: component('./src/components/CustomMarquee.astro'),
21+
attributes: {
22+
direction: {
23+
type: String,
24+
default: 'left',
25+
matches: ['left', 'right', 'up', 'down'],
26+
},
27+
},
28+
},
29+
},
30+
}
31+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"name": "@test/markdoc-render-with-extends-components",
3+
"version": "0.0.0",
4+
"private": true,
5+
"dependencies": {
6+
"@astrojs/markdoc": "workspace:*",
7+
"astro": "workspace:*"
8+
}
9+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
import { Code } from 'astro/components';
3+
4+
type Props = {
5+
content: string;
6+
language: string;
7+
}
8+
9+
const { content, language } = Astro.props as Props;
10+
---
11+
12+
<Code lang={language} code={content} />
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<marquee data-custom-marquee {...Astro.props}><slot /></marquee>
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
title: Post with components
3+
---
4+
5+
## Post with components
6+
7+
This uses a custom marquee component with a shortcode:
8+
9+
{% marquee-element direction="right" %}
10+
I'm a marquee too!
11+
{% /marquee-element %}
12+
13+
And a code component for code blocks:
14+
15+
```js
16+
const isRenderedWithShiki = true;
17+
```
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
---
2+
import { getEntryBySlug } from "astro:content";
3+
4+
const post = await getEntryBySlug('blog', 'with-components');
5+
const { Content } = await post.render();
6+
---
7+
8+
<!DOCTYPE html>
9+
<html lang="en">
10+
<head>
11+
<meta charset="UTF-8">
12+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
13+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
14+
<title>Content</title>
15+
</head>
16+
<body>
17+
<Content />
18+
</body>
19+
</html>
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import assert from 'node:assert/strict';
2+
import { after, before, describe, it } from 'node:test';
3+
import { parseHTML } from 'linkedom';
4+
import { loadFixture } from '../../../astro/test/test-utils.js';
5+
6+
const root = new URL('./fixtures/render-with-extends-components/', import.meta.url);
7+
8+
describe('Markdoc - render components defined in `extends`', () => {
9+
let fixture;
10+
11+
before(async () => {
12+
fixture = await loadFixture({
13+
root,
14+
});
15+
});
16+
17+
describe('dev', () => {
18+
let devServer;
19+
20+
before(async () => {
21+
devServer = await fixture.startDevServer();
22+
});
23+
24+
after(async () => {
25+
await devServer.stop();
26+
});
27+
28+
it('renders content - with components', async () => {
29+
const res = await fixture.fetch('/');
30+
const html = await res.text();
31+
32+
renderComponentsChecks(html);
33+
});
34+
});
35+
36+
describe('build', () => {
37+
before(async () => {
38+
await fixture.build();
39+
});
40+
41+
it('renders content - with components', async () => {
42+
const html = await fixture.readFile('/index.html');
43+
44+
renderComponentsChecks(html);
45+
});
46+
});
47+
});
48+
49+
/** @param {string} html */
50+
function renderComponentsChecks(html) {
51+
const { document } = parseHTML(html);
52+
const h2 = document.querySelector('h2');
53+
assert.equal(h2.textContent, 'Post with components');
54+
55+
// Renders custom shortcode component
56+
const marquee = document.querySelector('marquee');
57+
assert.notEqual(marquee, null);
58+
assert.equal(marquee.hasAttribute('data-custom-marquee'), true);
59+
60+
// Renders Astro Code component
61+
const pre = document.querySelector('pre');
62+
assert.notEqual(pre, null);
63+
assert.equal(pre.className, 'astro-code github-dark');
64+
}

0 commit comments

Comments
 (0)