diff --git a/packages/astro/package.json b/packages/astro/package.json index 474faa1f410d..5d227208d346 100644 --- a/packages/astro/package.json +++ b/packages/astro/package.json @@ -239,4 +239,4 @@ "publishConfig": { "provenance": true } -} +} \ No newline at end of file diff --git a/packages/astro/src/content/loaders/glob.ts b/packages/astro/src/content/loaders/glob.ts index 578f13057baf..4a4ecbcac8d3 100644 --- a/packages/astro/src/content/loaders/glob.ts +++ b/packages/astro/src/content/loaders/glob.ts @@ -128,17 +128,7 @@ export function glob(globOptions: GlobOptions): Loader { data, filePath, }); - - if (entryType.extensions.includes('.mdx')) { - store.set({ - id, - data: parsedData, - body, - filePath: relativePath, - digest, - deferredRender: true, - }); - } else if (entryType.getRenderFunction) { + if (entryType.getRenderFunction) { let render = renderFunctionByContentType.get(entryType); if (!render) { render = await entryType.getRenderFunction(settings); @@ -170,6 +160,16 @@ export function glob(globOptions: GlobOptions): Loader { if (rendered?.metadata?.imagePaths?.length) { store.addAssetImports(rendered.metadata.imagePaths, relativePath); } + // todo: add an explicit way to opt in to deferred rendering + } else if ('contentModuleTypes' in entryType) { + store.set({ + id, + data: parsedData, + body, + filePath: relativePath, + digest, + deferredRender: true, + }); } else { store.set({ id, data: parsedData, body, filePath: relativePath, digest }); } diff --git a/packages/astro/test/content-layer-markdoc.test.js b/packages/astro/test/content-layer-markdoc.test.js new file mode 100644 index 000000000000..c5279b9e7522 --- /dev/null +++ b/packages/astro/test/content-layer-markdoc.test.js @@ -0,0 +1,88 @@ +import assert from 'node:assert/strict'; +import { after, before, describe, it } from 'node:test'; +import * as cheerio from 'cheerio'; +import { loadFixture } from './test-utils.js'; + +describe('Content layer markdoc', () => { + let fixture; + + before(async () => { + fixture = await loadFixture({ + root: './fixtures/content-layer-markdoc/', + }); + }); + + describe('dev', () => { + let devServer; + + before(async () => { + devServer = await fixture.startDevServer(); + }); + + after(async () => { + await devServer.stop(); + }); + + it('renders content - with components', async () => { + const res = await fixture.fetch('/'); + const html = await res.text(); + + renderComponentsChecks(html); + }); + + it('renders content - with components inside partials', async () => { + const res = await fixture.fetch('/'); + const html = await res.text(); + + renderComponentsInsidePartialsChecks(html); + }); + }); + + describe('build', () => { + before(async () => { + await fixture.build(); + }); + + it('renders content - with components', async () => { + const html = await fixture.readFile('/index.html'); + + renderComponentsChecks(html); + }); + + it('renders content - with components inside partials', async () => { + const html = await fixture.readFile('/index.html'); + + renderComponentsInsidePartialsChecks(html); + }); + }); +}); + +/** @param {string} html */ +function renderComponentsChecks(html) { + const $ = cheerio.load(html); + const h2 = $('h2'); + assert.equal(h2.text(), 'Post with components'); + + // Renders custom shortcode component + const marquee = $('marquee'); + assert.notEqual(marquee, null); + assert.equal(marquee.attr('data-custom-marquee'), ''); + + // Renders Astro Code component + const pre = $('pre'); + assert.notEqual(pre, null); + assert.ok(pre.hasClass('github-dark')); + assert.ok(pre.hasClass('astro-code')); +} + +/** @param {string} html */ +function renderComponentsInsidePartialsChecks(html) { + const $ = cheerio.load(html); + // renders Counter.tsx + const button = $('#counter'); + assert.equal(button.text(), '1'); + + // renders DeeplyNested.astro + const deeplyNested = $('#deeply-nested'); + assert.equal(deeplyNested.text(), 'Deeply nested partial'); +} diff --git a/packages/astro/test/content-layer-render.test.js b/packages/astro/test/content-layer-render.test.js index ab38bb1da2b4..fa743e719ca4 100644 --- a/packages/astro/test/content-layer-render.test.js +++ b/packages/astro/test/content-layer-render.test.js @@ -2,7 +2,7 @@ import assert from 'node:assert/strict'; import { after, before, describe, it } from 'node:test'; import { loadFixture } from './test-utils.js'; -describe('Content Layer dev', () => { +describe('Content Layer MDX rendering dev', () => { /** @type {import("./test-utils.js").Fixture} */ let fixture; @@ -10,7 +10,6 @@ describe('Content Layer dev', () => { before(async () => { fixture = await loadFixture({ root: './fixtures/content-layer-rendering/', - cacheDir: './fixtures/content-layer-rendering/.cache', }); devServer = await fixture.startDevServer(); }); @@ -27,13 +26,12 @@ describe('Content Layer dev', () => { }); }); -describe('Content Layer build', () => { +describe('Content Layer MDX rendering build', () => { /** @type {import("./test-utils.js").Fixture} */ let fixture; before(async () => { fixture = await loadFixture({ root: './fixtures/content-layer-rendering/', - cacheDir: './fixtures/content-layer-rendering/.cache', }); await fixture.build(); }); diff --git a/packages/astro/test/fixtures/content-layer-markdoc/astro.config.mjs b/packages/astro/test/fixtures/content-layer-markdoc/astro.config.mjs new file mode 100644 index 000000000000..bbb19ad302db --- /dev/null +++ b/packages/astro/test/fixtures/content-layer-markdoc/astro.config.mjs @@ -0,0 +1,9 @@ +import markdoc from '@astrojs/markdoc'; +import preact from '@astrojs/preact'; +import { defineConfig } from 'astro/config'; + +// https://astro.build/config +export default defineConfig({ + integrations: [markdoc(), preact()], + experimental: { contentLayer: true } +}); diff --git a/packages/astro/test/fixtures/content-layer-markdoc/content/_nested.mdoc b/packages/astro/test/fixtures/content-layer-markdoc/content/_nested.mdoc new file mode 100644 index 000000000000..68f529280124 --- /dev/null +++ b/packages/astro/test/fixtures/content-layer-markdoc/content/_nested.mdoc @@ -0,0 +1,3 @@ +Render components from a deeply nested partial: + +{% deeply-nested /%} diff --git a/packages/astro/test/fixtures/content-layer-markdoc/content/blog/_counter.mdoc b/packages/astro/test/fixtures/content-layer-markdoc/content/blog/_counter.mdoc new file mode 100644 index 000000000000..4a015695c68e --- /dev/null +++ b/packages/astro/test/fixtures/content-layer-markdoc/content/blog/_counter.mdoc @@ -0,0 +1,7 @@ +# Hello from a partial! + +Render a component from a partial: + +{% counter /%} + +{% partial file="../_nested.mdoc" /%} diff --git a/packages/astro/test/fixtures/content-layer-markdoc/content/blog/with-components.mdoc b/packages/astro/test/fixtures/content-layer-markdoc/content/blog/with-components.mdoc new file mode 100644 index 000000000000..eb7d20426e59 --- /dev/null +++ b/packages/astro/test/fixtures/content-layer-markdoc/content/blog/with-components.mdoc @@ -0,0 +1,19 @@ +--- +title: Post with components +--- + +## Post with components + +This uses a custom marquee component with a shortcode: + +{% marquee-element direction="right" %} +I'm a marquee too! +{% /marquee-element %} + +{% partial file="_counter.mdoc" /%} + +And a code component for code blocks: + +```js +const isRenderedWithShiki = true; +``` diff --git a/packages/astro/test/fixtures/content-layer-markdoc/markdoc.config.ts b/packages/astro/test/fixtures/content-layer-markdoc/markdoc.config.ts new file mode 100644 index 000000000000..6093ec5938a5 --- /dev/null +++ b/packages/astro/test/fixtures/content-layer-markdoc/markdoc.config.ts @@ -0,0 +1,32 @@ +import { Markdoc, component, defineMarkdocConfig } from '@astrojs/markdoc/config'; + +export default defineMarkdocConfig({ + nodes: { + fence: { + render: component('./src/components/Code.astro'), + attributes: { + language: { type: String }, + content: { type: String }, + }, + }, + }, + tags: { + 'marquee-element': { + render: component('./src/components/CustomMarquee.astro'), + attributes: { + direction: { + type: String, + default: 'left', + matches: ['left', 'right', 'up', 'down'], + errorLevel: 'critical', + }, + }, + }, + counter: { + render: component('./src/components/CounterWrapper.astro'), + }, + 'deeply-nested': { + render: component('./src/components/DeeplyNested.astro'), + }, + }, +}); diff --git a/packages/astro/test/fixtures/content-layer-markdoc/package.json b/packages/astro/test/fixtures/content-layer-markdoc/package.json new file mode 100644 index 000000000000..91ca2f8c9c00 --- /dev/null +++ b/packages/astro/test/fixtures/content-layer-markdoc/package.json @@ -0,0 +1,11 @@ +{ + "name": "@test/content-layer-markdoc", + "version": "0.0.0", + "private": true, + "dependencies": { + "@astrojs/markdoc": "workspace:*", + "@astrojs/preact": "workspace:*", + "astro": "workspace:*", + "preact": "^10.23.1" + } +} \ No newline at end of file diff --git a/packages/astro/test/fixtures/content-layer-markdoc/src/components/Code.astro b/packages/astro/test/fixtures/content-layer-markdoc/src/components/Code.astro new file mode 100644 index 000000000000..18bf1399f22e --- /dev/null +++ b/packages/astro/test/fixtures/content-layer-markdoc/src/components/Code.astro @@ -0,0 +1,12 @@ +--- +import { Code } from 'astro/components'; + +type Props = { + content: string; + language: string; +} + +const { content, language } = Astro.props as Props; +--- + + diff --git a/packages/astro/test/fixtures/content-layer-markdoc/src/components/Counter.tsx b/packages/astro/test/fixtures/content-layer-markdoc/src/components/Counter.tsx new file mode 100644 index 000000000000..f1e239718cf8 --- /dev/null +++ b/packages/astro/test/fixtures/content-layer-markdoc/src/components/Counter.tsx @@ -0,0 +1,10 @@ +import { useState } from 'preact/hooks'; + +export default function Counter() { + const [count, setCount] = useState(1); + return ( + + ); +} diff --git a/packages/astro/test/fixtures/content-layer-markdoc/src/components/CounterWrapper.astro b/packages/astro/test/fixtures/content-layer-markdoc/src/components/CounterWrapper.astro new file mode 100644 index 000000000000..e45ac6438152 --- /dev/null +++ b/packages/astro/test/fixtures/content-layer-markdoc/src/components/CounterWrapper.astro @@ -0,0 +1,5 @@ +--- +import Counter from './Counter'; +--- + + diff --git a/packages/astro/test/fixtures/content-layer-markdoc/src/components/CustomMarquee.astro b/packages/astro/test/fixtures/content-layer-markdoc/src/components/CustomMarquee.astro new file mode 100644 index 000000000000..3108b997354c --- /dev/null +++ b/packages/astro/test/fixtures/content-layer-markdoc/src/components/CustomMarquee.astro @@ -0,0 +1 @@ + diff --git a/packages/astro/test/fixtures/content-layer-markdoc/src/components/DeeplyNested.astro b/packages/astro/test/fixtures/content-layer-markdoc/src/components/DeeplyNested.astro new file mode 100644 index 000000000000..eb23f675a0f6 --- /dev/null +++ b/packages/astro/test/fixtures/content-layer-markdoc/src/components/DeeplyNested.astro @@ -0,0 +1,5 @@ +--- + +--- + +

Deeply nested partial

diff --git a/packages/astro/test/fixtures/content-layer-markdoc/src/content/config.ts b/packages/astro/test/fixtures/content-layer-markdoc/src/content/config.ts new file mode 100644 index 000000000000..18ead9aa161f --- /dev/null +++ b/packages/astro/test/fixtures/content-layer-markdoc/src/content/config.ts @@ -0,0 +1,11 @@ +import { defineCollection } from 'astro:content'; +import { glob } from 'astro/loaders'; + +const blog = defineCollection({ + loader: glob({ + pattern: '*.mdoc', + base: 'content/blog', + }), +}); + +export const collections = { blog }; diff --git a/packages/astro/test/fixtures/content-layer-markdoc/src/pages/index.astro b/packages/astro/test/fixtures/content-layer-markdoc/src/pages/index.astro new file mode 100644 index 000000000000..5c7747eef923 --- /dev/null +++ b/packages/astro/test/fixtures/content-layer-markdoc/src/pages/index.astro @@ -0,0 +1,19 @@ +--- +import { getEntry, render } from "astro:content"; + +const post = await getEntry('blog', 'with-components'); +const { Content } = await render(post); +--- + + + + + + + + Content + + + + + diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4045a204d104..274af7480447 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2722,6 +2722,21 @@ importers: specifier: workspace:* version: link:../../.. + packages/astro/test/fixtures/content-layer-markdoc: + dependencies: + '@astrojs/markdoc': + specifier: workspace:* + version: link:../../../../integrations/markdoc + '@astrojs/preact': + specifier: workspace:* + version: link:../../../../integrations/preact + astro: + specifier: workspace:* + version: link:../../.. + preact: + specifier: ^10.23.1 + version: 10.23.1 + packages/astro/test/fixtures/content-layer-rendering: dependencies: '@astrojs/mdx':