1
2
3
4

On ways to write

While chatting with amazing folks, I realized that content lies at the core of my passion for design and development. Picking apart past projects and things I’m excited about revealed the idea of “Elevating content through presentation” as a constant. The concept of content as the foundation of what I make brought attention to my personal site, as I like to describe it, igorbedesqui.com  is a glorified playground, my safe space to overengineer and experiment. But how can I hone the craft of elevating content through presentation if there’s no content? my 2 year old site only had a few pages worth of text and although the project pages were fine, I felt a lot of resistance whenever I wanted to create something different.


On Resistance

This resistance was primarily created by the disconnect between content and where it lived, due to my internationalization setup, I needed to keep every bit of content into files under an i18n folder and use it through functions in the actual pages and components. Since the content lived in JSON files, whenever I wanted to represent HTML tags or react elements, I needed to write fake tags and switch them on the page with a function from my i18n library. This was by no means a horrible experience and I even managed to make it typesafe with autocomplete , but it put enough resistance between me and writing that it was never my choice when asking “What should I do next?”. Additionally, internationalization is not only translating but making sure the tone, delivery, and structure are just right for both languages so the work of writing was always doubled.


Escaping resistance

To make writing as simple as possible, I dropped internationalization, cutting the effort needed in about half. To tackle the biggest barrier in the JSON files I switched to MDX, allowing me to write as if I was jotting down something on Notion but with the full power of React. Guilherme Rodz(GOAT) even helped me with colocating the content in the same file it was used . Look at this perfect solution

const MDs = {
   update: `
      Lorem *ipsum* ...
   `,
   why: {
      paragraph: `... <Popover />`
      popoverContent: `...`
   },
   ...
}

export const getStaticProps = async () => {
   const mdx = await mutateSerializeMdx(MDs);
   return { props: { mdx } };
}

export default function Page({mdx}){
   return(
      <MDXRemote {...mdx.update} />
      <MDXRemote {...mdx.why.paragraph} />
      ...
   )
}

But wait… although this is a cool API with clear benefits, it felt wrong, it still has too many steps. Before going further with anything, I took a break to think (or was forced to, time to move abroad!).


first off, I did content in JSON because I needed it for i18n, but why am I using MDX now? markdown is an easier way to write HTML, and MDX is the same but with support for React stuff. I’m conflicted about this approach, it’s simple enough but it still takes the content away from where it belongs. It does allow me to write MDX so for the time being I’ll be using it in some places and ignoring it in others.


Update

After dogfooding this approach to markdown on this very website, I can confidently say . As much as you can format your content in plain JSX, MDX makes it easier to write and read without taking power away. I prefer reading some *'s and _'s over a <span> soup every time.


Preparing to migrate to Next.js 13’s App directory , I ran into enough bugs with my MDX solution that the absolute GOAT, Marcos S. , helped me rewrite it into a much safer approach with no mutations . While at it, he planted the seed of a simpler API in my head. What if <MDX>**Content**</MDX> just worked™? Knowing that the server has to serialize the content meant this approach would be hacky at best, and straight-up impossible at worst. That is, without server components.


Fast forwarding to my migration to Next.js 13, the notion of "server code in getStaticProps, then prop drill to components" became obsolete. In the App directory, you can await server code on the component itself. With the only barrier between me and Marcos’ API shattered, I implemented it in what felt like seconds, thanks to the efforts of the Next.js team and the Remote-MDX maintainers .


Now, my concerns of MDX adding too many steps flipped upside down, NOT writing it has more overhead. The current API looks like the following:

import MDX from 'components/MDX';

export default function Page(){
  return(
    <MDX>
      {`
        # Oh wow,
        This just **works**.
      `}
    </MDX>
  )
}

Finally, the editor is getting out of my way as I write. And if this approach sounds interesting to you, it's completely open source  and easy to incrementally adopt.