From 399d7e269834d11c046b390705a9a53d3738f3cf Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Thu, 21 Jul 2022 18:01:26 -0400 Subject: [PATCH] Fix: use `set:html` when markdown mode is `md` (#4008) * refactor: add legacy.jsxInMarkdown flag to config * fix: use `set:html` when `markdown.mode` is 'md' * Revert "refactor: add legacy.jsxInMarkdown flag to config" This reverts commit 5572e8d9b33eb1e9168d221f22348d3b3cb4b29a. * fix: move `remarkUnwrap, remarkEscape` to MDX only * fix: only apply scary HTML passthroughs on MDX * fix: move all JSX-specific rehype plugins under `isMDX` * fix: "allowDangerousHtml" for md (required for Shiki) * fix: apply `set:html` for non-layouts too * test: JSX expressions, components, syntax highlighting * chore: changeset * fix: ignore "setup" and "components" in plain MD mode * refactor: create new fixture to avoid weird caching error * fix: dup package name * chore: update lock * fix: apply rehypeCollectHeaders to md --- .changeset/moody-crabs-occur.md | 6 +++ .../astro/src/vite-plugin-markdown/index.ts | 22 ++++++-- .../astro/test/astro-markdown-md-mode.test.js | 52 +++++++++++++++++++ .../astro-markdown-md-mode/astro.config.mjs | 11 ++++ .../astro-markdown-md-mode/package.json | 9 ++++ .../src/components/Counter.svelte | 5 ++ .../src/pages/code-in-md.md | 7 +++ .../src/pages/components.md | 5 ++ .../src/pages/jsx-expressions.md | 13 +++++ packages/markdown/remark/src/index.ts | 18 ++++--- pnpm-lock.yaml | 8 +++ 11 files changed, 143 insertions(+), 13 deletions(-) create mode 100644 .changeset/moody-crabs-occur.md create mode 100644 packages/astro/test/astro-markdown-md-mode.test.js create mode 100644 packages/astro/test/fixtures/astro-markdown-md-mode/astro.config.mjs create mode 100644 packages/astro/test/fixtures/astro-markdown-md-mode/package.json create mode 100644 packages/astro/test/fixtures/astro-markdown-md-mode/src/components/Counter.svelte create mode 100644 packages/astro/test/fixtures/astro-markdown-md-mode/src/pages/code-in-md.md create mode 100644 packages/astro/test/fixtures/astro-markdown-md-mode/src/pages/components.md create mode 100644 packages/astro/test/fixtures/astro-markdown-md-mode/src/pages/jsx-expressions.md diff --git a/.changeset/moody-crabs-occur.md b/.changeset/moody-crabs-occur.md new file mode 100644 index 000000000..050e9ec0d --- /dev/null +++ b/.changeset/moody-crabs-occur.md @@ -0,0 +1,6 @@ +--- +'astro': patch +'@astrojs/markdown-remark': patch +--- + +Avoid parsing JSX, components, and Astro islands when using "plain" md mode. This brings `markdown.mode: 'md'` in-line with our docs description. diff --git a/packages/astro/src/vite-plugin-markdown/index.ts b/packages/astro/src/vite-plugin-markdown/index.ts index 2c218610b..3d70aba72 100644 --- a/packages/astro/src/vite-plugin-markdown/index.ts +++ b/packages/astro/src/vite-plugin-markdown/index.ts @@ -137,6 +137,7 @@ export default function markdown({ config }: AstroPluginOptions): Plugin { const filename = normalizeFilename(id); const source = await fs.promises.readFile(filename, 'utf8'); const renderOpts = config.markdown; + const isMDX = renderOpts.mode === 'mdx'; const fileUrl = new URL(`file://${filename}`); const isPage = fileUrl.pathname.startsWith(resolvePages(config).pathname); @@ -148,7 +149,7 @@ export default function markdown({ config }: AstroPluginOptions): Plugin { // Turn HTML comments into JS comments while preventing nested `*/` sequences // from ending the JS comment by injecting a zero-width space // Inside code blocks, this is removed during renderMarkdown by the remark-escape plugin. - if (renderOpts.mode === 'mdx') { + if (isMDX) { markdownContent = markdownContent.replace( /<\s*!--([^-->]*)(.*?)-->/gs, (whole) => `{/*${whole.replace(/\*\//g, '*\u200b/')}*/}` @@ -167,19 +168,30 @@ export default function markdown({ config }: AstroPluginOptions): Plugin { const prelude = `--- import Slugger from 'github-slugger'; ${layout ? `import Layout from '${layout}';` : ''} -${components ? `import * from '${components}';` : ''} +${isMDX && components ? `import * from '${components}';` : ''} ${hasInjectedScript ? `import '${PAGE_SSR_SCRIPT_ID}';` : ''} -${setup} +${isMDX ? setup : ''} const slugger = new Slugger(); function $$slug(value) { return slugger.slug(value); } -const $$content = ${JSON.stringify(content)} +const $$content = ${JSON.stringify(isMDX + ? content + // Avoid stripping "setup" and "components" + // in plain MD mode + : { ...content, setup, components })} ---`; const imports = `${layout ? `import Layout from '${layout}';` : ''} -${setup}`.trim(); +${isMDX ? setup : ''}`.trim(); + + // Wrap with set:html fragment to skip + // JSX expressions and components in "plain" md mode + if (!isMDX) { + astroResult = `` + } + // If the user imported "Layout", wrap the content in a Layout if (/\bLayout\b/.test(imports)) { astroResult = `${prelude}\n\n\n${astroResult}\n\n`; diff --git a/packages/astro/test/astro-markdown-md-mode.test.js b/packages/astro/test/astro-markdown-md-mode.test.js new file mode 100644 index 000000000..46056605f --- /dev/null +++ b/packages/astro/test/astro-markdown-md-mode.test.js @@ -0,0 +1,52 @@ +import { expect } from 'chai'; +import * as cheerio from 'cheerio'; +import { loadFixture } from './test-utils.js'; + +describe('Astro Markdown - plain MD mode', () => { + let fixture; + + before(async () => { + fixture = await loadFixture({ + root: './fixtures/astro-markdown-md-mode/', + }); + await fixture.build(); + }); + + it('Leaves JSX expressions unprocessed', async () => { + const html = await fixture.readFile('/jsx-expressions/index.html'); + const $ = cheerio.load(html); + + expect($('h2').html()).to.equal('{frontmatter.title}'); + }); + + it('Leaves JSX components un-transformed', async () => { + const html = await fixture.readFile('/components/index.html'); + + expect(html).to.include(''); + }); + + describe('syntax highlighting', async () => { + it('handles Shiki', async () => { + const html = await fixture.readFile('/code-in-md/index.html'); + const $ = cheerio.load(html); + + expect($('pre.astro-code').length).to.not.equal(0); + }); + + it('handles Prism', async () => { + fixture = await loadFixture({ + root: './fixtures/astro-markdown-md-mode/', + markdown: { + syntaxHighlight: 'prism', + mode: 'md', + }, + }); + await fixture.build(); + + const html = await fixture.readFile('/code-in-md/index.html'); + const $ = cheerio.load(html); + + expect($('pre.language-html').length).to.not.equal(0); + }); + }); +}); diff --git a/packages/astro/test/fixtures/astro-markdown-md-mode/astro.config.mjs b/packages/astro/test/fixtures/astro-markdown-md-mode/astro.config.mjs new file mode 100644 index 000000000..3fab631f3 --- /dev/null +++ b/packages/astro/test/fixtures/astro-markdown-md-mode/astro.config.mjs @@ -0,0 +1,11 @@ +import { defineConfig } from 'astro/config'; +import svelte from "@astrojs/svelte"; + +// https://astro.build/config +export default defineConfig({ + markdown: { + mode: 'md', + }, + integrations: [svelte()], + site: 'https://astro.build/', +}); diff --git a/packages/astro/test/fixtures/astro-markdown-md-mode/package.json b/packages/astro/test/fixtures/astro-markdown-md-mode/package.json new file mode 100644 index 000000000..48a6c6816 --- /dev/null +++ b/packages/astro/test/fixtures/astro-markdown-md-mode/package.json @@ -0,0 +1,9 @@ +{ + "name": "@test/astro-markdown-md-mode", + "version": "0.0.0", + "private": true, + "dependencies": { + "@astrojs/svelte": "workspace:*", + "astro": "workspace:*" + } +} diff --git a/packages/astro/test/fixtures/astro-markdown-md-mode/src/components/Counter.svelte b/packages/astro/test/fixtures/astro-markdown-md-mode/src/components/Counter.svelte new file mode 100644 index 000000000..4e91b2659 --- /dev/null +++ b/packages/astro/test/fixtures/astro-markdown-md-mode/src/components/Counter.svelte @@ -0,0 +1,5 @@ + + + diff --git a/packages/astro/test/fixtures/astro-markdown-md-mode/src/pages/code-in-md.md b/packages/astro/test/fixtures/astro-markdown-md-mode/src/pages/code-in-md.md new file mode 100644 index 000000000..72206a868 --- /dev/null +++ b/packages/astro/test/fixtures/astro-markdown-md-mode/src/pages/code-in-md.md @@ -0,0 +1,7 @@ +# Fenced code blocks + +```html + +
This should also work without any problems.
+ +``` diff --git a/packages/astro/test/fixtures/astro-markdown-md-mode/src/pages/components.md b/packages/astro/test/fixtures/astro-markdown-md-mode/src/pages/components.md new file mode 100644 index 000000000..cd27bc09f --- /dev/null +++ b/packages/astro/test/fixtures/astro-markdown-md-mode/src/pages/components.md @@ -0,0 +1,5 @@ +--- +setup: import Counter from '../components/Counter.svelte' +--- + + diff --git a/packages/astro/test/fixtures/astro-markdown-md-mode/src/pages/jsx-expressions.md b/packages/astro/test/fixtures/astro-markdown-md-mode/src/pages/jsx-expressions.md new file mode 100644 index 000000000..b87efbb2d --- /dev/null +++ b/packages/astro/test/fixtures/astro-markdown-md-mode/src/pages/jsx-expressions.md @@ -0,0 +1,13 @@ +--- +title: Blog Post with JSX expressions +paragraph: JSX at the start of the line! +list: ['test-1', 'test-2', 'test-3'] +--- + +## {frontmatter.title} + +{frontmatter.paragraph} + +
    + {frontmatter.list.map(item =>
  • {item}
  • )} +
diff --git a/packages/markdown/remark/src/index.ts b/packages/markdown/remark/src/index.ts index 567a4414d..6c72ba981 100644 --- a/packages/markdown/remark/src/index.ts +++ b/packages/markdown/remark/src/index.ts @@ -46,8 +46,7 @@ export async function renderMarkdown( let parser = unified() .use(markdown) - .use(isMDX ? [remarkMdxish, remarkMarkAndUnravel] : []) - .use([remarkUnwrap, remarkEscape]); + .use(isMDX ? [remarkMdxish, remarkMarkAndUnravel, remarkUnwrap, remarkEscape] : []) if (remarkPlugins.length === 0 && rehypePlugins.length === 0) { remarkPlugins = [...DEFAULT_REMARK_PLUGINS]; @@ -76,13 +75,13 @@ export async function renderMarkdown( markdownToHtml as any, { allowDangerousHtml: true, - passThrough: [ + passThrough: isMDX ? [ 'raw', 'mdxFlowExpression', 'mdxJsxFlowElement', 'mdxJsxTextElement', 'mdxTextExpression', - ], + ] : [], }, ], ]); @@ -92,10 +91,13 @@ export async function renderMarkdown( }); parser - .use(isMDX ? [rehypeJsx, rehypeExpressions] : [rehypeRaw]) - .use(rehypeEscape) - .use(rehypeIslands) - .use([rehypeCollectHeaders]) + .use(isMDX ? [ + rehypeJsx, + rehypeExpressions, + rehypeEscape, + rehypeIslands, + rehypeCollectHeaders, + ] : [rehypeCollectHeaders, rehypeRaw]) .use(rehypeStringify, { allowDangerousHtml: true }); let result: string; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0f48f3ed9..633ee1b9d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1280,6 +1280,14 @@ importers: dependencies: astro: link:../../.. + packages/astro/test/fixtures/astro-markdown-md-mode: + specifiers: + '@astrojs/svelte': workspace:* + astro: workspace:* + dependencies: + '@astrojs/svelte': link:../../../../integrations/svelte + astro: link:../../.. + packages/astro/test/fixtures/astro-markdown-plugins: specifiers: '@astrojs/preact': workspace:*