Skip to content

Commit

Permalink
Fix: use set:html when markdown mode is md (#4008)
Browse files Browse the repository at this point in the history
* 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 5572e8d.

* 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
  • Loading branch information
bholmesdev authored Jul 21, 2022
1 parent c2968b0 commit 399d7e2
Show file tree
Hide file tree
Showing 11 changed files with 143 additions and 13 deletions.
6 changes: 6 additions & 0 deletions .changeset/moody-crabs-occur.md
Original file line number Diff line number Diff line change
@@ -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.
22 changes: 17 additions & 5 deletions packages/astro/src/vite-plugin-markdown/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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/')}*/}`
Expand All @@ -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 = `<Fragment set:html={${JSON.stringify(astroResult)}} />`
}

// If the user imported "Layout", wrap the content in a Layout
if (/\bLayout\b/.test(imports)) {
astroResult = `${prelude}\n<Layout content={$$content}>\n\n${astroResult}\n\n</Layout>`;
Expand Down
52 changes: 52 additions & 0 deletions packages/astro/test/astro-markdown-md-mode.test.js
Original file line number Diff line number Diff line change
@@ -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('<counter client:load="" count="{0}">');
});

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);
});
});
});
Original file line number Diff line number Diff line change
@@ -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/',
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"name": "@test/astro-markdown-md-mode",
"version": "0.0.0",
"private": true,
"dependencies": {
"@astrojs/svelte": "workspace:*",
"astro": "workspace:*"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<script>
export let count = 0;
</script>

<button onClick={() => count += 1}>{count}</button>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Fenced code blocks

```html
<body>
<div>This should also work without any problems.</div>
</body>
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
setup: import Counter from '../components/Counter.svelte'
---

<Counter client:load count={0}></Counter>
Original file line number Diff line number Diff line change
@@ -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}

<ul>
{frontmatter.list.map(item => <li id={item}>{item}</li>)}
</ul>
18 changes: 10 additions & 8 deletions packages/markdown/remark/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand Down Expand Up @@ -76,13 +75,13 @@ export async function renderMarkdown(
markdownToHtml as any,
{
allowDangerousHtml: true,
passThrough: [
passThrough: isMDX ? [
'raw',
'mdxFlowExpression',
'mdxJsxFlowElement',
'mdxJsxTextElement',
'mdxTextExpression',
],
] : [],
},
],
]);
Expand All @@ -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;
Expand Down
8 changes: 8 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 399d7e2

Please sign in to comment.