Intermediate Gatsby with Gatsby Themes Syntax Highlighting
This course has been updated! We now recommend you take the Intermediate Gatsby, v2 course.
Transcript from the "Syntax Highlighting" Lesson
>> Jason Lengstorf: We wanna get the ability to share code snippets, because it's docs theme, right? And so a very common use case for docs name is gonna be to share code. So, the next thing we're gonna do is set up a syntax highlighting. And to do that, we're going to install a couple little helpers.
[00:00:18] So let's do yarn workspace, gatsby-theme-docks and we're going to add the prism-react-renderer. And then we're going to use mdx-utils, which will help us handle some busy work of making the react renderer work properly.
>> Jason Lengstorf: Once those are installed, we can go in to our docs package, and we'll create a new file in components, that is called code.
[00:00:56] And we're gonna use this as our kind of code highlighting, syntax highlighting element. So, let's set it up to use theme-ui, so import jsx from theme-ui, and then we're going to import preToCodeBlock From mdx-utils. And this will allow us to get some props out of the pre element and switch some things up under the hood, so that it's compatible with the prism react renderer.
[00:01:31] Then we're going to import the highlight component and some default props.
>> Jason Lengstorf: From prism-react-renderer.
>> Jason Lengstorf: And finally, I'm gonna import a theme from prism-react-renderer/themes and the one that I want is nightOwl which is Sarah Drasner's theme. It's also the one that we're using in the editor today. It's my favorite.
[00:01:59] So now that we've got this we have the ability to start showing the stuff, so let's create a component called code. And that's gonna receive some props and inside we can do, our code props are going to, this is where we use that preToCodeBlock on our props. And so what this is doing is it's giving us like what language is the the pre block using.
[00:02:28] Do we have the the code string separated from the rest of the the markup of the pre block. And that just makes our lives a little bit easier. So the first thing we're gonna do is if we didn't get any code props, then it's not a highlightable code block.
[00:02:45] Because there is a chance that somebody's just using it to show block text, or that it's a quote, and not necessarily code. And if that's the case, we're just gonna return a pre tag. And send in the original props. So that's our bailout. If we don't get any code props back, we just send back at default pre tech.
[00:03:05] If we do have code props, we're gonna pull some of those out. So we want the code string and the language specifically. And we get those out of the code props. Then, we are gonna return some stuff. And now, this is a little bit of an early looking component.
[00:03:23] So just fair warning, this is gonna get a little hairy, but it's very cool when it works. So we start out by using this highlight. And inside of it we are going to spread out the default props. So that if all else fails, it will have some defaults and at least not look completely broken.
[00:03:43] Then we're gonna set the code to the codestring. We're gonna set the language to the language. And we'll set the theme to the theme. This one uses the render props pattern, which means that we get a function back. And inside of that function we can do things. The, the props that will get in this render prop, is the classname, style, tokens, getLineProps which is a helper function, and getTokenProps with is also helper function.
[00:04:23] And we are just getting started. So then we are gonna put out a pre. And this one has a class name of className. And then it's going to use a style of style,singular and then we want to add a little bit of helper to make sure that it looks similar to it.
[00:04:53] We just want it to look nice in our theme. And so we're gonna have a little bit of patting and then if the code block is long, we want to scroll, not over flow and finally I'm gonna put a hook in here using a variant. Now we haven't looked at variants yet.
[00:05:13] We'll get into those in a little more detail a little bit later on but what these are is effectively a named way for someone to override styles in the theme-ui config which we're adding this as kind of a convenience thing. If somebody uses this theme and wants to override the prism highlight styles.
[00:05:31] They can do it by declaring a prism highlight prop in their theme UI config, instead of having to inject this component and deal with all of this kind of clutter that we're creating here. So, once we're inside our pre, then we're going to map over our tokens. And the first one is going to give us the line and then it's index, right?
[00:05:58] And inside of this we're going to spread out the results of getline props because we need to get those and it's an object. So we pass in line, and then the key is gonna be the index and that just gives us a unique key for it. Then, inside of that, we're going to map over the line itself and that's going to give us a token and a key.
[00:06:31] And finally we get a span. And this span is going to get the tokenProps. And the values there are the token and the key. Okay, has anybody's brain melted out of their ears yet? This is a, like big hairy component. So, we're doing several things. We start by just wrapping it in the general highlight component, that's a prism react renderers kind of hey, let's set all the defaults that we need for the highlighter to work.
[00:07:06] Then, We get all these defaults in here and create a pre tag. And then the way that a highlighter works is it breaks the string apart. So it's not just, your code block, and then you get a bunch of string with code in it. It takes that code and it breaks it up into all these tokens.
[00:07:24] So there's keywords, there's lines, there's all sorts of stuff like that. We start by taking the tokens and breaking them into lines. Each line is its own div. That gives us the ability to do things like number the lines, or do zebra striping to make it easier to track, or highlighting lines.
[00:07:42] Then, inside of the line, we have to get the token. If we look at the way that highlighting is working here, we can see that the bracket is one color. The variable is another color, the function is yet another color. So each of these things is actually broken up into a token that we are then wrapping in a span, which allows prism to highlight it.
[00:08:04] So to make this work there are two more steps. The first thing is we're going to in the Gatsby plug in theme UI, we can specify what components get used for a given MDX HTML value. So we can over ride what it gets as a pre tag which we would create by using fence blocks or just writing an HTML pre tag.
[00:08:32] We can tell it whenever you get one of these use something else in its place. So we do that by creating a components.js components. Make sure it's yes it is plural components.js. And we're doing that inside of the Gatsby plugin theme UI. So source. Gatsby plugin theme UI components.
[00:08:54] And then inside of that, we can import our code component from components code. And then we just export an object, and we tell MDX that anytime it encounters a pre tag to use that code component. So, with that being done, now we can take some code. So let me just copy this out, and we can go into one of our pages and I'm going to.
[00:09:28] Add some code, put it inside of a fenced block with the js language tag. And upon saving this and starting the server,
>> Jason Lengstorf: We should be able to see some highlighted code
>> Jason Lengstorf: Did I forget to export the code? I did, so we're going to export default code from the code component and that should solve our problem.
[00:10:05] There we go. So now we're getting any code that we drop in gets langauge specific highlighting attached to it. And if we add something else, like if I go into this index.js, wherever it was. And I add, let's say some,
>> Jason Lengstorf: It's not gonna try to highlight that, so it'll just leave it alone.
[00:10:33] Okay so now we can save our work.
>> Jason Lengstorf: So we added some new packages, created that code, component added that code component as a override for the pre tag in gatsby-plugin-theme UI added some fence code blocks to our index mdx.