From cfae9760b252052b6189e96398b819a4337634a8 Mon Sep 17 00:00:00 2001 From: Nate Moore Date: Tue, 24 May 2022 17:02:11 -0500 Subject: [PATCH] Improve Markdown + Components usage (#3410) * feat: use internal MDX tooling for markdown + components * fix: improve MD + component tests * chore: add changeset * fix: make tsc happy * fix(#3319): add regression test for component children * fix(markdown): support HTML comments in markdown * fix(#2474): ensure namespaced components are properly handled in markdown pages * fix(#3220): ensure html in markdown pages does not have extra surrounding space * fix(#3264): ensure that remark files pass in file information * fix(#3254): enable experimentalStaticExtraction for `.md` pages * fix: revert parsing change * fix: remove `markdown.mode` option --- .changeset/wicked-adults-pull.md | 6 ++ packages/astro/src/@types/astro.ts | 10 --- .../astro/src/vite-plugin-markdown/index.ts | 13 ++- packages/astro/test/astro-markdown.test.js | 49 ++++++++++- .../src/components/TextBlock.jsx | 20 +++++ .../astro-markdown/src/components/index.js | 5 ++ .../src/content/code-element.md | 3 + .../astro-markdown/src/pages/children.md | 12 +++ .../src/pages/code-element.astro | 7 ++ .../astro-markdown/src/pages/comment.md | 2 + .../src/pages/jsx-expressions.md | 4 +- .../astro-markdown/src/pages/namespace.md | 7 ++ .../astro-markdown/src/pages/script.md | 7 ++ .../fixtures/astro-markdown/src/pages/slug.md | 7 ++ .../astro-markdown/src/scripts/test.js | 1 + packages/markdown/remark/package.json | 13 ++- packages/markdown/remark/src/index.ts | 30 ++++--- .../markdown/remark/src/mdast-util-mdxish.ts | 18 +++++ .../remark/src/rehype-collect-headers.ts | 31 ++++++- .../markdown/remark/src/rehype-expressions.ts | 8 +- packages/markdown/remark/src/rehype-jsx.ts | 38 +++++++-- .../markdown/remark/src/remark-expressions.ts | 25 ------ packages/markdown/remark/src/remark-jsx.ts | 31 ------- .../remark/src/remark-mark-and-unravel.ts | 81 +++++++++++++++++++ packages/markdown/remark/src/remark-mdxish.ts | 15 ++++ packages/markdown/remark/src/remark-shiki.ts | 2 +- packages/markdown/remark/src/types.ts | 20 ++--- .../markdown/remark/test/components.test.js | 62 ++++++++++++++ .../markdown/remark/test/expressions.test.js | 40 +++++++++ packages/markdown/remark/test/plugins.test.js | 26 ++++++ pnpm-lock.yaml | 57 ++++++++++++- 31 files changed, 542 insertions(+), 108 deletions(-) create mode 100644 .changeset/wicked-adults-pull.md create mode 100644 packages/astro/test/fixtures/astro-markdown/src/components/TextBlock.jsx create mode 100644 packages/astro/test/fixtures/astro-markdown/src/components/index.js create mode 100644 packages/astro/test/fixtures/astro-markdown/src/content/code-element.md create mode 100644 packages/astro/test/fixtures/astro-markdown/src/pages/children.md create mode 100644 packages/astro/test/fixtures/astro-markdown/src/pages/code-element.astro create mode 100644 packages/astro/test/fixtures/astro-markdown/src/pages/comment.md create mode 100644 packages/astro/test/fixtures/astro-markdown/src/pages/namespace.md create mode 100644 packages/astro/test/fixtures/astro-markdown/src/pages/script.md create mode 100644 packages/astro/test/fixtures/astro-markdown/src/pages/slug.md create mode 100644 packages/astro/test/fixtures/astro-markdown/src/scripts/test.js create mode 100644 packages/markdown/remark/src/mdast-util-mdxish.ts delete mode 100644 packages/markdown/remark/src/remark-expressions.ts delete mode 100644 packages/markdown/remark/src/remark-jsx.ts create mode 100644 packages/markdown/remark/src/remark-mark-and-unravel.ts create mode 100644 packages/markdown/remark/src/remark-mdxish.ts create mode 100644 packages/markdown/remark/test/components.test.js create mode 100644 packages/markdown/remark/test/expressions.test.js create mode 100644 packages/markdown/remark/test/plugins.test.js diff --git a/.changeset/wicked-adults-pull.md b/.changeset/wicked-adults-pull.md new file mode 100644 index 000000000..f36d0a054 --- /dev/null +++ b/.changeset/wicked-adults-pull.md @@ -0,0 +1,6 @@ +--- +'astro': patch +'@astrojs/markdown-remark': minor +--- + +Significantally more stable behavior for "Markdown + Components" usage, which now handles component serialization much more similarly to MDX. Also supports switching between Components and Markdown without extra newlines, removes wrapping `

` tags from standalone components, and improves JSX expression handling. diff --git a/packages/astro/src/@types/astro.ts b/packages/astro/src/@types/astro.ts index 642fe9ffb..ada2427ad 100644 --- a/packages/astro/src/@types/astro.ts +++ b/packages/astro/src/@types/astro.ts @@ -513,16 +513,6 @@ export interface AstroUserConfig { */ drafts?: boolean; - /** - * @docs - * @name markdown.mode - * @type {'md' | 'mdx'} - * @default `mdx` - * @description - * Control wheater to allow components inside markdown files ('mdx') or not ('md'). - */ - mode?: 'md' | 'mdx'; - /** * @docs * @name markdown.shikiConfig diff --git a/packages/astro/src/vite-plugin-markdown/index.ts b/packages/astro/src/vite-plugin-markdown/index.ts index d75351ca3..d7c02192c 100644 --- a/packages/astro/src/vite-plugin-markdown/index.ts +++ b/packages/astro/src/vite-plugin-markdown/index.ts @@ -84,7 +84,7 @@ export default function markdown({ config }: AstroPluginOptions): Plugin { const source = await fs.promises.readFile(fileId, 'utf8'); const { data: frontmatter } = matter(source); return { - code: ` + code: ` // Static export const frontmatter = ${JSON.stringify(frontmatter)}; export const file = ${JSON.stringify(fileId)}; @@ -122,12 +122,17 @@ export default function markdown({ config }: AstroPluginOptions): Plugin { const hasInjectedScript = isPage && config._ctx.scripts.some((s) => s.stage === 'page-ssr'); // Extract special frontmatter keys - const { data: frontmatter, content: markdownContent } = matter(source); - let renderResult = await renderMarkdown(markdownContent, renderOpts); + let { data: frontmatter, content: markdownContent } = matter(source); + + // Turn HTML comments into JS comments + markdownContent = markdownContent.replace(/<\s*!--([^-->]*)(.*?)-->/gs, (whole) => `{/*${whole}*/}`) + + let renderResult = await renderMarkdown(markdownContent, { ...renderOpts, fileURL: fileUrl } as any); let { code: astroResult, metadata } = renderResult; const { layout = '', components = '', setup = '', ...content } = frontmatter; content.astro = metadata; const prelude = `--- +import { slug as $$slug } from '@astrojs/markdown-remark'; ${layout ? `import Layout from '${layout}';` : ''} ${components ? `import * from '${components}';` : ''} ${hasInjectedScript ? `import '${PAGE_SSR_SCRIPT_ID}';` : ''} @@ -151,6 +156,8 @@ ${setup}`.trim(); site: config.site ? new URL(config.base, config.site).toString() : undefined, sourcefile: id, sourcemap: 'inline', + // TODO: baseline flag + experimentalStaticExtraction: true, internalURL: `/@fs${prependForwardSlash( viteID(new URL('../runtime/server/index.js', import.meta.url)) )}`, diff --git a/packages/astro/test/astro-markdown.test.js b/packages/astro/test/astro-markdown.test.js index cfbf33b0a..0f9d28c86 100644 --- a/packages/astro/test/astro-markdown.test.js +++ b/packages/astro/test/astro-markdown.test.js @@ -28,12 +28,57 @@ describe('Astro Markdown', () => { const $ = cheerio.load(html); expect($('h2').html()).to.equal('Blog Post with JSX expressions'); - expect($('p').first().html()).to.equal('JSX at the start of the line!'); + + expect(html).to.contain('JSX at the start of the line!'); for (let listItem of ['test-1', 'test-2', 'test-3']) { - expect($(`#${listItem}`).html()).to.equal(`\n${listItem}\n`); + expect($(`#${listItem}`).html()).to.equal(`${listItem}`); } }); + it('Can handle slugs with JSX expressions in markdown pages', async () => { + const html = await fixture.readFile('/slug/index.html'); + const $ = cheerio.load(html); + + expect($('h1').attr("id")).to.equal('my-blog-post'); + }); + + it('Can handle code elements without extra spacing', async () => { + const html = await fixture.readFile('/code-element/index.html'); + const $ = cheerio.load(html); + + $('code').each((_, el) => { + expect($(el).html()).to.equal($(el).html().trim()) + }); + }); + + it('Can handle namespaced components in markdown', async () => { + const html = await fixture.readFile('/namespace/index.html'); + const $ = cheerio.load(html); + + expect($('h1').text()).to.equal('Hello Namespace!'); + expect($('button').length).to.equal(1); + }); + + it('Correctly handles component children in markdown pages (#3319)', async () => { + const html = await fixture.readFile('/children/index.html'); + + expect(html).not.to.contain('

'); + }); + + it('Can handle HTML comments in markdown pages', async () => { + const html = await fixture.readFile('/comment/index.html'); + const $ = cheerio.load(html); + + expect($('h1').text()).to.equal('It works!'); + }); + + // https://github.com/withastro/astro/issues/3254 + it('Can handle scripts in markdown pages', async () => { + const html = await fixture.readFile('/script/index.html'); + console.log(html); + expect(html).not.to.match(new RegExp("\/src\/scripts\/test\.js")); + }); + it('Can load more complex jsxy stuff', async () => { const html = await fixture.readFile('/complex/index.html'); const $ = cheerio.load(html); diff --git a/packages/astro/test/fixtures/astro-markdown/src/components/TextBlock.jsx b/packages/astro/test/fixtures/astro-markdown/src/components/TextBlock.jsx new file mode 100644 index 000000000..d9ea2534f --- /dev/null +++ b/packages/astro/test/fixtures/astro-markdown/src/components/TextBlock.jsx @@ -0,0 +1,20 @@ +import { h } from 'preact'; + +const TextBlock = ({ + title, + children, + noPadding = false, +}) => { + return ( +
+

{title}

+

{children}

+
+ ); +}; + +export default TextBlock; diff --git a/packages/astro/test/fixtures/astro-markdown/src/components/index.js b/packages/astro/test/fixtures/astro-markdown/src/components/index.js new file mode 100644 index 000000000..e7cc94c58 --- /dev/null +++ b/packages/astro/test/fixtures/astro-markdown/src/components/index.js @@ -0,0 +1,5 @@ +import Counter from './Counter'; + +export default { + Counter +} diff --git a/packages/astro/test/fixtures/astro-markdown/src/content/code-element.md b/packages/astro/test/fixtures/astro-markdown/src/content/code-element.md new file mode 100644 index 000000000..b091decc0 --- /dev/null +++ b/packages/astro/test/fixtures/astro-markdown/src/content/code-element.md @@ -0,0 +1,3 @@ +This should have `nospace` around it. + +This should have nospace around it. diff --git a/packages/astro/test/fixtures/astro-markdown/src/pages/children.md b/packages/astro/test/fixtures/astro-markdown/src/pages/children.md new file mode 100644 index 000000000..a22ee5f96 --- /dev/null +++ b/packages/astro/test/fixtures/astro-markdown/src/pages/children.md @@ -0,0 +1,12 @@ +--- +setup: import TextBlock from '../components/TextBlock' +--- +{/* https://github.com/withastro/astro/issues/3319 */} + + + + diff --git a/packages/astro/test/fixtures/astro-markdown/src/pages/code-element.astro b/packages/astro/test/fixtures/astro-markdown/src/pages/code-element.astro new file mode 100644 index 000000000..43ca0bfc5 --- /dev/null +++ b/packages/astro/test/fixtures/astro-markdown/src/pages/code-element.astro @@ -0,0 +1,7 @@ +--- +const content = await Astro.glob('../content/*.md'); +--- + +
+ {content.map(({ Content }) => )} +
diff --git a/packages/astro/test/fixtures/astro-markdown/src/pages/comment.md b/packages/astro/test/fixtures/astro-markdown/src/pages/comment.md new file mode 100644 index 000000000..39a916351 --- /dev/null +++ b/packages/astro/test/fixtures/astro-markdown/src/pages/comment.md @@ -0,0 +1,2 @@ + +# It works! diff --git a/packages/astro/test/fixtures/astro-markdown/src/pages/jsx-expressions.md b/packages/astro/test/fixtures/astro-markdown/src/pages/jsx-expressions.md index 2f038fdad..b87efbb2d 100644 --- a/packages/astro/test/fixtures/astro-markdown/src/pages/jsx-expressions.md +++ b/packages/astro/test/fixtures/astro-markdown/src/pages/jsx-expressions.md @@ -8,4 +8,6 @@ list: ['test-1', 'test-2', 'test-3'] {frontmatter.paragraph} -{frontmatter.list.map(item =>

{item}

)} + diff --git a/packages/astro/test/fixtures/astro-markdown/src/pages/namespace.md b/packages/astro/test/fixtures/astro-markdown/src/pages/namespace.md new file mode 100644 index 000000000..abbe26a3b --- /dev/null +++ b/packages/astro/test/fixtures/astro-markdown/src/pages/namespace.md @@ -0,0 +1,7 @@ +--- +setup: import ns from '../components/index.js'; +--- + +# Hello Namespace! + +Click me! diff --git a/packages/astro/test/fixtures/astro-markdown/src/pages/script.md b/packages/astro/test/fixtures/astro-markdown/src/pages/script.md new file mode 100644 index 000000000..f2b8bca88 --- /dev/null +++ b/packages/astro/test/fixtures/astro-markdown/src/pages/script.md @@ -0,0 +1,7 @@ +# Test + +## Let's try a script... + +This should work! + +