blog.itcode.devblog.itcode.dev

My Experience Developing Piedit

Generally, when writing posts on a website, an HTML-based editor is commonly used. But on development-related sites, it's not uncommon to see markdown-based editors used instead. My blog too, while not written directly on the web, is written based on markdown. It lets me write intuitively while also being highly compatible with HTML, so there's no issue rendering it on the web either. Plus, there's a variety of supporting plugins as a bonus. I've added rendering code to make the blog's content look polished. Code blocks are one example of this.

My Experience Developing Piedit

Generally, when writing posts on a website, an HTML-based editor is commonly used. But on development-related sites, it's not uncommon to see markdown-based editors used instead. My blog too, while not written directly on the web, is written based on markdown. It lets me write intuitively while also being highly compatible with HTML, so there's no issue rendering it on the web either. Plus, there's a variety of supporting plugins as a bonus. I've added rendering code to make the blog's content look polished. Code blocks are one example of this.
RWB0104
@RWBwritten at 2023-09-17 12:57:46

Generally, when writing posts on a website, an HTML-based editor is commonly used. But on development-related sites, it's not uncommon to see markdown-based editors used instead.

My blog too, while not written directly on the web, is written based on markdown. It lets me write intuitively while also being highly compatible with HTML, so there's no issue rendering it on the web either. Plus, there's a variety of supporting plugins as a bonus.

I've added rendering code to make the blog's content look polished. Code blocks are one example of this.

JAVASCRIPT

console.log('a feature like this');

Thanks to the compatibility between markdown and HTML, markdown conversion and previewing is provided in a variety of forms, from websites to IDE plugins. However, most conversion services only provide basic conversion functionality. That is, for someone like me who has even the slightest custom code mixed in, converting or previewing it via a general-purpose method becomes difficult.

Because of this, writing and checking a blog post always required the hassle of running the blog's frontend server directly to view it. That's manageable on its own, but if I switch computers, I'd need to set up the blog's development environment all over again. Sure, GitHub handles version control anyway, but that process is still a hassle in itself.

While working on this recent blog overhaul, I used the react-markdown dependency to build and apply a React-based markdown converter made of components.

TSX

<ReactMarkdown
    components={{
        a: A,
        blockquote: Blockquote,
        code: Code,
        h1: H1,
        h2: H2,
        h3: H3,
        h4: H4,
        h5: H5,
        h6: H6,
        img: Img,
        table: Table,
        td: Td,
        th: Th,
        tr: Tr
    }}
>
    {markdown}
</ReactMarkdown>

This let me apply the component I wanted to whichever tag I wanted, as shown above. It occurred to me that using this component would let me check the markdown output styled with the blog's design in real time.

The service's functionality is simple: take the markdown text a user types on the web, and convert it into HTML in real time to display. In other words, it can be split into two areas: the input area and the conversion area.

Here, the conversion area can just reuse the blog's code, so there's nothing to worry about there. The problem is the input area, which needs a place for the user to type. Using a plain textarea would make this reasonably easy to implement. But if I turned markdown that was originally written in VSCode into a textarea, I'd lose a lot in terms of both design and functionality.

🖼️ Monaco Editor

I happened to hear about something called the Monaco Editor a while back. It's identical to VSCode's editor — I'm not entirely sure whether it was built based on VSCode, or whether VSCode uses Monaco Editor internally. Either way, the important thing is that applying Monaco Editor lets me offer a UX similar to VSCode.

I was able to design the input area using the @monaco-editor/react dependency. Most of the configuration could be applied through option code, so it turned out to be simpler to implement than expected. Had I not known about this and just stuck with a plain textarea, I would clearly have wasted a ton of effort and ended up with a messy component to boot.

Once both the input area and conversion area were implemented, the rest was simple. I saved the value entered in the editor as state and passed it to the conversion component, and that completed the implementation.

🖼️ Piedit

For something I threw together on a whim, it turned out not too bad. The usability is a bit worse than VSCode. But now I can write blog posts from anywhere, on any device, as long as I have internet access.

There were occasional times when I wanted to write from a different device or while away from home, and now I don't even need to think twice about it.

I mulled over what to name it, and settled on Piedit, combining the 𝝅 I often use in the sites I build with the "edit" from editor. Not exactly a name I love, but not bad either.

There were a few issues I noticed while actually using it.

I didn't notice it when I first built it and tested it briefly, but lag occurs as posts get longer. It relies on state, and more importantly, the markdown has to be converted in real time through a fairly complex set of customizations. It's only natural that conversion time increases as the post gets longer.

With a basic conversion, it might have been able to handle even fairly long posts, but with all the large and small components involved now, lag noticeably increases as posts get longer.

One fortunate thing is that toggling the preview panel on/off can alleviate this to some degree. It happened somewhat by accident, but I generally prefer to completely remove tags that are hidden in the DOM rather than just visually hiding them, unless there's a specific reason not to.

TSX

// When hiding based on isActive
function A(): JSX.Element
{
    return <Component style={{ display: isActive ? 'block' : 'none' }} />;
}

// When removing the DOM entirely based on isActive
function B(): JSX.Element
{
    return isActive ? (
        <Component />
    ) : null;
}

This is to prevent situations where a tag that isn't even visible still ends up consuming resources in the background.

When the preview panel is hidden, the component itself disappears from the DOM as null, so the markdown conversion logic doesn't run at all. Thanks to that, closing the preview panel prevents lag from occurring.

Unfortunately, it seems like the way to use it will have to be: write with the preview panel turned off, and turn it on occasionally just to check.

For the preview to be meaningful, the blog's markdown design and the preview's design need to match. But since these are entirely separate services, the same code needs to exist once in each service. If the blog's markdown design changes, this service needs to be updated to reflect it as well.

Unless I split the conversion component out separately and publish it to NPM to manage it, there's really no solution for this right now.

Since it's purely a preview service, there's no way to save or load written text.

I've thought that, ideally, it might be nice to let users log in with GitHub and save or load posts via the Issue API. That's something I'll probably need to think through a bit more later.

Having a management feature would be convenient, but I also wonder if just handling the conversion to the blog's design is already fulfilling its role well enough on its own.

# React# Next.js# Markdown
ship
blog.itcode.dev

Notes from the π-th Alpaca

7.0.1
Developed by RWB since 2021.057th upgraded at 2026.08