Digital Gardening with MDX Magic
Kathleen McMahon walks us through a real-world MDX digital garden implementation
Transcript
Kathleen McMahon: [0:01] Hello. My name is Kathleen McMahon, and I'm so psyched to be here speaking at MDXConf. I'm here today to talk to you about "Digital Gardening with MDX Magic."
[0:11] Before we begin, let's get some details out of the way. My slide deck will be posted on Notist after this talk, including links to the resources I briefly touched upon. The full URL will be available after the event on Twitter. You can follow me @resource11 on Twitter, Instagram, and GitHub.
[0:32] Before we dig into the details of the talk, let's back up a bit so I can introduce myself better. I'm a principal engineer, and I will soon be joining CarGurus RAD people there. I'm so excited to start on that team. That will be next month, in September.
[0:49] Also, I race bikes very badly. Mostly, you will see me in costume racing [inaudible] at the back of the pack on a single-speed, mostly unless something random happens, like perhaps a pandemic kicking in our doors, then your race is postponed. You have to focus on something else like perhaps reworking your site, digital garden style.
[1:20] What is a digital garden? You may ask. If you haven't heard the term, a digital garden is a site that is collection of pages and posts in various states of completion. Joel Hooks made a great quote to talk about the metaphor of what a digital garden is.
[1:36] The phrase, digital garden, is a metaphor for thinking about writing and creating that focuses less on the resulting showpiece and more in the process, care, and craft it takes to get there. In other words, it's a great place to get your thoughts down and care for it later or not.
[1:57] Now, why did I choose the digital gardening way of doing a new site? Well, I'm not sure about any of you all. I have more than one personal site that I've created over the years using the technology of the time.
[2:16] Every once in a while, I look back at that site and think, "Wow, you should really update that code, Kathleen," or, "Those designs look a little bit long in the tooth. Don't you think?"
[2:26] My brain starts going, "Should I refactor the site? Should I refactor all the projects? Will I make questionable choices in the redesign and end up with something like a recipe that combines Jell-O with shellfish?"
[2:40] Oh, maybe not, but then my brain wanders over too, "Hey, should I toss out all those sites and start again? Wait, what about the blog posts I wanted to write? How should I structure those blog posts."
[2:53] Right on cue, option paralysis makes an appearance and nothing gets done. Years go by, and the cycle repeats. Woof, that's a lot.
[3:06] Digital gardening resonated with me because it is the perfect blend of what works in the way I like to create a site. I could create a site that is more of a catch-all for all my interests -- publish what I want, when I want -- and without thinking of that state of done. I could keep moving.
[3:28] I could make a code reference for future me to remember, something that I learned at the time. If I want to go back and edit, cool. If not, no big deal.
[3:39] How does MDX fit into this? I think of MDX like my mom's garden in the spring. MDX is the soil prepped and ready with a layer of bark mulch, rocks lining all the pathways to give you a hint of guidance, providing a solid start for your garden design, yet allowing you the freedom to plant in whichever way may happen to suit your mood.
[4:13] MDX also reminds me of coloring books, especially the magic series of illustrations created by Johanna Basford. Her illustrations are wonderful on their own. Yet, they give a good basis to show up your own creativity.
[4:31] You can enhance or cultivate the illustrations to whatever state of done that you prefer, rework them to different shades and colors, and add a level of detail that makes sense to you. In the end, the product you create looks great. That is what I call -- in another way of saying it -- magic.
[5:05] This is how I think of MDX. MDX is the magic that makes a garden great in whatever form it happens to be created.
[5:18] Now, there are many benefits to using MDX. You can write a blog post using Markdown. You can import React components right into file even better.
[5:28] MDX will compile down into Semantic HTML, which in turn makes your site more accessible, better support for your users that rely on assistive technologies to access your blog.
[5:46] You can use frontmatter as props to control what you display on the page. You can import your own components or components from other libraries. You can use shortcodes. You can override the styling within a Markdown tag and make it globally available on your site. I'm going to be demoing some of this stuff very soon.
[6:07] When I originally created my digital garden, I chose to use Gatsby which supports MDX and provides a Webpack and Babel config similar to create-react-app. This way I could start with a scaffolded project and extend it as I needed.
[6:26] Now, I'm going to talk quickly about configuring for MDX, and then we can dig into the greatness of what I love about MDX. The default setup for Gatsby is great, but I had to make some adjustments to make Gatsby work for my needs and for how I wanted to manipulate MDX.
[6:44] In the gatsby-config file, I am going to show you get into the code a little bit. Gatsby-config file, let's get over there. In the gatsby-config file, I added some post gatsby-plugin-postcss to support my postCSS and CSS modules.
[7:10] Also, I added in some gatsby-plugin-mdx support. That way, my site will recognize MDX files and making sure that my posts will resolve to this post-mdx-layout file that I've created.
[7:29] I've also added in here -- scroll, scroll, scroll, here we go -- some support using the gatsby-source-filesystem plugin to allow me to find the pages that are in the source-posts folder. That is where all my blog-specific MDX files live.
[7:59] Next, I'm going to talk really quickly about my gatsby-node file. My gatsby-node file....watch part of me while I go behind the scenes and pull up my notes to keep me on track.
[8:12] In the gatsby-node file here, what I did was also I added some custom nodeFields that I wanted to be able to access with graphql so I want to be able to hit certain things in my frontmatter, like featuredImage, whether an image is featured in my post, whether I want to show or hide one of these posts, and whether I want to publish this post now or at a future time.
[8:42] I also use the createPages method to use graphql query to query all the MDX files, looking for anything that is in the posts folder, and sort it by the frontmatter_date, and then grab the node id and the slugs there.
[9:02] I could take that information and programmatically generate pages for all of those any pages that are in the posts folder and resolved the path to whatever I needed to do.
[9:18] Next, in my gatsby-browser file, this is the file where you want to add things if you want to have site-wide changes. Here, I added some global styles that allows me to have some generic styles on my blog page.
[9:41] Also, I have this wrapRootElement that I'm going to be talking about later. This is where I'm going to show you how you can do things like shortcodes.
[9:53] Next, there is one more thing to do, is I needed to adjust my mdx-layout template. In this template, one thing I needed to do here was make sure that I added the MDXRenderer into this file and wrapped it around the mdx.body that is coming into my layout.
[10:25] This is very important because my posts are not in the source-pages directory. They are in the post directory. In order for you not to see gobbledygook on the page, you need to wrap your mdx.body with this renderer in order to see words on the page.
[10:56] Now that we have this all set up, I'm going to show you why I love using MDX. I created a quick page called...Basically, it's Digital Gardening with MDX Magic. What I have up here is my frontmatter. What I like about this is you can add props like this and use it in graphql queries to decide how you want to organize your files, if you want to show files, if you want to hide files.
[11:29] For example, here I have the prop by frontmatter, isPublished property, set to false. Because of that, when I look in my right page, everything is ordered by oldest to newest here. As you can see, this file was published in April 29th. This particular post will be published today on the 24th.
[11:55] Because I have this set it to isPublished: false, this is not showing up. What I could do here is...If you look -- let me just dig into the page really quickly for you -- in my pages, the write.js pages, I have a graphql query here that is pinging all the MDX files.
[12:20] If you look, the frontmatter is set to isHidden: false and isPublished: true. Once those are found, then I can click and sort everything, grab anything that we need in all of this data, and render things on the page.
[12:45] You can see isHidden is still false, but I'm going to set this to true, not gure but true. They take two, take three. There we go. Now, go over here. Look, voila. The page is published. That is awesome.
[13:07] Also, in my post-mdx-layout here, I also have the graphql query that is looking for in the frontmatter, whether you have passed in a featuredImage. If you pass in a featuredImage, you are going to use gatsby-image.
[13:29] If a featuredImage exists, you are going to apply childImageSharp properties to it to make sure that it scales fluidly. You're going to edit right here as an image.
[13:49] I love gatsby-image because it's using under the hood, the picture element. What is great about the picture element is it's going to optimize your images and also serve up images at the correct sizes for the different viewports that you have set under the hood in your queries. It is pretty awesome. It's pretty streamlined.
[14:13] Sometimes, gatsby-image is a little bit of a learning curve, but what I'm doing here is I'm going to turn this on. First, I'm going to show you...We're going to get into the file so you can see it. There's the file. As you can see, we have the dailylilies-in-july in the same folder as the digital-gardening post.
[14:33] If I unhide this, bam, we have an image. This is awesome. What's really great about this is you could have this featuredImage prop. If you drop in an image in your folder, wherever you are in any of your particular posts here, literally any of these could have dailylilies-in-july if they wanted.
[14:59] Whatever you want to point to, it's just easier to have it hosted at the same level as your particular file, but this is pretty awesome. This is the power of frontmatter.
[15:11] One final thing I'm going to show you on frontmatter also. In this page, I have it querying for...and it's only showing any of the posts that have happened to have isFeatured. It's a featured post. If I did this, if I could also spell it today, it will. There it is, show it up, which is awesome.
[15:35] I'm not going to do that. I'm going to go back to false because I don't want that featured just yet. Maybe later.
[15:43] Moving on, you can if you want to...Well, you can. What's great about MDX is you can import. I have to show you this slide. You can import React components. That is awesome. You can import your own component. You can import components from other libraries. I'm going to show you a quick one.
[16:15] I'm going to show you what, my favorite one first. I'm going to show you gatsby-embed-mdx. This one is awesome. With Gatsby MDX by Paul Scanlon, he has made this plugin for Gatsby that provides these wrapper components that will allow you to pop in. YouTube embeds. Instagram embeds. Flickr embeds. Twitter embeds and more. All these social embeds right into your file.
[16:52] What I'm going to show you here is that. Let me show you really, really quickly. My brain will come back in a second. I am doing a little bit of Julia Child action right now.
[17:07] First, what I'm going to show you is, one thing that's very important, to make the gatsby-embed-mdx available to your files, is you have to make sure that there's a provider that is passed in to your component.
[17:27] Where I chose to put it the MDXProvider from gatsby-mdx-embed, I choose to wrap that around my entire layout component because this set of components are so awesome that I want it available throughout the entire page.
[17:50] Whenever we use a layout component, we will have all the components that are passed in under the hood to this provider, and I can use this straight in my digital gardening post. What I'm going to do is take my Julia Child Solution and I'm going to pull out...
[18:13] For example, are you ready? I'm going to show you Gatsby plug-in embed examples four. Let's see, CodePen, Flickr, YouTube, and Instagram. I am going to give a caveat here because I am demoing this in Chrome and I can't open up Firefox to show this.
[18:43] Chrome is blocking the same site origin. We're having a CORS issue right now with the CodePen embed. Let me just show you at least what you're going to see here.
[18:55] For example, right below this, right here, ready, Gatsby plug-in support, ready.
[19:06] Now, let's go back over here, go back to our component. Ready, one, two, three, and CodePen embeds, Flickr embeds, YouTube embeds. Look at that, it just placed it right in there and you just put IDs and you can have social embeds in there.
[19:25] Let me see if I can get...Yes, I can. Cancel whatever that's canceling. There you go, are you ready? Let's get to the right page so you can see it. It is not showing, but I don't care. There it is, see, look, no CORS issues on Firefox.
[19:53] Anyhow, that is Gatsby-mdx-embed. I love that. The next thing I'm going to do is I'm going to show you this. Are you ready? Shortcodes. Shortcodes are amazing. With MDX, you can swap in React components with Markdown tags.
[20:19] You can do some really cool things because, in Markdown, you have your standard H1 through H6 paragraph tags, link tags, unordered lists, ordered lists, images, etc. What I'm going to show you, first, is that you can, one, pass in your file. We don't need the layout file anymore.
[20:43] What you can do is you can pass in to your...This is where you're going to pass in, use your wrapper element file. This is the area where you can define some components and pass it in to a provider here in your wrapRootElement file.
[20:59] You can take this wrapRootElement file and import it and export it from the gatsby-browser.js file, and that will make all these available throughout your site.
[21:10] What I'm going to do here is, first, I'm going to bring in some general files. You know what? I'm going to do it both at once. I'm going to add this first. I want to add some buttons.
[21:43] You know what? I just want to pass in for now. I want the button, and I want the DisplayBox. I'll just take them all. What's nice about this? I'm going to take this. Also, I am going to see if I've added a code block in there.
[22:00] What I'm going to do is I am going to take...define some components, define the components, and pass in things like the buttons. Those just general things that are available...Look, it broke. We'll fix it. What we're going to do is we're going to take those components we are defining, and then we're going to pass it in to the MDXProvider.
[22:45] What I can do if I wanted to? Now, see here, I have a button passed in here. If you look at the file right up here, the button is showing up. Look at that. See? Why did that work?
[23:08] Let me tell you why. Because in this wrapRootElement file, what we did was we are taking the button all of my local components, and we're passing them in as component, passing them in as a scope that will make these available to all, anything that is wrapped by this wrapper element, which means everything.
[23:32] Now, why I like this is, in any MDX file, I don't have to do at the top like import button from find the particular folder where to find those buttons. This is pretty awesome.
[23:46] I could sit there, and I could have a great time, just doing some quick edits with buttons, putting things in together. It's really nice. Everything is interactive. It's very cool, but these CodeBlocks aren't very fancy.
[24:07] What I'm going to do is use something called...Well, yes, I'm going to do that. First, I'm going to show you this, we're going to do custom CodeBlocks, and it's awesome. We were going to use a library called prism-react-renderer.
[24:29] We're going to import these files into our wrapper element file. We're also going to import, while we're at it, react-live library, because I want to have editable CodeBlocks. It is going to be awesome.
[24:48] To do that, what we are going to do is, in the wrapRootElement file, we are going to import the...make sure I have it. We need to have the { preToCodeBlock } from "mdx-utils."
[25:11] I'm going to show you, in the CodeBlock -- I've already done this ahead of time -- is I've added the MDXScope, the React LiveProvider, Preview, the Highlight from prism-react-renderer, and the theme. I can theme things and have syntax highlighting.
[25:32] What is great about this is I can use these libraries. When you write something like a pre-tag or a CodeBlock, mostly it's a pre-tag, in your MDX file, you can do some fancy things. Right now, if I do nothing, I will now always just get syntax highlighted CodeBlocks, once I activate it.
[26:06] What's a really cool thing, and I'm going to demo this in a second, is you can pass in props to your CodeBlock next to the name of your language. When you do that, you can customize how your CodeBlock shows.
[26:21] For example, if I'm going to pass in react-live, I'm going to take the wrapper that we used to create a live editable CodeBlock. I'm also going to use my DisplayBox, wrap it around to make some things really fancy. I can also do something very similar under the hood for react-live. They also use prism syntax highlighting, by the way.
[26:45] You don't need to add this, pair this highlight with it. If I wanted to have just a DisplayBox, I could have wrapped the React LivePreview in the box without having any of the live editor section or the error component and just have syntax highlighting below it. Just more of a static representation of the code.
[27:05] To activate that, we have to write some things in your wrapRootElement, like this. You would have to add in this. Make sure I have the comma. I do. Here we go. If I do something like this, I'm passing in to override the pre. If you pass in pre-props, you'll get some fancy syntax highlighting.
[27:35] Right here, you already got fancy syntax highlighting, which is really nice. That is pretty cool. I'm going to demo a little bit better in a second, but to keep us on time, I'm going to add one more thing. I will do it later, but first, let me show you here. Let me show you here because it's just too exciting.
[27:57] Let me get over here. Here is one of the things that irks me about MDX right now, and I'm hoping they're going to release something different in v2. I'm excited to hear that. What's interesting in the way we do this, if we could get everything...Here we go. I'm getting the code for you.
[28:25] If I actually just put it up here...If I put it up here...It's going to complain to me right now for this purple though, you watch. It's going to say that the button is not defined. I'm waiting. There it is. See.
[28:49] It looks like, "Where's the button?" because right here, this is the live error where we have a DisplayBox and a code, but the thing is it can't find the button. Here, it's passed in from the wrapperElement. That part vexes me, but there's a way to get around that.
[29:04] The way to get around that is you have to import again below your frontmatter, by the way, all your particular local components and have the correct path for everything to work. Once you do that, watch this. Hold my beer. It's compiling again. I'm going to refresh the page because I'm impatient.
[29:41] Looking at my stack trace. Everything should be fine. Success. I'm going to refresh because it should work. It is not working. Right. Something happened. Hold on. Clean and start again, and then I will show you the last part of this while this happens.
[30:16] That could also be a reason why. It's not like that. You needed to have that space between your horizontal rule. Do not fail me now.
[30:34] It's thinking about things. What's very interesting is, for some reason...maybe that will keep it from doing its thing. We will see. It's building. Something went funky with the horizontal rule tonight. Building the development bundle. At least I only have 10 pages. Success. Are you ready? I hope so. I'm ready. I'm ready to see this.
[31:43] Show me the file. There it is. See, look it, look. There's a button. It's awesome. What's really great about this is because I know what props I can pass in for my own button, I can just do some things right on the fly. It is awesome.
[32:02] In addition, what we are going to do is this one final thing, is I'm going to show you that we can override things in terms of we can also pass in things like headers in our...We could pass in headers once my file does not complain for me. Wrap root element. Here's my file.
[32:27] Everything is going to break for a second. I'm going to import grommet. I am going to override some of the heading levels for grommet. I'm going to do it this way like this, is you can pass in your heading levels for grommet. In order for grommet to work, you need to import its provider.
[32:54] It's going to complain a little bit. It's not going to show what I need it to show right now. It's not overriding with the styles that I needed. Let me show you what it will do. It will close that page. Close that page for now.
[33:14] In this post template, what we need in the post template is this. Get my file. In the post template, please. There we go. My post wrapper, I need a few things. First of all, I need to import grommet into my post layout. That would go right here.
[33:42] Once I have that, because you need to wrap your layout with the grommet...It's a provider. It allows you to grab the theme instead of theme. What I like about this is, this is the grommet's theme. It's going to cause a little bit of CSS conflict in a moment. See what I did there? I put in the grommet's dark theme.
[34:14] If I put in the grommet's light theme, if you can see, right above it, it's only the MDX file that's taking on the dark theme right now. Not any of the headers or footers, because they do not have the grommet provider wrapped around it. This is pretty cool.
[34:30] Now, if I turned off my baseline styles in my browser, which has my feature and everything else, you'll see the colors getting a little gray. As it rebuilds, look at that, see look it, it just took on all the grommet baseline styles. That's interesting, and it's fun.
[34:49] Now that I have the grommet provider in there and I have it in the layout, what I can do in my MDX file is I can pass in. I can import the grommet components in here. What I can do with that is I could, if I wanted to end my code on a code, I can add a grommet button here. Are you ready, when I put this here?
[35:33] I'm going to put it below here, because you also have to wrap things. We have a grommet button. It's going to take a second, then it's going to show. There it is. There's a grommet button. I could call it label x. Why am I doing it here? I could do it here. I could do it right here, because we're doing live editing, and it's awesome.
[36:13] I could call this a secondary button. This is the props that they support. I'm just going to do that. What's great about this is I can grab some of the stuff that grommet has set up for me, and in my React Live down here, I can put in some really, really fancy stuff for you. I'm going to do that right now.
[36:40] I'm going to show you some CodeBlocks at the bottom, and then I'm going to wrap this up. Here is your custom code blocks section. It's interesting how the Instagram one took a...I shouldn't have done that. Let's fix the Instagram post. That shouldn't have been there.
[37:12] Let's let it rebuild. Ignore our codes error. Watch everything show up. Instagram is taking a bit to do, because that's what it does. Look, little playground. You can start messing with things. This is the share option button here. I can make it green or I can call it purple. Grommet supports all these awesome colors.
[37:51] I love this, because you can just have a little playground and share it with your users. You could post this and your users could start playing with a little playground right in your MDX file. I just love that about MDX. That said, I think we are ready to wrap up this presentation.
[38:21] In conclusion, MDX is pretty powerful. It's just getting better and better. I'm so excited to see what's going to be released with v2. Pair this with the freedom and creativity of the digital garden philosophy and you can cultivate some serious magic.
[38:47] Thank you.