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 5572e8d9b3
.
* 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
This commit is contained in:
parent
c2968b0542
commit
399d7e2698
11 changed files with 143 additions and 13 deletions
6
.changeset/moody-crabs-occur.md
Normal file
6
.changeset/moody-crabs-occur.md
Normal file
|
@ -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.
|
|
@ -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 = `<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>`;
|
||||
|
|
52
packages/astro/test/astro-markdown-md-mode.test.js
Normal file
52
packages/astro/test/astro-markdown-md-mode.test.js
Normal file
|
@ -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);
|
||||
});
|
||||
});
|
||||
});
|
11
packages/astro/test/fixtures/astro-markdown-md-mode/astro.config.mjs
vendored
Normal file
11
packages/astro/test/fixtures/astro-markdown-md-mode/astro.config.mjs
vendored
Normal file
|
@ -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/',
|
||||
});
|
9
packages/astro/test/fixtures/astro-markdown-md-mode/package.json
vendored
Normal file
9
packages/astro/test/fixtures/astro-markdown-md-mode/package.json
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"name": "@test/astro-markdown-md-mode",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@astrojs/svelte": "workspace:*",
|
||||
"astro": "workspace:*"
|
||||
}
|
||||
}
|
5
packages/astro/test/fixtures/astro-markdown-md-mode/src/components/Counter.svelte
vendored
Normal file
5
packages/astro/test/fixtures/astro-markdown-md-mode/src/components/Counter.svelte
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
<script>
|
||||
export let count = 0;
|
||||
</script>
|
||||
|
||||
<button onClick={() => count += 1}>{count}</button>
|
7
packages/astro/test/fixtures/astro-markdown-md-mode/src/pages/code-in-md.md
vendored
Normal file
7
packages/astro/test/fixtures/astro-markdown-md-mode/src/pages/code-in-md.md
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
# Fenced code blocks
|
||||
|
||||
```html
|
||||
<body>
|
||||
<div>This should also work without any problems.</div>
|
||||
</body>
|
||||
```
|
5
packages/astro/test/fixtures/astro-markdown-md-mode/src/pages/components.md
vendored
Normal file
5
packages/astro/test/fixtures/astro-markdown-md-mode/src/pages/components.md
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
setup: import Counter from '../components/Counter.svelte'
|
||||
---
|
||||
|
||||
<Counter client:load count={0}></Counter>
|
13
packages/astro/test/fixtures/astro-markdown-md-mode/src/pages/jsx-expressions.md
vendored
Normal file
13
packages/astro/test/fixtures/astro-markdown-md-mode/src/pages/jsx-expressions.md
vendored
Normal file
|
@ -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>
|
|
@ -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;
|
||||
|
|
|
@ -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:*
|
||||
|
|
Loading…
Reference in a new issue