Dynamic Markdown content (#273)
* wip: serverside render dynamic Markdown content * docs: update Markdown.astro comments * Use existing markdown infrastructure to render external MD * Update Markdown docs * Add a changeset Co-authored-by: Matthew Phillips <matthew@skypack.dev>
This commit is contained in:
parent
d2330a5825
commit
ffb6380c3f
11 changed files with 93 additions and 7 deletions
5
.changeset/forty-rice-provide.md
Normal file
5
.changeset/forty-rice-provide.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
'astro': minor
|
||||
---
|
||||
|
||||
Support for dynamic Markdown through the content attribute.
|
|
@ -97,7 +97,7 @@ const expressions = 'Lorem ipsum';
|
|||
|
||||
### Remote Markdown
|
||||
|
||||
If you have Markdown in a remote source, you may pass it directly to the Markdown component. For example, the example below fetches the README from Snowpack's GitHub repository and renders it as HTML.
|
||||
If you have Markdown in a remote source, you may pass it directly to the Markdown component through the `content` attribute. For example, the example below fetches the README from Snowpack's GitHub repository and renders it as HTML.
|
||||
|
||||
```jsx
|
||||
---
|
||||
|
@ -107,7 +107,27 @@ const content = await fetch('https://raw.githubusercontent.com/snowpackjs/snowpa
|
|||
---
|
||||
|
||||
<Layout>
|
||||
<Markdown>{content}</Markdown>
|
||||
<Markdown content={content} />
|
||||
</Layout>
|
||||
```
|
||||
|
||||
Some times you might want to combine dynamic markdown with static markdown. You can nest `Markdown` components to get the best of both worlds.
|
||||
|
||||
```jsx
|
||||
---
|
||||
import Markdown from 'astro/components/Markdown.astro';
|
||||
|
||||
const content = await fetch('https://raw.githubusercontent.com/snowpackjs/snowpack/main/README.md').then(res => res.text());
|
||||
---
|
||||
|
||||
<Layout>
|
||||
<Markdown>
|
||||
## Markdown example
|
||||
|
||||
Here we have some __Markdown__ code. We can also dynamically render content from remote places.
|
||||
|
||||
<Markdown content={content} />
|
||||
</Mardown>
|
||||
</Layout>
|
||||
```
|
||||
|
||||
|
|
6
examples/remote-markdown/src/pages/test.astro
Normal file
6
examples/remote-markdown/src/pages/test.astro
Normal file
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
import Markdown from 'astro/components/Markdown.astro';
|
||||
const content = await fetch('https://raw.githubusercontent.com/snowpackjs/snowpack/main/README.md').then(res => res.text());
|
||||
---
|
||||
|
||||
<Markdown content={content} />
|
|
@ -1,3 +1,24 @@
|
|||
<!-- Probably not what you're looking for! -->
|
||||
<!-- Check `astro-parser` or /frontend/markdown.ts -->
|
||||
<slot />
|
||||
---
|
||||
import { renderMarkdown } from 'astro/dist/frontend/markdown.js';
|
||||
|
||||
export let content: string;
|
||||
export let $scope: string;
|
||||
let html = null;
|
||||
|
||||
// This flow is only triggered if a user passes `<Markdown content={content} />`
|
||||
if (content) {
|
||||
const { content: htmlContent } = await renderMarkdown(content, {
|
||||
mode: 'md',
|
||||
$: {
|
||||
scopedClassName: $scope
|
||||
}
|
||||
});
|
||||
html = htmlContent;
|
||||
}
|
||||
|
||||
/*
|
||||
If we have rendered `html` for `content`, render that
|
||||
Otherwise, just render the slotted content
|
||||
*/
|
||||
---
|
||||
{html ? html : <slot />}
|
||||
|
|
|
@ -10,7 +10,8 @@
|
|||
"./package.json": "./package.json",
|
||||
"./snowpack-plugin": "./snowpack-plugin.cjs",
|
||||
"./components/*": "./components/*",
|
||||
"./runtime/svelte": "./dist/frontend/runtime/svelte.js"
|
||||
"./runtime/svelte": "./dist/frontend/runtime/svelte.js",
|
||||
"./dist/frontend/markdown.js": "./dist/frontend/markdown.js"
|
||||
},
|
||||
"imports": {
|
||||
"#astro/compiler": "./dist/compiler/index.js",
|
||||
|
|
|
@ -557,6 +557,12 @@ async function compileHtml(enterNode: TemplateNode, state: CodegenState, compile
|
|||
if (componentName === 'Markdown') {
|
||||
const { $scope } = attributes ?? {};
|
||||
state.markers.insideMarkdown = { $scope };
|
||||
if (attributes.content) {
|
||||
if (curr === 'markdown') {
|
||||
await pushMarkdownToBuffer();
|
||||
}
|
||||
buffers[curr] += `,${componentName}.__render(${attributes ? generateAttributes(attributes) : 'null'}),`;
|
||||
}
|
||||
curr = 'markdown';
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ export default async function dev(astroConfig: AstroConfig) {
|
|||
|
||||
const server = http.createServer(async (req, res) => {
|
||||
timer.load = performance.now();
|
||||
|
||||
const result = await runtime.load(req.url);
|
||||
debug(logging, 'dev', `loaded ${req.url} [${stopTimer(timer.load)}]`);
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ const isAstroRenderer = (name: string) => {
|
|||
|
||||
// These packages should NOT be built by `esinstall`
|
||||
// But might not be explicit dependencies of `astro`
|
||||
const denyList = ['prismjs/components/index.js', '@vue/server-renderer'];
|
||||
const denyList = ['prismjs/components/index.js', '@vue/server-renderer', 'astro/dist/frontend/markdown.js'];
|
||||
|
||||
export default Object.keys(pkg.dependencies)
|
||||
// Filter out packages that should be loaded threw Snowpack
|
||||
|
|
1
packages/astro/src/frontend/markdown.ts
Normal file
1
packages/astro/src/frontend/markdown.ts
Normal file
|
@ -0,0 +1 @@
|
|||
export { renderMarkdown } from '../compiler/utils';
|
|
@ -45,4 +45,14 @@ Markdown('Bundles client-side JS for prod', async (context) => {
|
|||
assert.ok(counterJs, 'Counter.jsx is bundled for prod');
|
||||
});
|
||||
|
||||
Markdown('Renders dynamic content though the content attribute', async ({ runtime }) => {
|
||||
const result = await runtime.load('/external');
|
||||
if (result.error) throw new Error(result.error);
|
||||
|
||||
const $ = doc(result.contents);
|
||||
assert.equal($('#outer').length, 1, 'Rendered markdown content');
|
||||
assert.equal($('#inner').length, 1, 'Nested markdown content');
|
||||
assert.ok($('#inner').is('[class]'), 'Scoped class passed down');
|
||||
});
|
||||
|
||||
Markdown.run();
|
||||
|
|
15
packages/astro/test/fixtures/astro-markdown/src/pages/external.astro
vendored
Normal file
15
packages/astro/test/fixtures/astro-markdown/src/pages/external.astro
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
import Markdown from 'astro/components/Markdown.astro';
|
||||
import Hello from '../components/Hello.jsx';
|
||||
|
||||
const outer = `# Outer`;
|
||||
const inner = `## Inner`;
|
||||
---
|
||||
|
||||
<Markdown content={outer} />
|
||||
|
||||
<Markdown>
|
||||
# Nested
|
||||
|
||||
<Markdown content={inner} />
|
||||
</Markdown>
|
Loading…
Reference in a new issue