skip to content

Create a Plugin for 11ty

We already know that 11ty is powerful. In this episode, Bryan Robinson will teach us how to take 11ty even further with custom plugins!

Full Transcript

Click to toggle the visibility of the transcript

Captions provided by White Coat Captioning ( Communication Access Realtime Translation (CART) is provided in order to facilitate communication accessibility and may not be a totally verbatim record of the proceedings.

Jason: Hello, everyone, and welcome to another episode of Learn with Jason. Today on the show, we've got Bryan Robinson. Thank you so much for joining us, how are you doing?

Bryan: I appreciate you having me here today. I'm so excited.

Jason: I think it's going to be great. For those not -- I see you around the Internet, we work in the same circles, see you on the party corgi Discord. A whole bunch of other fun places. For those of us not familiar with you, can you give us a little background?

Bryan: Sure. I have been doing web development stuff for a while now. For like 14 years. And so, sorry, I have my own audio playing back --

Jason: Do you have Twitch open in another channel? You'll have to mute the Twitch.

Bryan: There it is. It was minimized, awesome. You would that like I don't do streaming on a regular basis with all of that. So, yeah, I have been doing web time development for 14 years. Worked at newspapers before they fought back against online and won. And then I did some work at a small agency for about 7 years. Led their design and development team for a bit. And then for the past two years, you have been what I consider myself to be a free agent developer advocate for things I care about. And a year of that time was present significant into 11ty. And most recently, for the past month, I'm a Dev rel at Sanity. io. Doing the things I have been doing for two years, but for them going forward. Super-excited about that and to be part of that team.

Jason: The Sanity team, good friend of the show, one of the sponsors. We have had guests in various support capacities. And so, I'm super happy to have you on the team. I feel like that's a good group of people and you're going to fit right there.

Bryan: Awesome.

Jason: We were talking before the show that Sanity powers some of the visuals of the show. What you're seeing right here, wait, over here, the name, Bryan's name and the title of the show down below. That's stored in Sanity. The same information on the website with is pulled into the overlay so I don't have to manually update when the episode is going to live. That's fun. I really like using Sanity for that.

Bryan: Legitimately, didn't know that before we were talking before. And talking about we're starting our streaming adventure on Twitch. You know what would be cool? Building an overlay with Sanity. There's a proof of concept in the wild for that. It's exactly what you just mentioned. A stream overlay, but also a website. You wouldn't think those pieces Data would connect well. But that's kind of the whole theory blind, you know, structured content as opposed to like the whole tied together CMS.

Jason: Right. Right. Yeah. And that's -- I think that's what is really interesting about the space that we work in right now. And so, you want to talk about that. But first, there's a good question in the chat which is, what exactly is a developer advocate?

Bryan: That's an excellent question. And honestly, I feel like you are better suited to answer that. But for the most part me having been a legitimate developer advocate for about a month and pseudo my own style developer advocate for a few years, I viewed as an educator that's passionate about an area and wants to get as many developers, technologists, whatever, involved in that as they can. So, for me, for about two years, the beginning of it was CSS. I'm super-passionate about CSS. And then JAMstack was a big thing for me that I latched on after I started my own business. And obviously when you're working for a brand, you're advocating for their tech stack. But also everything around it. Not necessarily you have to use Sanity. It's the most amazing thing ever even though you should and it is. Everything around that, the whole JAMstack ecosystem. The bigger the JAMstack ecosystem gets, it's better for Sanity and the others inside much it. Such as Netlify and others.

Jason: Developer advocacy is an interesting space. Every company that I've talked to defines it a little bit differently. But the common thread is if you start to think about a company's economies existence in the world as a Venn Diagram. You have the people who use the platform. And then another circle, the people who build the platform, you've got marketing. You've got education and docs. And right in the middle of that circle where everything overlaps, that's sort of where developer advocacy fits. Because we need to be engineers. Because we have to be able to build and understand what the tools that we're attempting to get people to use. We have to work with customers, we have to work with people who are trying this out. We have to understand feedback and we have to escalate that back inside the team. We have to make sure we're routing -- when people struggle, we have to show our team how and why. We have to help marketing because marketing is typically people who are very, very good marketers and don't have a lot of engineering experience. We're helping to connect the marketing message to actual code. Thank you so much for the bits, Steve Thompson. That's wonderful. Great to see you here, by the way. And then you have the other -- there's a support side to this, there's a documentation side to this. What I like about developer relations or developer advocacy or developer experience, however you want to frame it, is it's a great way if you are somebody who has a hard time staying in one lane. If you're interested in product, if you're interested in writing, if you're interested in building, all of these different things, developer advocacy is going to touch on all of those different lanes and you're going to get an opportunity to work multiple modes across the business. The frustrating part is you don't get it be deep, right? You rarely get to the take a project and go all the way to the bottom. Usually you're gonna tee something up and get it started and hand it off to an engineering team or to sunset it as a proof of concept or whatever. But the flipside that have coin is you get to do so much. I feel like my job -- I've repeatedly called my job professional play time. Like I just -- how is that, you know, I get to host a TV show on the Internet for a living. This is super-weird. But it's also really fun. You know? This stuff is really, really rewarding, I think. And so, it's good for me.

Bryan: It's a cool thing because you get to do all sorts of different things. Not just didn't code. But you have a whole audio setup, rack set you were and all that, and the streaming and videographer and video editing. You don't have to be good at any one of those things. You have to be pretty good at a lot of different things and you get to experiment with the newest stuff. Like I started Twitch streaming in January. I would like to stay I'm the last of the hipster live coders I got into it right before it got cool with COVID. Just barely before it got cool. But we get to do really random things and see what sticks and place our bets on the things that we think are sticking. It's a lot of fun.

Jason: Quick shoutout to the chat, thank you Ximena, and others for the subscriptions and the bits. A Hype Train is going. This Hype Train is a whole new adventure, right? But what's up, chat? I think there were a couple other questions I wanted to look at.

Bryan: A shoutout to Dan Thompson who did those bits. A Memphis Dev. I'm no longer a Memphis Dev. I'm a Michigan Dev. But I'm wearing a hack Memphis T-shirts from a hackathon a few years ago. Appreciate the Memphis -- the Mem tech crowd.

Jason: He's great. He's showing up every once in a while. Glad to have you in the chat. Brad asked, is it still just an HTML page pulled into OBS? Yes. That's exactly what it is. The whole design of this website is actually just an HTML page. The HTML just kind of sets up a frame and then there's transparent video and my video and Bryan's boxes are set up behind it. It's a Zoom call that I made look fancy. (Laughter) Yeah. And then I think there was one other question. Where did it go? I might have lost it.

Bryan: And you can do a whole bunch of stuff. I have mine hosted on Netlify. I have the broad overlay on Netlify. It's there. And I ingest it into OBS. Nice rain bow backgrounds. There's a unicorn that speaks when people chat different things. It could be better as I start playing with Sanity and integrating it there.

Jason: Yeah. I just realized I screwed up my own. Bryan L. Robinson.

Bryan: Yes, Bryan L. Robinson. I'm Brob on the on Twitch.

Jason: You were the last of the hipster live coders.

Bryan: I've got a four-letter Twitter handle. You don't get those anymore. On Twitch.

Jason: And cap's here. Cap's going to be on the show in a few months. Great to have you here. All right. Let's talk a little bit about what we're actually going to be doing today. We touched on Sanity and Netlify which are in the JAMstack space. But today we're specifically working with 11ty. And 11ty is a static site generator. So, can you tell us a little bit about like what -- what's 11ty and what makes it different from other -- or chat, you can tell us, do we need to talk about what static site generators are? Respond -- boop us if we need to. But in the meantime, do you want to talk a little bit about 11ty?

Bryan: Sure. Like I said, when I have been doing my own thing, I got kind of really into 11ty. So, my JAMstack journey kind of began like 3 years ago, 5 years ago, and I got into Jekyll. I hate servers. I was managing a huge rack space server for an agency that had like hundreds of sites and I'm terrified. Like, I don't want to mess with servers. And so, like, we did it on our doc site for our internal use in Jekyll. We many a Ruby Dev on staff. Let me experiment. Oh, I love this. This is great. I can do all sorts of data stuff with just YAML and JSON and stuff like that. And so, I got really into that. Converted my site over to it. Went hard into static. I'm old school. I love HTML. HTML is super near and dear to my heart. And so, I liked it, but I kept finding myself doing a lot of Gulp tasks around it. Making these things work. Data fetching and stuff like that without touching Ruby. I don't really know Ruby. I could probably make it right. But it's Ruby. I'm a frontend guy. I like JavaScript. I heard about this 11ty thing and I played with it. I said this looks like Jekyll but with JavaScript. It's not like that. There's a whole bunch more, but it can feel like that. And the first thing I saw was there was a 24-ways post about it four years ago, three years ago.

Jason: Oh, yeah, yeah.

Bryan: Turning my Jekyll site over to 11ty. It was converting a Jekyll site to 11ty. And I did that with my personal site. It's about rendering HTML to the browser. No opinions on the frontend, don't have to know React or Vue or Svelte. You have to have knowledge around template engines and it comes with a bunch. In Jekyll. we had liquid, it was decent. I love that enough. It's the default for 11ty. We get Nunjucks, which is even more powerful. You can use just JS template literals as your templating engine as well. And handle bars. There's a whole bunch of different things you can do with it. It's all shipped with it. But you can use them one at a time, all at once. You can do a whole bunch of cool configuration which I really, really love.

Jason: Yeah, absolutely. Yeah, there were a couple questions about just kind of 11ty in general. I'm going to -- let's talk a little bit about what static site generators are in the abstract. Because there were a couple people who booped for more information. (Laughter) So, we had -- we -- like, if you think about the -- so, the traditional path for building a website was to write HTML. You would have index.HTML, and start with the tag, the head and body tags, all of the markup. And this was fine for small sites. But what it lead to, if you need and about page, you had to copy a whole bunch of HTML to about.HTML and only change a little bit in the middle. As time went on, this became kind of unmaintainable. If you remember the '90s websites, there were a lot of websites where you could watch the progression of the website. It was a time travel thing. The home page is up to date, but clicking through, you would see different iterations of the website. It was like a geological dig.

Bryan: Like a UX nightmare.

Jason: It was exactly that, right?

Bryan: Terrifying.

Jason: You would see C GI scripts or PHP born from this. PHP was short for personal home page which it's no longer short for that. What -- it's a recursive acronym. It's also a backcronym. I love the ways that we justify how we change the names.

Bryan: I've never heard of the term backcronym. But I like that.

Jason: It was personal home page, now PHP hypertext pre-processer. Whatever. But the idea was that you would run a server and then a request would go into that server and the server would interpret is, find the data, use a template, smash those things together and return them. And this would all happen at request time. Which is cool until you have too many people visit your website. Your server gets overloaded, it crashes, or your data for whatever reason is unavailable and that causes a crash. All of these things led to scaling problems. You saw an explosion in how to descale things? Docker containers, Kubernetes, all that. As this was happening, as we were trying to figure out how to scale servers, there was this other movement with things like Jekyll. Jekyll and Hugo and early node ones like Hexo. Yeah, exactly, right? That were all built from this idea, what if we did that server-style thing where we take the data and we take a template and we mash them together. But what if we did that first? And then just served this instead of having to wait for somebody to request it. Moved the server side rendering to build time rendering. Now I can say here's my template, here are my pages of data. I want to take all of this data, throw it into this template and generate my HTML. And then I'm going to upload the generated HTML to the website and everyone will interact with it as though it were just plain HTML. That's the core concept of the static site generator. You're working with just the data that changes and you have a template of what doesn't change and stick the data in to make that. So you as a Dev are doing less repetitive work and the outcome is still plain HTML that is still really easy for everybody to use. No servers between your users and the content they want to view. But where this gets interesting is like with stuff -- as you mentioned, using Jekyll. I used Jekyll for a while, switched to Hugo. I hit the same hurdle. I don't write Ruby or Go. I was trying to make these things cooperate with them. I lacked the knowledge to use them are the way they wanted to be used. I was looking for a JavaScript solution. This is where you and I diverge. You went to 11ty and I did Gatsby. I did an episode, I dropped the link in the chat, with Zach --

Bryan: The brain behind it.

Jason: Zach is the creator let's learn 11ty. If you scroll back in the chat a little bit, you'll see it as well. So, what's the difference gene like something like Gatsby and something like 11ty? Like why would you choose one or the other?

Bryan: So, for me, and again, I'm coming with lots of personal and strong opinions. First and foremost, 11ty is completely un-opinionated around frameworks. Especially around the frontend. There's a really cool Tweet the other day that Zach referenced that was one of the built with suits. We're working on getting our NUX built with support in. We're going to be able to show people websites are built with Nuxt. Are we going to get free 11ty? We have no clue how to identify a site built with 11ty. Zach chimed in, that's intentional. That's how it's developed. It ships nothing to the frontend that you don't write in your templates. That goes for any frontend code. If you want to write your fancy JavaScript on the frontend, you're writing your JavaScript to the frontend. Everything that's shipping is HTML that's renders, right?

Jason: Yeah.

Bryan: There's no rehydration, nothing out of the box. You want to write as close to HTML as I can. I like Nunjucks and liquid, the feeling that I get out of HTML with the power that you mentioned and why we use the site generators. Like it's dynamic things at build time. And then if I want to rehydrate it or bring in new functionality, I can progressively enhance into it. Gatsby, Gridsome, Nuxt, Next, when you don't want to rewrite a bunch of stuff. You can ship all of your components in a Gatsby site in the frontend and it takes over and becomes like a single page application. 11ty is rendering HTML pages and we're making sure that a fast CDN is in front of it so that all of those pages get downloaded super-fast and it's quietly doing it. It's behind the scenes. No one on the frontend's ever gonna know. I think it's amazing for small to medium sites. So, blogs, like agency-style websites where you're making like a 15-page small business website it's amazing for. There's a bunch of stuff that I think it's amazing for, but if you want to bring your super-interactive stuff from a React or a Vue, you're going to do either some rewriting or some heavier frontend work to make that happen.

Jason: Yeah, for sure.

Bryan: I tend to avoid a lot of that when I can. But those platforms are way better for that sort of thing. Although there's some Vue stuff coming in 11ty which I hope is going to be cool too.

Jason: Yeah, I've heard Zach Leatherman talking about that a little bit. There's some Vue interop in 11ty that's at least in experimental phases, which is pretty exciting. So, okay. So, we've talked about it in the abstract. And I think that that is, like, I would encourage anybody who is curious about this stuff, with static site generators especially, there is a reasonably short onramp. So, like, I would encourage you if you're kind of waffling between, use the ones that are in languages you know. That's going to make your life easier. But try everything out there. You know, build a little site. Try to get some data. Try to do something interactive and get a sense for like what for your requirements which one feels right for you. Because this is very much coming down to -- it's now a choice of flavors. Static site generators are going to do good for you. They have benefits. We're not going into the architectural like why the JAMstack. There are lots of articles on it. And I would encourage you if you're not familiar with the JAMstack, read about the benefits. But they give you most of the benefits of the JAMstack out of the box. Now it's not a choice of good versus bad, it's a preference. Chocolate or strawberry or vanilla and you can choose which one you like and which one feels best to work with and get a lot of the benefits without having to reinvent wheels or do anything like that. So, today, though, I want to dig into 11ty. You were going to teach us not just about 11ty in general, but more specifically how we can extend and customize it.

Bryan: Yeah. There's plugin functionality built into it. It's not as robust as Gatsby's plugin ecosystem. But there's a lot of cool things we can do to extend and make portable the things that we would have to configure in every project.

Jason: Cool.

Bryan: I want to mention thegreengreek in chat, and, a few different articles on 11ty and data and a whole bunch of other stuff. And there's a link in chat. But like that work is great and I read her stuff constantly.

Jason: Wait. Sia. Is your -- is your Twitch handle different than your Twitter hands or am I just now realizing that you're thegreengreek and not thegreengeek. Oh, no. Oh. No. Well, that's embarrassing. (Laughter) Sorry, Sia. Okay. All right.

Bryan: We say green geek, but it is green Greek.

Jason: My brain never bothered to read that word. That's definitely geek, is what I saw. (Laughter) Okay. So, let's -- let's write some code, right? Let's switch over to pairing view here. And I haven't pulled anything up yet, right? We're just sitting in -- in like ready to roll mode. So, what I am gonna do real quick that I should have done before is I'm gonna pull up your Twitter. So, everyone should go and follow Bryan on Twitter.

Bryan: Awesome. I appreciate it.

Jason: All right. And then if you want to look at 11ty, we have So, the green geek Greek. And this is Sia who I have been absolutely -- I cannot believe that. Like, this is like -- did you -- have you ever read -- there's a paradox where like people earnestly believe that something was a certain way. Like the Bernstein versus the Bernstein bears. And there's people who very much believe that Nelson Mandela becomes in prison. It becomes your reality. I feel like this is one of those moments. So, yeah. Definitely go -- go check out Sia, spell her Twitter handle right. (Laughter) And we're ready. What are we gonna do today?

Bryan: Throw out one more link. My personal initiative.



Jason: I'm so mad --

Bryan: Blame Kolby if he's in here.

Jason: Are you in here?

Bryan: I don't know if he is. But I'm making like an open source plugin repository. Using Netlify CS's open authoring. I have a dozen in here. It doing a simple alpine JS search. Of course I had to learn new technology to do it. I have a few different ones, some of the basic ones in there. It's copy and paste a lot. I haven't done as many as I should. But just some simple search functionality. Because it's not always listed on the plugin site on That's like the top 20 or 30 there. So, I was like, let's see if we can all as a community come together and build something like this.

Jason: That's super cool, yeah.

Bryan: Right now it's me, there have been three people that submitted plugins. The more the merrier. Submit them.

Jason: If you're watching this, today is the day. You can create an 11ty plugin after you watch this stream and submit it here so the rest of the community can find it. On that note, how should I get started? What should we do first if we want to do this?

Bryan: First and foremost, what we want to understand about 11ty plugins is they are basically modular portable config files that you can include in other projects. My first prototype, I did a short code, going into the images directory, find an SVG and spit the contents on to the page to have an embedded SVG as opposed to an image tag. I did it on like three projects. I made a plugin for it. So all I have to do is add plugin, I think it's SVG contents and I have it right there. I don't have to write that boilerplate code over and over again. The first thing we need to do is create a directory and create a small 11ty project inside of it.

Jason: So, this will be 11ty plugin -- let's just call it 11ty plugins. That seems good. And then we'll jump in here. And I'm going to get init. And let's open it in VSCode.

Bryan: Nice. I love the teach command. That's awesome.

Jason: It's different settings for VSCode to simplify the UI and make it bigger and stuff.

Bryan: I need to get into that education automation. First initialize an npm package.JSON. I like to use npm/y to give the defaults. And then install 11ty to test things locally here. And later bring it into another 11ty project to test the functionality of it.

Jason: I'm installing it as a Dev dependency, right?

Bryan: You could install it as regular dependency or Dev dependency. It doesn't matter. Since we're not hosting a site with it, it doesn't --

Jason: This is a very interesting sidebar. When you use npm the way that most of us building websites use npm, the dependencies do not matter. Because you're not, like -- it's -- the Dev dependencies versus Dev dependencies versus peer dependencies matters whether you're shipping a plugin. When somebody installs your package. That means they need to know what they should and shouldn't install. When you're doing it as a site, it doesn't matter. You can include all of your Dev dependencies in the Dev artifact and it doesn't matter. This is becoming more and more clear to me. I used to care about this, is this a peer or Dev dependency and I realized that I could not care less.

Bryan: Yeah, exactly. It's just -- it's whatever.

Jason: Okay. Here we go. We're installing 11ty. What else do we need here?

Bryan: We're going to have probably an index.HTML so we can test out some of our plugin functionality. Actually, let's make it an index.markdown so that we can write markdown around it. It will make it feel like a blog post. I don't want to go through the process of setting up a collection just for small stuff. And a couple paragraphs of lorem ipsum in there.

Jason: Okay. Let me grab some lorem ipsum. I found a good one the other day. Phil found a Yorkshire ipsum. And it was a lot. I wanted him to actually do like a live reading of this.

Bryan: I would watch that. I would watch that every day. Twice a day.

Jason: And it's just full of so many amazing things that I, like --

Bryan: Where's the mock?

Jason: I have no idea. It's one of those things where I don't want to read it out loud. Maybe it's super-offensive and I've never read anything with in particular dialect. So, it's just, you know, well, okay. So, now I have -- I've got what up --

Bryan: The markdown.

Jason: Yeah, we've got some basic markdown. Let's link something, right? So, we'll just go to Discord.partycorgi if you want to come chat with a bunch of cool folks who like to build things. All right. We're ready.

Bryan: I'm in there, Jason's in. It's all good stuff.

Jason: Cool folks.

Bryan: Just the two of us, no one else?

Jason: Just you and me. I'm kidding. We're the worst. Everybody else who saves us.

Bryan: You're all right. I'm -- (Laughter) So, we also need an 11ty config file. That's .11ty.js in the project.

Jason: Okay. And this is -- no. This one.

Bryan: Nope, spelled out, yep.

Jason: Okay.

Bryan: The worst for 11ty is all the blog posts I write about it, I put a parenthetical. I worry about SEO, 11ty, parentheses, Eleventy.

Jason: I'm not a violent person. But when I see Zach, I'm going to give him a nuggie. In a head lock. It doesn't stop. To install the plugin, we all observed, you have to use the 11ty and spelled out. To go to the website, To follow on Twitter, it's not even spelled out. It's 11 underscore TY. Zach is a monster and needs to be stopped. He is a menace.

Bryan: I would guess he did that on purpose.

Jason: He's a freaking troll.

Bryan: Yep.

Jason: Good. Let's configure 11ty.

Bryan: The only thing to do right now -- you don't need to have this 11ty config file to run 11ty. Which is awesome.

Jason: Actually, can we do that first?

Bryan: Jay.

Jason: I'm gonna copy this and then I'm gonna delete the file.

Bryan: Okay.

Jason: Okay. And then to run 11ty, I'm gonna add a script for if. But we could do it out of whatever. So, let's build. And all I need to do is just run 11ty, like this?

Bryan: If you're going to build it, it's 11ty, if you're going to serve it and watch it, it's 11ty, dash, dash.serve.

Jason: Let's go both and call this one Dev.

Bryan: For the most part, we're not worrying about building. This is not a website. This is a plugin. People are going to be pulling it into their sites and running it there. You can see, it's using browser sync and all sorts of stuff. We click one of those links and we have our simple HTML page. Now, we don't have any framework around that. So, it's literally just H1 and those paragraphs and that one anchor tag and not actual like good HTML. It should live refresh because it's using browser sync.

Jason: I think my -- my computer's running a little -- a little slow lately. And I'm thinking it might be reaching end of life.

Bryan: It's always time --

Jason: Trying to reload over here.

Bryan: I see what up chat friends is in there.

Jason: Yeah. It's like -- it's fine. This is -- this is not -- this is not 11ty. This is my poor little compooper on its last legs.

Bryan: One more piece of boilerplate before the config file. Create a template area to use. And by default, there's configuration in there. And one of them you put your template into underscore includes as a directory.

Jason: Okay.

Bryan: You can configure that in the 11ty.js file. You can do templates or whatever and configure it. I don't think that's important for today. In here, we can create a base template file. We're going with Nunjucks. I like that personally.

Jason: Okay. And I just found out, it might not be my computer. CJ says that you need a body tagger or browser sync won't work. So, yeah.

Bryan: We're gonna fix that right now.

Jason: Should I just do like a regular old HTML boilerplate?

Bryan: HTML: 5 boilerplate. Just type --

Jason: Oh, no. I think I've disabled this.

Bryan: You're in a Nunjucks file. There are plugins and syntax highlighters for Nunjucks and liquid.

Jason: Let's see. Let's add a Nunjucks.

Bryan: On the fly. That's a fair point too in chat. 5T3F -- you can go in the bottom right and you can change it from Nunjucks to HTML. In the bottom right-hand corner of the code. That's a handy thing too.

Jason: That will just work?

Bryan: It will make it render as HTML according to the VS code.

Jason: That's what we needed. Pro tips from the chat. Okay. Now we've got -- close --

Bryan: We have a simple temperate. But save this and go into the index.markdown, and use this. The markdown won't come here. We have to create a slot for our markdown content to come into it. But if we want to show that. You're already a step ahead.

Jason: Oh, sorry.

Bryan: You're fine. You're fine. Boilerplate.

Jason: There we go.

Bryan: At the top, three dashes and a layout, colon. Based on Nunjucks. And --

Jason: Cool.

Bryan: 11ty is assuming that directory. That's the root of the layouts. If we save this, our actual document on the page should be blank because we no longer have the markdown content coming in. In theory.

Jason: Excellent. Excellent. Okay. So, now we have -- so, it's gonna include this lay out. So, if I save this, what I believe will happen -- oh, no.

Bryan: Blank. That's exactly --

Jason: But check this out. Now we do have -- I guess if I view source instead. There's that -- that browser sync which is what we wanted. Now that we've got a body tag, we can actually use it. And it included like our document which we had over here. So, if we change this. Right. Save that. And now refresh. And so, it is pulling in our template, but we're missing all of our content.

Bryan: Yes. So, we have to tell Nunjucks and this is the same for Liquid and others, where to place the content to get from the page. Right now we have to go into the body tags and do what's called a template expression in Nunjucks is called a template variable in Liquid. Same thing, two curly braces on either side. And that's going to pull in some sort of variable.

Jason: Okay.

Bryan: In this case, the content. That's the default variable for the content of the page. If you're using Nunjucks and not Liquid, it's going to assume this is going to be malicious markup coming in and going to print it as a string on the page and you have to use the safe filter on this. Give it a space, give it a pipe. This is the first template filter. And just put the word safe, and that allows it to render as HTML as opposed to a string of HTML that's put into our template.

Jason: Okay. Now if I -- doing this -- we can see, if I view the source again, here's all of this markup. And like this is actually worth calling out. So, what we've done here is because this is getting built at -- it's like a -- a compiled page and not a client-side rendered page. If you view source on a React single page app, you would see a div ID app and nothing else, right? Because the view source is just gonna show you what's from the server. So, because we're doing this with 11ty, it's injecting the code before it serves it so the actual output is gonna be -- if we look over here, uh-oh.

Bryan: It's gonna be absolutely lovely HTML. Rendered in the DOM.

Jason: Right. Index.HTML. Look at it. This is the finished page. Like this is built.

Bryan: Yep.

Jason: And that's really nice. Like that is a very cool setup that like we don't have to -- you know, we don't have to worry about whether JavaScript is disabled. In fact, like we're not loading any JavaScript so it doesn't matter if JavaScript is disabled. The only JavaScript that's running is the browser sync which is only for Dev. So, like, we could ship this site and this would get perfect hundreds on Lighthouse because there's no JavaScript, no blocking code. Your time to render would be more or less instantaneous.

Bryan: Great SEO for what up chat and all the words stuffed in there.

Jason: Kill it. This corner of the Internet is ours, Rob. We got it, chat. Here we go. So, then what? Now what do we do? This is our output folder and maybe something that is worth just mentioning real quick. We don't ever work in here, right? I actually -- it's a good --

Bryan: Ignore.

Jason: Remind ourselves that we don't want it. And then I'm also going to ignore Node modules so we don't accidently commit those. And I think that's all we'll need today. Anything else you can think about it.

Bryan: No, that's fine. There's a question in chat from CJ. Asking, how would you go about adding a frontend library to view a React or -- you would add it by basically bundling it yourself in this of all of this, shipping it as a static asset and linking in the header or however you want to do that. With a script tag, you willing in that file old school. hate saying it, but 11ty is so old school in the absolute best my favorite ways. But I'm also old. So, take that for what it's worth.

Jason: Yeah. It kind of comes down to the necessity, right? Because if you -- if you have complex apps and the process of doing it through script tags and, you know, the actual setup of all this stuff is gonna take you a really long time and it's finicky and like breaks easily, then it makes sense to switch over to one of the more advanced frameworks. But if you're trying to add one interactive element like you know you want to have a modal window or something and you just want to use React for that so it's a little more reactive, like, you can do that using just straight script tags as opposed to having to build out a whole Webpack process and, you know, all these things. I think it's trying to find that tradeoff. There's a point on the spectrum where it becomes so much work that it's worth switching over to a tool. But on the other side of that spectrum, it's so much work it set up those tools that if you could just do it by pasting in some JavaScript tags, why not? Why not do it that way?

Bryan: And there's an interesting conversation, I'm going to name drop the new dynamics Slack channel. There's a great thread, it was like 90 messages long, that was like how do you bring a framework into 11ty? And like there are people using Gulp. And that's how I use to do it. Gulp is not cool anymore? I don't know. I didn't learn Gulp like I should have. I just moved on. Bring your own Webpack config. But one thing that's interesting is transforms in 11ty allow you to take the outputted form from the process. The HTML file that we just created and run it through a transformation. You can do it with a JavaScript file too. So, if you wanted to build your JavaScript and then set up your Webpack configuration, or CSS and you want to use just a little bit of PostCSS and not bring an entire build process with you, you could set up a transformation on your CSS files that does like a purge or does a autoprefix or something like that in your 11ty build. And that's a really -- I haven't done it yet. Like, there's just kind of a theoretical thing that was talked about. But it's really interesting. You don't have to bring a build process with you because 11ty can function that way for certain cases. We're not going to do that today. Because that's -- I haven't done that and I would completely blow that. But that's something you could do a plugin for and have like an 11ty autoprefixer plugin that ingests the CSS that goes into your site folder and does the transformation on it. It's super cool. Again, I don't know what that would take exactly. But there are things you can do in 11ty as well. Random aside.

Jason: Yeah.

Bryan: We have a page rendering with all of our stuff.

Jason: Yes.

Bryan: We do need that configuration file.

Jason: Okay. Let's the config file back if had here. It's Eleventy.js.

Bryan: It's cool that the things work without this. Nunjucks is not the base templating extension. Because we newsed the extension, 11ty knew what to do with it. We could make a Liquid.liquid template and it would render with the Liquid engine. You don't have to configure stuff if you name it correctly. We have to set up the boilerplate for the configuration file. Module exports. Module.exports equals, and export a function. Function parentheses, and pass into the function the 11ty config. You can name it Eleventy config, I stick with that because that's the demos on show that. We won't break anything theoretically. But we can write the first piece of the plugin inside of these curly braces. inside what we're going to export out to 11ty. I thought we would start simple and create context tools. Starting with a bad idea. A really bad idea that you should never give clients or anything else. I want people to be able to resize text in markdown, any template based on a template tag. When I worked at an agency, people wanted this functionality. And we said no every time. But for Learning with Jason, we're going to let you do whatever content size you want for random strings inside why your markdown.

Jason: Okay. I'm ready. Let's ruin this website.

Bryan: It's important to know that all the things we're doing today, you can do without setting up a plugin. they're 11ty out of the box, shortcodes, template tags, linters, all sorts of stuff. We're going to make a template code.

Jason: This is all 11ty. We're not importing extra stuff. It's in 11ty.

Bryan: Depending how far we get, maybe will import things for fancier stuff. For this one, write three lines of code and have a shortcode setup that we can use in our markdown and our setups.

Jason: Okay.

Bryan: First, the config. And there's a method for adding what's called a paired shortcode. There's two different types of shortcode. The one is you put a couple variables inside of. And one is what you put on either side of text. We're going to get into that. This is all camel case, addPairedShortcode.

Jason: Is shortcode camel case the C?

Bryan: It's not. Good thing I have my cheat sheet. This is a function. Pass into it two properties. The first is the name of our shortcode. This is how we will reference it in the templates. This is a string, call this size. Name doesn't matter. It's what with you want to be as long as you're consistent. And the second argument is a function that's going to handle what happens. And it's going to be two things we're going to be giving it. The first inside that is going to be the content that is inside that paired shortcode. And then in the second one is we're gonna give it a size of some sort. I would just say size as our variable or whatever you want to call it, text size. And then turn back directly in this function. You can do any logic you want, it's just JavaScript. But start super-simple and return back HTML. We're going to do a template literal. And we're going to put a span around our content. We're not going to get super-fancy yet. So, just span in that curly bracket, or that right angle bracket.

Jason: Oh. Okay.

Bryan: We want to be sure we're working. And do template interpretation to do interpolation, I guess? And just do that content variable. And then close our span. When we save this, may have to restart 11ty depending on where it picks things up. But resort 11ty, refresh the page. Nothing would have changed because we didn't use the shortcode yet. Got to use what we make too.

Jason: Go into that --

Bryan: Yep. Whatever text you want to make huge.

Jason: I mean, here we go.

Bryan: We're going to use corgis, yep. Write template tag. This is how you do a loop or a conditionals.

Jason: Is it double?

Bryan: Not double curly bracket. It's single with a percentage sign.

Jason: I got ya.

Bryan: Give it a space and a closing reverse too.

Jason: Got it.

Bryan: Use the name we created. Size and then space and the first of a series of arguments. In this case, we only had the one. It is going to be -- I think what would be best would be the actual size and unit in a string. So, like 55px inside of a string.

Jason: That makes sense, yeah.

Bryan: And then on the other side of your link, you're going to end this with a curly bracket percentage sign, end signs, and do the same closing on that as well.

Jason: Like this?

Bryan: End size -- yeah, exactly.

Jason: Okay.

Bryan: If we have errors, it will error in the console. If we don't, we'll go back to our browser.

Jason: No errors.

Bryan: No change would happen except there's a span around our corgis now.

Jason: There is.

Bryan: We have successfully created our first shortcode. It doesn't do anything. Let's go ahead and toss in here in this template literal, style equals font-size and then we'll interpolate that as well. Yep. That should be good.

Jason: Look at it go.

Bryan: Boom!

Jason: This, I mean, we've already got -- we've already got serious client vibes.

Bryan: Oh, yeah. This is exactly what any of my clients in the smallest businesses would eat up. But, you know, if you don't want to as emphasize for accessibility. If you're making it this big, maybe you want it to be accessible. You could add the strong tag and make sure they know we're emphasizing it.

Jason: Sure.

Bryan: Not making it huge for people not using accessibility things. We don't want to hurt anyone else. So, literally, we've written our first shortcode. If they were to install this in their computer and reference it as a plugin in their 11ty configuration, they would have in shortcode ready to go.

Jason: Oh, interesting.

Bryan: This is legitimately a plugin as it stands right now.

Jason: Yeah, yeah. Yeah.

Bryan: We could do that or we could write a second piece and import that is somewhere else too.

Jason: Yeah. Why not. Let's do that. So, I have a -- I have a -- like a base site. And let me see where this is. It's, I think, base template. That's not it. Let's go find --

Bryan: Guessing the URL and instead of going to your repos and finding it.

Jason: I should. Demo base, that's what we want. Use this as a template. I'm going to use this as a new thing. Put it on learnwithjason, and we're going to call this 11ty-plugins.

Bryan: Do you have enough organizations that you're part of, Jason? Do you need more?

Jason: Yeah, please invite me to your organizations. That's definitely what I need. Okay. So, okay. Let's get this one and then I'm going to -- out here -- let's go back. And then we will clone. No!

Bryan: Yeah. Because that's what you named it. You can rename it in the clone.

Jason: I'm gonna rename it to 11ty-plugin. Because that's actually what it was. And this is the thing that will use the plugins. It doesn't matter.

Bryan: I guarantee you, that naming is going to bite you later. I guarantee having a singular and a plural is going to bite you.

Jason: Yes, I will regret this. Let's jump in here. And this site is set up -- okay. Yeah. This is also an 11ty site. And so, this is set up to use Liquid.

Bryan: I should have mentioned this, right? This is actual -- you can set up template language specific shortcodes and filters. So, you can make a Liquid one versus a Nunjucks versus a handle bars. Also, you can make your own. As long as you do your work properly, they work kind of across the board. I've got a plugin called 11ty blog tools that has a couple that I wrote specific Nunjucks around to give some syntactic sugar that was only available using Nunjucks. There was a CodePen and a YouTube embed, I think. And you still got those embeds. But if you were using Nunjucks, you could use it in a different syntax and get something a little bit easier.

Jason: Okay. Yeah. You can kind of bind this to whatever you want. That's pretty cool.

Bryan: Exactly. Yeah, there's features in Nunjucks that aren't available in 11ty that aren't available in handle bars.

Jason: Recommending the jock rocks voice. Is that like a shock jobbing, make the logo bigger? Or is there a different voice for jock rock? Also, John, with the good troll on just aiding more underscores. I think that's a good idea.

Bryan: Yeah. Instead of like having a versioning, you just say final finalist, final, final, final finalist.

Jason: Final, final, final --

Bryan: Exactly. Add more underscores.

Jason: Here's kind of a baseline demo site. And what we can do is, I think, if I create an and delete the HTML --

Bryan: You can use this in HTML. This is useful in any file type that is supported by the way that we're doing it.

Jason: What?

Bryan: HTML will render as a Liquid template, and an RS shortcode will work inside of that.

Jason: That's amazing.

Bryan: All by default because somehow Zach kept it all in his brain to do that.

Jason: I think what should happen now is I broke everything how?

Bryan: Perfect.

Jason: The thing that I broke is -- oh, it doesn't like something. Tag size not found. Oh, it's because we haven't included it yet.

Bryan: Yes, we need to add a plugin.

Jason: Okay. That's all we have to do to fix this. Let's go into our 11ty. And look up my teaching on this too. I forget the exact syntax. Inside the 11ty config, use the same 11ty config object. There's a method, like add filter, add shortcode, there's add plugin, camelCase again.

Jason: Okay. EleventyConfig.addPlugin.

Bryan: Outside of this we need to require into this page. The typical way of doing this would be to publish this to npm and download it as a dependency of the app and then require it in. Here we're going to require it from the other place. We just need to require that entire directory. You can also require the 11ty config file.

Jason: Wait, how would this work?

Bryan: You have to set it in the entry for the package.JSON.

Jason: Let's do that. Oops. I'm in caps lock. Let's go to level plugin. And then I'm going to open this one separately.

Bryan: Yep.

Jason: Okay. And so, in our package.JSON, we need so set a main file.

Bryan: The main. Yes. The manually should be Eleventy.js.

Jason: Okay. Then when we include this, it should give us --

Bryan: Sorry, somebody in chat is saying I'm the designated adult. I'm be no means the designated adult.

Jason: Are we not getting audio on the overlays today? Did they not work? Oh, are my overlays just not working like at all.

Bryan: That's sad. the boops happened earlier.

Jason: Yeah. What gives? Let's maybe just rerun this. Let's just refresh this page. Figure out why it's not doing what I want. Try it again. Come on. Huh. Something -- something broke.

All right I think I need adult supervision here.

Jason: All right. Something's going on. It's working. It's beta software.

Bryan: Makes sense.

Jason: Early release. Okay. So, I have now could inned this Eleventy plugin. I'm going to call it plugin --

Bryan: Yeah. Size plugin. Well, this is more than just our size plugin. This is a content helper. Names don't matter. It's fine.

Jason: We can fix that later.

Bryan: We'll do it live.

Jason: Drop in like this?

Bryan: Drop it in like that. And there's a second argument that we will get into this we have time, the configuration options. But we don't have those yet. Restart 11ty because it errored out and you're going to struggle otherwise.

Jason: I gotcha. And let's fix this.

Bryan: If I have done my job properly and you typed properly.

Jason: No errors. There it is. Look at it go!

Bryan: Wave created our first plugin.

Jason: We've done it. And you can see it, this is composed. This is the site that's kind of a demo. And then we've got the text that came from our -- our markdown file and then we were able to just drop in this size plugin. So, that's pretty -- that's pretty awesome that just worked. You know? It just happened.

Bryan: No problem, yeah. And like that's the thing. Like I often like start with like the actual template syntax because that's how I think. I'm a very visual person. I consider myself a designer who codes. So, I want to like see what I'm going get -- my own unit testing almost. I needed my thing to have these arguments and then I error it out until I get there. So, yeah, we now have the absolute worst shortcode in existence. The client-approved size increase.

Jason: Wait. I can make it better.

Bryan: Oh, no, not another digit.

Jason: Now it's better.

Bryan: That fits perfectly. I feel like the exclamation point should be inside of it. I miss it with huge.

Jason: You're right.

Bryan: Just from a branding and design perspective.

Jason: Yep. You're right. That was the right call.

Bryan: Oh, and, yeah, holy buckets, indeed. So, where we can go from here is one of a couple directions. We've got about 30 minutes, you will talk about 11ty all day. But I'm sure everyone has places to be. We could create another paired shortcode to do a block quote excessively, you can't put attributions in. It's a block quote. You can do that or a transform that would be taking the headers on a page and creating anchors and IDs around them to be jump links for the page.

Jason: Let's do that. Because the -- the interesting part, I think, is getting into how 11ty interacts with content. Because you think the block quote would be more of like writing HTML which is super-valuable. But I think that it doesn't dig into the internals of 11ty as much.

Bryan: So, I'm gonna give a shoutout. This is actually a simplified version that we're gonna walk through today of the -- there's a version of this in Andy Bell's Hialeah 11ty theme, which is super great. It runs my JAMstack website. It comes with this and a whole bunch of stuff. Really good CSS opinions and awesome 11ty things behind the scenes as well. One of which we're going to do a simplified version of this transform today.

Jason: Nice cool.

Bryan: Back into the plugin singular directory. And you can build these in any way you want and require them into your final Eleventy.js or write them in the file. Today, it's in the one Eleventy.js. But you could configure a directory of these to impart into your final product.

Jason: Totally.

Bryan: Instead of a filter, we're going to do a transform. We're going to break the heck out of our site to start with.

Jason: Good, I'm ready.

Bryan: 11ty config, add transform. It was before we got the filters, and the naming was terrible. This is going to be simple, the first argument is the name that we give it. Naming doesn't matter because we're not actually going to use it. You can call header bookmarks or jump links. Naming is the hardest thing in Dev.

Jason: Header jump links sounds good to me.

Bryan: Okay. It's going to take a second argument, I'm sorry, which is going to be our function. That's going to have two arguments inside of it as well.

Jason: The first is which?

Bryan: Content, yep, what is coming into our transform. And the second one is going to be our output path. That's for every file that runs through this transformation.

Jason: Okay.

Bryan: What that path is going to be. And it's going to allow us to specify a little bit more about what we want this to run on.

Jason: Okay.

Bryan: So, just to start with, we're going to do a very small conditional. So, just a standard JavaScript if. And we're gonna check to see what the file type is. So, if output path ends with .HTML is basically what we're going for here. Yep. Then we're gonna run everything inside of it. This will keep it so if that you have static assets running through, it's not going to try to run this transform on CSS, on random images. That would break things pretty badly.

Jason: Can I do a thing that is just like one of my little quirks? I like the -- the shortcut style so that we end up with fewer levels of nesting.

Bryan: Okay.

Jason: So, basically, instead of wrapping all the logic, we like early exit, basically?

Bryan: It will run a little bit better, yeah. Half a millisecond faster.

Jason: Really what I'm going for, whenever I look at code, the more nested it is, the harder it is to visually trace it. With by swapping this, it encapsulates the logic. We want to quit early if it's not HTML.

Bryan: This is like a one use thing, right? If you want to have multiple transforms, you could do it all in one big transform and run it through multiple things with checking file types.

Jason: That would be super cool. Yeah.

Bryan: I've only scratched the surface on transforms because they're a pretty big topic overall. But let's do something. Let's experiment and see what happens when we save this file to our site. And I'm gonna -- spoiler alert -- bad things happen.

Jason: Oh, CJ has a good question, do I need to return the content if nothing changed?

Bryan: Dang it, yes. But that was what was going to break. You're stealing my thunder. (Laughter) This is running through everything, right? Every file on the site is going to run through this. It's going to erase it.

Jason: We would just get empty files.

Bryan: Empty files.

Jason: I like that.

Bryan: 100%.

Jason: That was like a wrestling finishing move.

Bryan: Clip it. CJenaro is asking, is that possible add a custom fuel extension, I can't read the end of the chat. I don't see why not. What's happening, right? Is 11ty takes the templates and creates things out of it. This is what it creating out of our markdown file in this example. It's creating an HTML file. In this case, the path is underscore, site/index HTML. That's what we're checking about. Potential issues around that. Convince 11ty to spit out a custom extension. Possible. It can happen that way. Also, if we don't short circuit it, we want to get the content. It will, modified in the end.

Jason: In the end, right now, if we run this, nothing happens.

Bryan: Exactly. It looks -- if we've done this correctly, it will return every page and every page should look utility to what we've got. Which is good to know, I suppose. Also, with console open, you'll get any errors coming out of it automatically. Which is nice. So, yeah. So, let's go ahead and do something. But to do something, what we're actually getting is the stringified version of our HTML, right? It's just a big HTML dump on to this page for content.

Jason: Okay.

Bryan: And you will console log that and see the entire HTML for the page. But we need to navigate this with something. There's a few npm packages. If you're okay with JS DOM, if you're good with that.

Jason: Yeah.

Bryan: Going to require -- go ahead.

Jason: There's a question. These transforms -- these are going to run after the templates are generated, right? We're going to turn this index.hd into a fuel and then run the transform?

Bryan: You think it will being interesting to go ahead and run a console log out of the output. If you console log content, you can see it's the strung of HTML. Which is what the browser wants.

Jason: All right.

Bryan: We're going to get a big bump.

Jason: Stop and start. And I just saw it. So, let's pull this up and take a look.

Bryan: Slash HTML.

Jason: All of the HTML and the styles and everything. Here's the output. So, we're getting the rendered HTML, not the -- so, this is not a -- this isn't a pre-transform. This is like a post -- this is post-processing.

Bryan: Correct. And I don't know. And there might be something about this somewhere. I don't think there is a pre-transform. But a pre-transform would make 11ty into its own static site. Which would be amazing, Zach, if you're listening. I don't think that exists. But like I said, transforms I've only played with a little bit. And again, that's kind of that conversation we were having in the new dynamic Slack. Like, it can be its own little task runner for anything you can do with the npm package or in JavaScript you can do in 11ty. Yeah. Let's go ahead and install our JS DOM. It should be jsdom as the package.

Jason: I'm only including it as a Dev dependency, I started 11ty as a Dev dependency. That's not going to work, this is going to be a package. It needs had to be a regular dependency or else npm wouldn't include it.

Bryan: True. They have to be there as run time.

Jason: Fix that. These are going to be regular dependencies. Done. Okay. So, now over here, jsdom is installed.

Bryan: Yes. Yeah, we have to initialize it. And you can do all of this outside of your exports. So, you can do it like at the top of the file. Const jsdom. We require it in. And we have to get the jsdom. We can say const, and structure that into the jsdom as what we are going to end up doing.

Jason: Like this?

Bryan: All lower case jsdom. You think -- where that work?

Jason: That will do the same thing. If we're including it as jsdom, we can destructure it here.

Bryan: Cool.

Jason: We'll find out. This may blow up in our faces.

Bryan: Who know it is Node supports the same things -- whatever. We'll try it. Yeah. Now we can use that down below, right, to actually get a fake DOM of our -- of our page. So, inside of our conditional, or I suppose we're not in a conditional, because you do the reverse, we're going to basically instantiate a new DOM. So, const DOM females new JSDOM with the content string as we want to be the DOM.

Jason: Like this?

Bryan: Yes. I believe so.

Jason: Okay.

Bryan: Yep. And just to take a easier, syntactic sugar, set you were the document. So we're working with browser JS. Const document equals DOM.window.document to make it feel like standard JavaScript.

Jason: Okay.

Bryan: Now we can access anything. We can find our headings, any selector by using the things in browser code. If we wanted to find our H1 on the page, we could console log our -- document query selector. Yep. And then any query selector works in here. So, we do that. If we have an H1, we should get the H1 back.

Jason: Let's try this. I'm excited.

Bryan: On the console, yeah.

Jason: Okay. So, we should see an H1 get logged.

Bryan: Theoretically.

Jason: And here it is. So, we logged the DOM element so it's kind of truncated.

Bryan: Yep.

Jason: It's doing what we expect.

Bryan: That's exactly what we wanted.

Jason: Cool, perfect.

Bryan: Yeah. So, now we have to figure out, what do we want our plugin food? And so, really what we want it to do is find a certain size of header on the page and then add a link and an ID with that. Right? So, our H1, H2, H3, whatever we choose for that. And we can set that up to be configurable, if we have time, try to go fast. We've got time to configure it. We can basically say, use -- end user, tell me what selectors you want me to transform in this way? And then we're going to put a link next to that, an anchor tag next to that references that header. So, you can put a link icon, a bookmark icon, a possum, a boop, whatever you want.

Jason: Sure.

Bryan: What we need to do, we'll start since our current one has an H1. Go ahead in the query selector change it to query selector all. And list out H1, comma, H2, comma, H3. And get multiple headers even though we only have the one.

Jason: Let's fix that real quick. We'll do a header level 2. And then down here we can do header level 3. Nope. Okay. So, now we've got a couple -- a couple different levels of headings, right?

Bryan: A 1, a 2 and a 3, that's perfect. That will give us test cases. Yep. So, this is going to return back not an actual array. Like an array-like thing. So, we will need to destructure that. So, let's put it in the array and do the spread operator and all that in our returning headings.

Jason: Like that?

Bryan: Should be on the other side. If that works, again, not always ES2019 compliant.

Jason: This should work, I think. I don't know, let's try it.

Bryan: I've always seen it on the other side. But you can destructure with the variable call.

Jason: Yeah. I do things that I just assume work. Let's sigh. It didn't explode. I think we're in good shape.

Bryan: And we have three headers. Perfect.

Jason: Yes.

Bryan: And they're in an array. That's good. We're going to loop through that with a four each. And do something to each of those. So, headings dot for each. Pass in the heading function.

Jason: Okay.

Bryan: And then we want to grab the text content. Because we're going to use that to form our ID. And we're also going to need one more npm package. We need to slugify in to work "ID. Doesn't want spaces. Slugify. If you want to use a regX.

Jason: We can do it that way. Do a quick slug. Text.replace -- or text.toLowerCase and then we'll replace any -- like this is gonna be like a very rough version. But basically what we'll say is, any non-word character. And then we want that to be global. And then we will replace that with a hyphen. And let's see.

Bryan: Also have this be a number. Have it be the count for each ton honest.

Jason: I got to see if I did this. Can I do this on the first try? Let's find out.

Bryan: Yeah, yeah. Sia is like, wow. Live coded regX. I'm with you. I could not do that.

Jason: No! I screwed it up. Two lower case.

Bryan: Of undefined. This isn't your fault. We've done something earlier wrong, apparently. So, let's see --

Jason: My computer, I swear to god. Okay.

Bryan: The -- what is the text? Text is heading.inner text. Try Internet HTML. It might -- JSDOM may not have inner text. I don't know how close it is in feature parity.

Jason: Oh, okay. All right. Try it again.

Bryan: Maybe. Yeah. There we go.

Jason: First try. Okay. So, there are things that we would want to clean up on this. Like we would want to replace trailing tags and stuff like that. But I don't care.

Bryan: Not important at all. Yeah.

Jason: This is good enough for, you know -- close enough for horse shoes and hand grenades. We can make that work.

Bryan: What we need to do is create an anchor that is referencing that and also add that ID as an attribute on to the header. Right? So --

Jason: Okay.

Bryan: Heading.attribute add an ID. Just like you want in the DOM, in the browser.

Jason: Add attribute or just attribute?

Bryan: I think it's just attr. I think you're right.

Jason: All right.

Bryan: Sorry, no, set attribute.

Jason: Set attribute.

Bryan: Yeah. CamelCase.

Jason: Okay.

Bryan: So, setting the heading ID to each of the slugs and create an anchor. Document.createElement for an anchor tag. Might work as a string literal. But I don't trust myself live for that.

Jason: So, we'll document.createElement. It's going to be an anchor tag. And we need the href --

Bryan: The href -- you can set attribute href on that as well. You could probably continue stringing the dot notation along too.

Jason: And we just want -- or, no. We want slug? Like this? Am I doing this right? This feels wrong.

Bryan: That should be right as long as link.href works.

Jason: Oh, yeah, I think with DOM elements, let's do what you're doing. Because I think that, you know, consistency is a good idea. But what -- with a lot of DOM elements, if you know the property, you can just get away with like adding dot ID and stuff like that.

Bryan: And prop versus attribute makes me nervous moving between Node versus browser and stuff like that. And then let's set some innerHTML. Because we need that in JSDOM. And for now, say bookmark. That will just be the text inside it. Or that. An emoji works.

Jason: Watch me go.

Bryan: In my test case for that, I've got a possum. Was going to suggest grabbing the SVG for the boop. Exactly and then a pen child link. And then at the end, we have to do something weird. Let's see what happens. Let's just return the content. We don't to want return content, know? I don't think do we?

Jason: Well, we didn't really modify...

Bryan: At the end of -- where am I?

Jason: Oh, wait. We get the document.

Bryan: Why am I returning here? Let me look real fast. I'm returning out of -- sorry. I'm just so -- so used to writing things myself. That's inside of our heading. Okay. So, yeah. So, inside -- I have it in a conditional. Again, it's a little bit weird. But, yeah, return document.documentElement.outerHTML, right? That's going to get everything except for one key thing which we have to write manually. Which is a little bit weird in this. But different fake DOM, Node DOM implementations may have something that's a little bit different here. This is going to break all to heck. And did you refresh?

Jason: Yeah, it's working.

Bryan: What? Okay. When I did this, I added a doc type. So --

Jason: So, mine -- mine included a doc type, or, wait. Did we lose our doc type?

Bryan: We do. Because we're completely transforming this HTML.

Jason: I get it, I get it.

Bryan: Into that JSDOM. I don't know why yours is working. Are you in Chrome or Firefox?

Jason: This is Chrome.

Bryan: In my Chrome, it all sorts of broke. I got the HTML on the page.

Jason: You're saying that what we want to do is something like --

Bryan: At the beginning that have, do a string of a doc type. An actual document type. Yeah.

Jason: Okay. Yeah, it can be lower case, radio I thought?

Bryan: I think so, yeah. Doc type, HTML.

Jason: Is this self-closing?

Bryan: Yes. I don't. It is -- there's no closing tag for it. But it's HTML5. You don't need a self-closing. So, yeah. That -- you may need to --

Jason: I need to restart it, don't I?

Bryan: Yeah. Because, again, like this is happening in some different ways. And since you're using it from that plugin, this version of 11ty doesn't see the changes happening on the other version. And there it is. You could go in, you could add new line if you want to. You can use these minifications and you could do it in one go. If you bookmark, it should jump it down the page.

Jason: Yep, it does.

Bryan: You could do CSS and show/hide. We have a bookmark.

Jason: Does what it says on the tin, which is pretty great.

Bryan: Yeah, the other thing if we have time, or we could just wrap up here. We need to configure it.

Jason: Do you think that we can configure it in under 3 minutes?

Bryan: I think so.

Jason: Let's roll. Okay. Speed run. Here we go. Here we go, chat.

Bryan: In our plugins, 11ty config.

Jason: Yes.

Bryan: When we were starting that module.exports, wherever that is. There's a second variable to pass in here. Which is going to be our options object.

Jason: Okay.

Bryan: So, anything that's passed in as a second thing on the add plugin will come in here. There are many different ways to do what we're going to do. But we're doing an 11ty speed run. So, we are going to -- yeah, just default it to an object. And then in our project, we're going to pass in an object that has let's say header selectors or something like that. And put in there H1, H2 as a string.

Jason: So, like header selectors. And we'll do H1, H2.

Bryan: Yep. That will be different from what we did before so we can see it work.

Jason: Okay.

Bryan: Save that and go back and set it up to use that. Now in the document query selector all, instead of that, use the new options variable.

Jason: Okay. So, let's not do that. Let's not worry about it.

Bryan: You should like properly do that by adding some sort of default up there. But yes. Options.headerSelectors should work whether you restart everything.

Jason: Let's try it. And when we refresh, no H3.

Bryan: Yep. This is configured at the site level. But you can put in any selector you want. If you only want these on like articles, you could have article space H1, comma, article H2. And the outlet path, begins with/blog. But that feels super-brittle to me and I'm not sure I like that idea. But you could specify only where to run the output path. Only on blog posts or only on a certain type of document. Again, that feels brittle. And I'm not sure of the best way to kind of go about that. But you could do it as opposed to running it on every single document.

Jason: Yeah. I feel this is one of the things as you start to dig deeper, the more complex this gets, the more you are building your own complex static site generator, right? And so, I think the -- make the decision to make when you start digging into this is how much custom code are you writing? Because when you -- when you exceed a certain amount, you are -- instead of using a framework, you are building a framework. And, you know, the tradeoff there is like when you build a framework, you get to make all the decisions. But you have to maintain the decisions and educate everybody about the decisions. How many people are going to maintain this? How long does the site need to live? All of those things?

Bryan: Which is why I look for more plugins. And hopefully you can have a better plugin author than me. You can download my four plugins. They're okay. There's things -- putting in the Cloudinary images.

Jason: Strong. I love that strong endorsement ment. It's like: Bryan Robinson, use my plugins. They're okay.

Bryan: Bryan Robinson, okay at everything. Not great. But okay.

Jason: With that being said, I think it's time for us to start wrapping it up a quick shoutout to White Coat Captioning who has been doing our live captions today. Thank you so, so much for making that possible for us. And that is made possible through the generous sponsorships of Netlify, Fauna, Sanity and Auth0, Sanity is where Bryan works, as mentioned earlier. So, super, super cool to get it, you know, just the effort from the community through companies like our sponsors who make this show more accessible to more people. That is very much appreciated. Also, make sure that you go check out the schedule for the show because we've got some really exciting stuff coming up. So, next week, Nat Allison is coming on the show and we are going to work on internationalizing React sites. And Nat is like the premier expert on this. Did it for the React docs worked with Gatsby. If anybody is going to be able to help us figure this out, she's going to teach us. And Stefan to teach us about Contentful. Amazing. We just added a ton of episodes to the show. Check out the schedule and let's go. Like let's make this happen. It's going to be so much fun. If you want to get notified, you can add this calendar that will show up in Google calendar. Let you know when new episodes are going to happen. And you will be able to join right from your Google calendar without having to do anything. Bryan, where should people go if they want to follow-up with you? What's next steps here?

Bryan: Sure. Twitter has most of the links that might be of interest to folks. So, B-Rob. Check out on my website, And stream on Twitch. I'm a host of that's my JAMstack. A JAMstack podcast. Thank you for being on last season, Jane. If you use the JAMstack, and you want to be the on the podcast. Even if you aren't super-technical, I want all the takes on the JAMstack. That's the theme on that's any JAMstack. Need to fix the logo. I have 5 episodes, 30 episodes total. need more guests. We can record a 20-30 minute episode.

Jason: Chat, thank you so much for hanging out, Bryan. And chat, stay tuned, we are going to raid. Thank you so much. See you next time.

Bryan: Thanks.

Closed captioning and more are made possible by our sponsors: