summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Nate Moore <natemoo-re@users.noreply.github.com> 2021-06-02 10:53:33 -0500
committerGravatar GitHub <noreply@github.com> 2021-06-02 11:53:33 -0400
commitffb6380c3fde97e67c94a374d177b7fb4ca809c5 (patch)
tree55a4d1bd9d77ec0100263f8ed272037f39af63a0
parentd2330a58256c212288bbba04ca41f1d65d37e711 (diff)
downloadastro-ffb6380c3fde97e67c94a374d177b7fb4ca809c5.tar.gz
astro-ffb6380c3fde97e67c94a374d177b7fb4ca809c5.tar.zst
astro-ffb6380c3fde97e67c94a374d177b7fb4ca809c5.zip
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>
-rw-r--r--.changeset/forty-rice-provide.md5
-rw-r--r--docs/markdown.md24
-rw-r--r--examples/remote-markdown/src/pages/test.astro6
-rw-r--r--packages/astro/components/Markdown.astro27
-rw-r--r--packages/astro/package.json3
-rw-r--r--packages/astro/src/compiler/codegen/index.ts6
-rw-r--r--packages/astro/src/dev.ts1
-rw-r--r--packages/astro/src/external.ts2
-rw-r--r--packages/astro/src/frontend/markdown.ts1
-rw-r--r--packages/astro/test/astro-markdown.test.js10
-rw-r--r--packages/astro/test/fixtures/astro-markdown/src/pages/external.astro15
11 files changed, 93 insertions, 7 deletions
diff --git a/.changeset/forty-rice-provide.md b/.changeset/forty-rice-provide.md
new file mode 100644
index 000000000..cff1ec123
--- /dev/null
+++ b/.changeset/forty-rice-provide.md
@@ -0,0 +1,5 @@
+---
+'astro': minor
+---
+
+Support for dynamic Markdown through the content attribute.
diff --git a/docs/markdown.md b/docs/markdown.md
index 116f807a6..c20124096 100644
--- a/docs/markdown.md
+++ b/docs/markdown.md
@@ -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>
```
diff --git a/examples/remote-markdown/src/pages/test.astro b/examples/remote-markdown/src/pages/test.astro
new file mode 100644
index 000000000..d0a050f35
--- /dev/null
+++ b/examples/remote-markdown/src/pages/test.astro
@@ -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} />
diff --git a/packages/astro/components/Markdown.astro b/packages/astro/components/Markdown.astro
index 8e4e17cee..ae27876a9 100644
--- a/packages/astro/components/Markdown.astro
+++ b/packages/astro/components/Markdown.astro
@@ -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 />}
diff --git a/packages/astro/package.json b/packages/astro/package.json
index a4e29e1cf..237f72a8d 100644
--- a/packages/astro/package.json
+++ b/packages/astro/package.json
@@ -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",
diff --git a/packages/astro/src/compiler/codegen/index.ts b/packages/astro/src/compiler/codegen/index.ts
index 68ff8d853..a37861a28 100644
--- a/packages/astro/src/compiler/codegen/index.ts
+++ b/packages/astro/src/compiler/codegen/index.ts
@@ -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;
}
diff --git a/packages/astro/src/dev.ts b/packages/astro/src/dev.ts
index 5d1f20cff..a7da0c863 100644
--- a/packages/astro/src/dev.ts
+++ b/packages/astro/src/dev.ts
@@ -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)}]`);
diff --git a/packages/astro/src/external.ts b/packages/astro/src/external.ts
index f8ae0e23c..63abeffad 100644
--- a/packages/astro/src/external.ts
+++ b/packages/astro/src/external.ts
@@ -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
diff --git a/packages/astro/src/frontend/markdown.ts b/packages/astro/src/frontend/markdown.ts
new file mode 100644
index 000000000..3a446092f
--- /dev/null
+++ b/packages/astro/src/frontend/markdown.ts
@@ -0,0 +1 @@
+export { renderMarkdown } from '../compiler/utils'; \ No newline at end of file
diff --git a/packages/astro/test/astro-markdown.test.js b/packages/astro/test/astro-markdown.test.js
index bb5a540e0..ecd946f47 100644
--- a/packages/astro/test/astro-markdown.test.js
+++ b/packages/astro/test/astro-markdown.test.js
@@ -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();
diff --git a/packages/astro/test/fixtures/astro-markdown/src/pages/external.astro b/packages/astro/test/fixtures/astro-markdown/src/pages/external.astro
new file mode 100644
index 000000000..a39209d4a
--- /dev/null
+++ b/packages/astro/test/fixtures/astro-markdown/src/pages/external.astro
@@ -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> \ No newline at end of file