iTranslated by AI

The content below is an AI-generated translation. This is an experimental feature, and may contain errors. View original article
👩‍🚀

Using zenn-markdown with Astro

に公開

Introduction

zenn-markdown is what you'd call a Markdown parser that transforms raw Markdown into the nice-looking layout you typically see in Zenn articles.

Recently, I've been building a personal blog using Astro and was considering which Markdown parser to use. Since I had a very smooth experience using zenn-markdown for a blog I previously built with Next.js, I decided to introduce it into Astro as well.

However, I ran into several integration issues with Astro's settings and struggled quite a bit before getting it fully functional. I'm writing this down here so that others don't have to go through the same trouble.

I hope you find this helpful!

How to Install

Basically, you can follow the same steps and do the same things as described in the following article:
https://zenn.dev/team_zenn/articles/intro-zenn-markdown

1. Install zenn-markdown-html and zenn-markdown-css

Install the latest packages.
As of February 21, 2023, the version is 0.1.140, so add the following to your package.json:

package.json
   "dependencies": {
      ...
+    "zenn-content-css": "^0.1.140",
+    "zenn-embed-elements": "^0.1.140",
+    "zenn-markdown-html": "^0.1.140"
   }

After that, run yarn install to fetch the packages.

2. Use zenn-markdown-html

zenn-markdown-html is a tool that converts raw Markdown into an HTML string.

The basic usage is as follows:

[...slug].astro
import markdownToHtml from "zenn-markdown-html";

// Pass raw Markdown (=post.body) to the markdownToHtml function and receive it as HTML (=content)
const content = markdownToHtml(post.body, {
  embedOrigin: "https://embed.zenn.studio",
});

However, in the case of Astro, if you build it as is, you will encounter a markdownToHtml is not a function error, so you need to fix it like this:

[...slug].astro
- import markdownToHtml from "zenn-markdown-html";
+ import lib from "zenn-markdown-html";

+ // Fixed because using it as-is during build results in an error
+ const markdownToHtml = lib.default ? lib.default : lib;

// Pass raw Markdown (=post.body) to the markdownToHtml function and receive it as HTML (=content)
const content = markdownToHtml(post.body);

This is a temporary workaround. While it shows a red wavy line in VSCode, it works correctly, so we'll leave it as is.

Why does a build error occur?

It seemed that the import result of markdownToHtml changes depending on the execution command, leading to the markdownToHtml is not a function error.

I didn't understand why the error was occurring at first either, so I asked the Zenn developers, and they replied:

Upon checking here, the reason for the markdownToHtml is not a function build error is that the import result changes when the build command is executed. Specifically, the value of the default import changes from a Function to { default: Function }👇

import lib from "zenn-markdown-html";
console.log( lib ); 
// In the case of yarn dev, it is `Function`
// In the case of yarn build, it becomes `{ default: Function }` 

Indeed, when I checked it myself, it was exactly as they said.
It would be great if the Astro side resolves this in the future, but since we don't know when that will be, taking this temporary measure seems to be the only option.

3. Displaying HTML by Converting HTML Strings

The content received in step 2 is just an HTML string, so you need processing to have it recognized as an HTML element.

In Astro, there is a directive called set:html. (Equivalent to dangerouslySetInnerHTML in React)

↓ About set:html
https://docs.astro.build/ja/reference/directives-reference/#sethtml

You can display the Markdown content by using <Fragment set:html={content} />.

[...slug].astro
...

// Add the following where you want to display the Markdown content
+ <Fragment set:html={content} />

...

4. Using zenn-content-css

At this point, no CSS is applied to the HTML, so we will use zenn-content-css to apply the design.

[...slug].astro
...
// Add import
+ import 'zenn-content-css';

+ <div class="znc">
    <Fragment set:html={content} />
+ </div>
...

5. Adding script to enable embedded content

Add the script required for displaying embedded content within the <head> tag.

This is a potential stumbling block: by default, Astro performs optimization processes on <script> and <style> tags. Simply adding <script src="https://embed.zenn.studio/js/listen-embed-event.js"> will result in a CORS error in the browser.

Therefore, you need to add is:inline to the <script> tag to prevent this default processing. *Reference

↓ About is:inline
https://docs.astro.build/en/reference/directives-reference/#isinline

.astro
<head>
  <!-- Add is:inline to cancel Astro's script optimization process -->
  <script is:inline src="https://embed.zenn.studio/js/listen-embed-event.js"
  ></script>
</head>

Now everything should display correctly!

Conclusion

I've introduced zenn-markdown into Astro. I struggled because there were behaviors different from Next.js that caused several errors, but I hope this helps anyone else trying to implement zenn-markdown in Astro 🐸

Discussion