skip to content
Home

Build Your Own Babel Plugin

with Laurie Barth

Babel might seem like magic, but Laurie Barth is going to teach us how developers of any skill level can build custom Babel plugins for fun and/or profit!

Transcript

Captions provided by White Coat Captioning (https://whitecoatcaptioning.com/). 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 have Laurie Barth. Laurie, thank you so much for joining us.

Laurie: Hi, everyone. Nice to be here.

Jason: I am very excited about your background here. You've got I see a rollercoaster, I see a castle. Is this all LEGO?

Laurie: There are two castles. That one is Hogwarts. And that one -- I can never do this right. Depth perception. That's Disney castle and a rollercoaster.

Jason: Is it a particular rollercoaster?

Laurie: No, it's just a rollercoaster.

Jason: Okay. What is up, everyone? Okay. So, Laurie, I feel like we have been talking to each other forever on the Internet. We both almost -- we almost worked together at Gatsby. We like -- ships in the night. But for those who aren't familiar with your work, do you want to give us a little bit of a background?

Laurie: Sure. I'm Laurie, nice to meet you. I'm very online. So, I do a lot of content creation. I write blog posts, I'm an Egghead instructor. Occasionally I show up on other people's streams, I don't stream myself. And podcasts and speaking. But I work at Gatsby as a software engineer. So, despite the fact that everything I do looks very DevRely, I'm a contributor and write code every day. I'm @laurie literally everywhere. That's me.

Jason: I'm excited to do something I have dabbled with, but I have made a joke, but Babel plugins. This is something you have been really stuck into lately.

Laurie: Yeah.

Jason: For people who are hearing this for the first time, what is a Babel plugin?

Laurie: So, I really want to call up this really funny image that John Otander had on Twitter for a while, I would have to find it. But basically, it's whether you are -- it's sort of chaotic evil --

Jason: Okay.

Laurie: That chart for what you consider a compiler to be. And the most loose definition is a sun is a compiler. So, Babel is a compiler. Some people call it a transpiler. Roughly birds of the same feather. But what it does is runs against your code before it's built into an artifact and transform little the syntax in each of your files based on whatever plugins you've given it.

Jason: Okay.

Laurie: So, there are default plugins that you can use that Babel officially supports like preset emv. And that's everything that's been part of the ECMAScript current release. So, it didn't includes optional chaining, then it did.

Jason: Gotcha.

Laurie: But before it did, there was an option to increase that.

Jason: Just a little bit of quick vocabulary in case somebody is new. ECMAScript, that's the spec for JavaScript, the language features.

Laurie: Yeah. ECMAScript is the standard on which JavaScript is based. And you might think that JavaScript -- the JavaScript that you're running is, you know -- what's running on your computer when you build your artifact. But that's not necessarily true. The JavaScript you're allowed to use depends on the JavaScript engine you are running it in and those are either in Node or in a browser. There's some -- there's some nuance there. But each browser has a JavaScript engine. And so, depending on how recent that engine is, and how recent the version of the browser is, there's certain syntax that it doesn't yet understand and it can't parse. So, parsing is a really important term in compilers. And what it means is, JavaScript's ability to read -- or the engine's ability to read the JavaScript you've written.

Jason: Right.

Laurie: If it's something it doesn't recognize, I don't know this vocabulary word, and I don't have a dictionary to look it up in so I'm just going to break.

Jason: Yeah. It occurs to me that like 5 years ago everybody would know -- would have come in contact with Babel. If you were writing JavaScript 5 years ago, you were going to have to deal with a Webpack setup with a Babel setup because you needed that to support these different browsers. But I'm realizing now, like thinking about it, you don't really see Babel anymore. It's been abstracted away. It's part of NEXT. It's part of Gatsby, it's part of Nuxt and stuff. So, you're not going to see Babel. Chat, I'm interested. How many of you have had to write a Babel config before? And while we're waiting for the chat to weigh in on that, why would you end up in a situation where you want to write custom Babel today?

Laurie: So, you can actually use Babel transforms inside of your code if you're taking some sort of input from an external user and you want to turn it into something else, for example. The reason I talk about a lot is code mods. So, if you're a library author or some other JavaScript interface that people are using and you release a new version and make considerable changes to the interface that your user is developing against, that's a lot of manual effort to use to upgrade. You can write a code modification that transforms their new code to the new syntax.

Jason: Yeah. That makes a lot of sense. And I've seen those for the React team released one, for example, when they went to 16. That would like to transform certain -- like if it was able to identify a type of component, it would roll it over to be a functional component. Or add in some certain things that updated the code. Which is really, really nice, you know, as a developer to not have to go do that kind of clicky, copy-pasty work that's not so much coding so much as cleaning. I do enjoy just being able to click a but then and have it done.

Laurie: Yeah. So, code mods, using it in code is definitely a thing that happens, especially for library authors when they're like accepting certain syntax that isn't technically valid. And sometimes people are actually configuring and using existing plugins. But, for example, I know plenty of codebases that are using a combination of TypeScript and JavaScript. And so, if you want different plugins to run, depending on the extension of your file, that's the sort of thing you can configure. If you want to call everything a .JS file, but have it be compatible with JSX syntax, that's things that you can configure. So, all of the -- the batteries included piece, like Gatsby has it, NEXT has it, that sort of thing, you can still but the a layer on top of that and it will respect your local config.

Jason: Okay. That's really nice. That's what we're going to be doing today. Digging in and taking code and messing with it and turning it into other code. Effectively writing our own code mod.

Laurie: Yep.

Jason: I'm pretty pumped about this. Before we get started, I'm going to read something from Chris that made me chuckle. As we were writing about Babel configs -- the chat -- it looks like a lot of folks have never written one before. And what Chris said is, never admit to staring into the abyss for you might be considered an expert on the abyss and asked to stare into other people's abysses. Is it abysspi or abyss...?

Laurie: They did find that.

Jason: I'm excited about that. This is the compiler alignment chart.

Laurie: The sun is a compiler. Gets me every time.

Jason: I do like this. Your input and your output -- I don't know enough about -- like, I'm not a CS major. And so, a lot of my knowledge about compilers is what I've heard other people say.

Laurie: I would say that the -- like the kind of CS definition of what a compiler is has become less and less appropriate as the target of our code has become more and more abstracted. So, previously, it was, you know, everything compiles down to a binary. And that's not really -- I mean, it's true. But like it's not really true in the way we think about it anymore. For example, browsers, you are compiling down to something that the browser understands. And the browser has a JavaScript engine. And so, your target is not assembly or binary, it's something much higher level.

Jason: Got it.

Laurie: And like compiling to WASM and some others -- there's layers of abstraction where one thing compiles to another thing, compiles to another thing, compiles to another thing. I think that you start at 20 levels of abstraction and compile down to a level of binary and then only is a compiler is not really accurate. So, clearly I'm not a purist is what we came out with this with.

Jason: Input rebel, output rebel. The compiler is great. It produces something and because it exists and it producing something, other things are output.

Laurie: Just saying.

Jason: I love it. That's really fine. A quick shoutout to your LEGOs. We talked about the background a little bit, but you're also brand new to TikTok.

Laurie: I literally downloaded it last night. This is a little embarrassing.

Jason: Here, it is, watch a TikTok together. Wait, wait.

Laurie: No, we're still not at the beginning.

Jason: Wait, why aren't you starting at the beginning? [awesome captioned TikTok]

That's great. Okay. So, if everybody wants to go and follow Laurie on Twitter, it sounds like you also get TikTok content now. So, head over there. While we're on the subject of shouting things out and linking to them, let's also do a quick shoutout to our sponsors. We have White Coat Captioning today, Amanda's here doing live captioning with us as we speak, thank you so much for being here, Amanda. And that is made possible through the support of our sponsors. We have Netlify, Fauna, Auth0 and Hasura all kicking in to make this show more accessible to more people. If you want to see the live captioning as the show is going, just head to learnwithjason.dev. That is going to be -- this is gonna be great. We're gonna have so much fun today. So, what we're going to do today is we're going to take the code that Ali Spittel taught us. You can watch that episode if you want to see it. We're going to work from the row, which I'm going to fork --

Laurie: Thanks for your code, Ali!

Jason: You're not going to let me do it. Here's what I'm going to do. I'm going to create a new version of this. And we will just boy, I've got so much stuff going on here that I can't show on screen.

Laurie: We cannot put it in Git for the moment. We can put it in there later.

Jason: Okay. Sorry, I had to clear my terminal. So, what I can do now is I can -- I can --

Laurie: The terminal. It's so esthetically pleasing. I'm loving the colors. So simple. Just clean.

Jason: I'm also -- I'm a big fan of this one. So, let's -- yeah. This -- what are we doing? Like custom Babel code mod.

Laurie: Yeah, let's do it.

Jason: We're gonna clone into here. I'm going to remove the Git folder. And then we're gonna do a Git init.

Jason: Wait, your terminal is written in Rust?

Jason: It is. This is starship.

Laurie: What? We should talk about this really quickly. The other thing about compilers is they don't have to be written in the language they're compiling. Chris who is in the chat introduced me to this crate for Rust called SWC which can literally be a like drop-in replacement for Babel. But it runs all of the transformations and all of the parsing and the code gen using Rust. Which is super-cool. But it's changing JavaScript.

Jason: Super cool.

Laurie: Thanks, Chris.

Jason: If y'all remember, the way this worked is we put together a demo where you were able to click a button and it would change the background color based on that button. Pretty simple as far as functionality goes. This was very simple. Check it out, lest Let's Learn React! On the Learn with Jason site. We are going to mess with this a little bit. Let's do some transformation. So, if I want to do that, and I've got my code, I assume I don't start messing around in here. What's the first step if I want to start doing a Babel transformation?

Laurie: The first step is to make a file that's going to be your plugin. And a plugin doesn't really have any rules other than the fact that it is a function. And it's a function that returns an object which is a little bit confusing. We can talk about visitor patterns if we want to dive in that deep.

Jason: I think we might have to at least do the high end -- or the high-level version of this. Okay. So, a -- a plugin doesn't have any rules. And I have this file. And I'm ready.

Laurie: Okay. So, what did we call it? We called it codemod.js. I love it. So, in this file, we want to make a function -- let's call it Babel plugin. Or whatever. And it will actually take an argument called Babel.

Jason: Okay.

Laurie: Which comes by default with all plugins that you use, this gets passed.

Jason: Okay.

Laurie: And then inside of the function, we'll worry about dealing with Babel later. But we're gonna return an object. And inside the object, we're going to have a key called visitor that is itself an object.

Jason: Okay.

Laurie: All right. Now, all of our code is gonna go in here. And let's --

Jason: Okay.

Laurie: Quickly explain what's happening. So, there's something in computer science called the Visitor Pattern. And what the visitor pattern does is allows you to basically manipulate the form or output of a given class without having to have that function live inside the code for that class.

Jason: Okay.

Laurie: The only code in that class is a function name that says, "When I am visited, I am looking for... this function name." This is going to make a lot more sense when we jump into AST explorer. But we're going this visitor object is going to have a bunch of different functions in it with type names. So, import declaration or member expression, all of these different things that we're gonna get from our AST. What that does is it allows us to do a transformation that we are passing in essentially as a callback.

Jason: Okay. So, if I want to --

Laurie: I feel like we went in the wrong order here. You feel like we should go and explain ASTs and then it will make more sense.

Jason: Yes, let's do that. Let's do that. How does one go about dipping their toes into the AST? I don't know if there's a shallow end. There's just a deep end with AST.

Laurie: No. I contend it is all the shallow end. It's all approachable because it's very nice tools that other people who aren't me have created. What we are going to do is go and grab let's say your code with all your buttons. You want to grab that?

Jason: This one. Okay. Got it.

Laurie: Grab the whole thing and we're going to go on a field trip.

Jason: We're going on an adventure!

Laurie: A site called AST explorer.

Jason: I cheated. I had this ready.

Laurie: You did. So, we want to switch over, instead of acorn, we want to be on Babel 7.@babelparser, that will work. And then put the code in the left-hand side. Remove what they have and put what we have. And on the right-hand side, we have generated an AST which stands for abstract syntax tree. And this is essentially a tree representation of your JavaScript code. So, if you're familiar with a DOM in the browser where you have this tree of all your HTML elements, very similar concept here. The difference is, you -- they've taken what you think of as a single line of JavaScript and turned it into this nested set of nodes that each have types. So, let's look at one of the nodes. So, inside the body, we have an import declaration and we can open one of those.

Jason: Oh! Look at this, look at this.

Laurie: Yes, it high lights.

Jason: It opens up. Oooo! That's cool. I've clicked on my function. Did you want me to look at an import?

Laurie: It doesn't matter. Either way is fine.

Jason: This is a little smaller.

Laurie: You have import declaration and you hover over it and you see it's the whole line. And you have a type. So, this whole node is of type import declaration.

Jason: Okay.

Laurie: This is what's gonna be -- these are the types of things we're going to be giving to the function to say, hey, I want to look at this import declaration which is referring to this whole line. And then inside of this, we get different information. So, let's click on the specifiers array. So, inside of that, there's an import default specifier. If we were to compare that to the use state that's a named import at the top of our file, we'll see that the specifiers are different because it's an import specifier versus an import default specifier. And because those are different types, one of them is a piece of code that comes with curly braces. And the other one doesn't. And it doesn't explicitly tell you that curly braces are not explicitly represented. They're represented as part of the type declaration and definition.

Jason: And so, I'm starting to see how this, like, this is the abstract part of it, right?

Laurie: Yes.

Jason: Because what we're doing is we're not saying how. We're describing the behavior.

Laurie: Right.

Jason: So, I'm already starting to connect a couple dots here. Because this basically says, like, if we were to take this, and we wanted to move this A ST over into something that wasn't JavaScript, but supported the same language features, we could say, okay. No problem. We know how to do an import declaration. We know how to handle defaults, we know how to handle named imports. And we can write those in whatever our target language is.

Laurie: Exactly.

Jason: And that's pretty slick.

Laurie: It's really slick. Once you start understanding this, you have the power to do a whole lot of things.

Jason: Nicky in the chat is asking, are these types standardized? Like is the AST kind of -- who maintained this spec?

Laurie: There is a spec. I don't remember who maintains it explicitly. It does -- so, there's -- there's different compatibility. So, yeah. So, ESTree is a little bit interesting. So, ESTree is the compatible spec for using ESLint. Technically out of the box, Babel is not ESTree compliant. There is functionality that it provides that allows you to make it an ESTree compliant AST.

Jason: Okay.

Laurie: So, there are slightly different specs. The types for JavaScript tend to be pretty standardized at this point. Just because there are a number -- sort of like Babel got there first. And a lot of people followed and they used the same -- they used the same types. But it's what is actually in the node is what tends to differ. So, for example, we're looking at a Babel AST which has this location. If you click on the LOC, it's saying, you know, this is the start line and the end line. If you look at something that's -- actually, we can show examples of this, switch over from a Babel parser in the drop down. And go to the Babel -- or the ESLint parser. Because there's gonna be different information in there.

Jason: Oh, it doesn't like JSX.

Laurie: It doesn't like JSX. That's what's built in by default and what isn't. Yeah. But it comes with slightly different information. So, that will say things like, includes parentheses. Which is information that Babel doesn't pay attention to because that's considered sort of lexical analysis. And more styling information rather than something that changes functionality.

Jason: Sure, sure, sure. Yeah. And like this is -- okay. So, we have -- the entirety of what we've built here is now broken down into a pretty, you know, a complex but not necessarily difficult to understand object. There's just a lot in it.

Laurie: Yes.

Jason: There's support, how do we do comments. We can see whether or not it's an async function. Those are cool -- that's really cool stuff.

Laurie: Yeah.

Jason: And inside, in our body, it breaks into smaller, more declarations.

Laurie: Smaller and smaller.

Jason: So, each of these things is Babel saying, like, okay. I have one thing. And then I'm nesting my one thing inside of another one thing. And then nesting that inside of another one thing until you get a tree.

Laurie: And eventually you reach the orphan node -- well, I was gonna say the bottom.

Jason: Oh, the bottom.

Laurie: Eventually you reach a node that doesn't have any children. And those are literals. Just -- so, if we think of primitives in programming, strings booleans, that tends to be what's at the base of subtrees.

Jason: Okay.

Laurie: So, they have identifiers which are strings. And then there's variable names, essentially. And you have string literals, you have boolean literals. Yeah, we got to keep going down.

Jason: There's --

Laurie: JSX text. Inside -- yeah, let's look inside JSX --

Jason: Yeah.

Laurie: Elements. JSX elements, closing element.

Jason: And text, and here's our value.

Laurie: That's interesting. I'm not used to seeing JSX text because I'm so used to seeing expressions that are inlined there rather than just text. I actually don't think I've ever seen that one before. So, JSX text is a thing. We have learned something! It's an AST. An AST is like a LEGO castle. Actually, an application and components are like a LEGO castle, video coming soon. Also -- it makes sense.

Jason: Of course it does.

Laurie: So, now that we have all of this, we can think about what we might want to change. So, we could -- let's start with what is sort of the most straightforward change we can make, which is we don't want to call it button anymore.

Jason: Okay.

Laurie: We want to call it -- this is a default export. Is this from inside our file? Or inside our code? Is button.js hour --

Jason: But the season ours.

Laurie: Okay, great.

Jason: We're also naming the import here.

Laurie: Yeah, because it's a default.

Jason: In this file.

Laurie: I was just curious because I forgot it was a default for a second. There we go. Yay! We're awake this morning. This afternoon.

Jason: Here! Here we go.

Laurie: So, you can click on that. Aw! You knew?

Jason: I knew. Well, I guessed. I saw this transform when you said "Transform."

Laurie: Yes, click on this and go to the bottom.

Jason: I picked v7 because you said v7 before, is that the right thing?

Laurie: Yes. And this function looks a whole lot like what I just had us put in the file.

Jason: There's Babel.

Laurie: It returns. The name is optional and we hadn't started pulling the types out of Babel yet. But we get our visitor, which in this case they're showing an example of messing with an identifier and reversing the name.

Jason: Oh.

Laurie: So, if you look at the code to the right, it's rolo class, rolo -- I can't see that. RoloCtes.

Jason: Yeah. And they actually -- so, they replaced it in certain places, but they broke it in JSX.

Laurie: Yes.

Jason: That will be a fun thing to fix. And the way that that's happening is we're changing like path node name is being taken as a string. And then split into individual characters. And then we reverse the array and then we join it back together. But if I just wanted to change this so that everything was named "Boop" --

Laurie: You could do that.

Jason: Boop, boop, boop.

Laurie: Exactly.

Jason: I'm picking up what you're taking down.

Laurie: Let's talk about path because it can be confusing at first if you think what path, what's available to you inside each of your visitor functions, it is not the node that we're looking at here. So, each one of these nodes have a type. Those are nodes. Path is an object that contains a node and comes with other information. So, path has some metadata information like parent.

Jason: Right, right.

Laurie: Point to the parent. If you want to be actually inside the node, you want path.node.

Jason: Got it. Makes sense.

Laurie: When it's a literal like this, the node has a name and we can change it directly. And we chose the very appropriately named "Boop."

Jason: Yes.

Laurie: But if we wanted to do something slightly different, we could actually replace it. So, instead of doing a manipulation directly on the node, we're gonna use path.replaceWith. But we have to make a new -- a new node first.

Jason: Okay.

Laurie: So, let's make a constant called inside our identifier function. We're going to make a const called, I guess, newNode. And there's a couple different ways to do this. We can use types and do T.identifier. And initialize it.

Jason: That's probably way easier.

Laurie: There's only two thing this is one needs. So, we could do it the slower way which is with --

Jason: Like that?

Laurie: A name and a type. Yeah. So, t.identifier. And we're going to want to give it a name. Which I think you can just pass directly. This is when you have to look up -- actually, we should show this because it's relevant. Do you want to pull up the Babel types documentation? It's very useful.

Jason: Like this one?

Laurie: Yes. So, if you look at the right, you have all these different things and we can scroll down and get to identifier. It's in alphabetical order. Spent a lot of time in here.

Jason: Oh. So, it's not capped. I did that.

Laurie: Oh. It's -- I think there's an alias for that one. But I could be -- yeah. Some of them -- this actually is my like big thing. The JSX ones are also slightly different. But maybe identifier doesn't have one. So, yeah. .identifier. And then because we're using types, it knows what type to assign it and we only need to give its data. And its data in this case is name, the rest of the stuff we're not worrying about right now.

Jason: Okay.

Laurie: So, we can pass it the name "Boop."

Jason: Okay.

Laurie: And then replace with gets past new node. And something bad is gonna happen here.

Jason: No!

Laurie: Too much recursion. So, visitors patterns are great because they're recursive. They're allowing you to look at every single identifier again and again and again. But the problem is, when you get a identifier and you replace it with a new identifier, the recursive pattern wants to look at the new one and the new one and the new one because you want to replace it with something new that the visitor pattern hasn't looked at yet. So, in order to keep that from happening, this is what you wanted to transform it into. If it wasn't, you would define it differently. You want to put path.skip. And path.skip is telling Babel to not look at this particular path again.

Jason: Like this.

Laurie: It's a function.

Jason: Function. Okay. We've done it.

Laurie: Ta-da.

Jason: We've done the thing.

Laurie: Sorry, go ahead.

Jason: We've wreaked a little havoc here. How do I make sure I'm only doing one thing, I broke everything.

Laurie: Theldofalan is asking a important question, it's being turned into the code on the left.

Jason: This is our source, our tree, our plugin, our output.

Laurie: Yes. And path.skip is marking a node as being traversed already. Yes, you can do path.stop if you want to stop traversal entirely because you found what you wanted.

Jason: Oh. If we wanted to the hit the first one, it would just do the one.

Laurie: Yep.

Jason: No, it's not. Did it again and again. Oh, it does it for each identifier at the top level or something?

Laurie: Yes. It does it for all siblings. Instead of parents.

Jason: Got it. Got it.

Laurie: Normally you would not use path.stop. You would use it as a conditional inside of an if statement. This one's a little convoluted. So, we broke things. And we don't want to break things.

Jason: Yeah, I want things to be not broken.

Laurie: Part of the reason we broke things is we have been changing identifiers. And that's not actually what we want to do. Because identifiers are very low level hey, we're going to have a LEGO analogy here.

Jason: You just talk about LEGOs, I'll be back.

Laurie: It's LEGO, the plural of LEGO is LEGO. It's an adjective. LEGOs are not a thing.

Jason: I'm sorry. I screwed that up. I said LEGOs?

Laurie: Yes.

Jason: I'm sorry.

Laurie: It's okay. You're forgiven. Thanks for coming to the LEGO show. So, an identifier is a very low-level building block and it's used by a lot of different things. Which is why we see it as the name of the function, we see it as both of the variables getting assigned by use state. We see it by use state. It's essentially a variable name. It's a string. This is too low-level for what we want. Unless we want to add some conditional where we check what parent we're in and say, okay, this is actually where I want to be, that's what I want to change. But we grabbed it because the identifier was the example that they showed us.

Jason: Okay.

Laurie: So, let's find out what we actually want to change. We actually want to change button. And button is in fact an identifier. But it is inside an import default declaration.

Jason: Imports!

Laurie: Above.

Jason: Wait, what have I done?

Laurie: I don't know. Go up.

Jason: Where am I? Here. Import declaration. Okay.

Laurie: Yeah.

Jason: Oh, I didn't go into the specifiers. That's why I didn't see the import.

Laurie: Yeah. Instead of looking at the identifiers and messing with them, we want to look at all the import default specifiers. So, we're going to change line 7 in our function to be visiting a different type. And --

Jason: Okay.

Laurie: One thing to keep in mind is that we could have kept the code that we just had put a comma. Visitors can take as many functions for as many different types as you want.

Jason: ooo... that's nice.

Laurie: That's nice about them.

Jason: This initially looks like it's right but I don't trust it because we replaced an import default specifier with an identifier.

Laurie: Correct. So, the only reason that works is because an import default specifier takes a -- a name and a string and I'm actually surprised this didn't yell at us. I think if there was typing on and stuff like to, it would yell at us. But the information that it can grab from an identifier, theoretically you can have an identifier inside the default specifier. I think we do. Can we look at the AST? Scroll down. Inside of here. So, yeah. That's why. Embedded inside of this is an identifier. So, it technically works, but this probably isn't how we want to do it.

Jason: Okay. All right. So, then I would just change over here. I would make this an importDefaultSpecifier.

Laurie: Property local -- oh, because it's changing local. This is one of the situations they wouldn't do the replaceWith because we don't want to change the type of node that we're looking at. We really just want to change the name inside of it. It's a good example. We're glad to have looked at it. But we can go back to what the original example was, which is path.node.name. But in this case, I think it's gonna be path.node.local.name. And we don't need a new node at all because we are changing a string directly. And we don't need to skip because we're not replacing anything. Ta-da! Boop.

Jason: Ta-da! But

Laurie: But.

Jason: It didn't get picked up by JSX.

Laurie: It didn't get picked up by JSX because all of these are uses that have import. So, it's a couple ways to use this. Let's go -- I believe it's a JSX element. I don't want to cheat for us. Let's double check.

Jason: I'm going do click on one.

Laurie: Yay!

Jason: JSX identifier inside of a JSX element.

Laurie: So, there are a couple ways to do this. Why don't we start with what most people will do and then we can look at the sort of fancy way of doing it. So --

Jason: Oh, you fancy!

Laurie: After the import default specifier function, let's look at a JSX element. So, comma, JSXElement. And then that's gonna take path. And wonderful. We got -- we have to close it.

Jason: Do that thing...

Laurie: It's not closed. We need another closing.

Jason: Yeah. What happened? Something went weird when I tried to push buttons. It was in very confusing ways. All right. Okay.

Laurie: So, if you're ever -- actually this is a good thing to show -- if you're curious and you're not exactly sure what you're going to get and you don't want to break the right side of the AST explorer, fun fact. I have done that. And literally busted the whole page, and return from cache. It remembers the things. You can do console.log path. And it shows us everything that's passed in. Look at the pretty things!

Jason: Okay.

Laurie: So, inside our node, we're looking for the name, which is a JSX identifier. And we're looking at the name of the name. Yes, that is confusing.

Jason: Okay.

Laurie: So, we want to set path.node.name.name. To boop. But this is gonna be wrong. So, we'll explain why. Oh, pass.node -- hold on. We might be one level --

Jason: JSXElement.

Laurie: JSXHelp. We have to get into the opening element. Dot opening element. It's hard, there's not enough screen real estate and I'm not scrolling. No, I have not memorized the order of the AST.

Jason: Wait a minute, JSX --

Laurie: Path.node.opening element. There we go. But this is still wrong. Because this is changing -- this is changing all of this stuff.

Jason: No!

Laurie: So, what we want to do is if this is button, then change it.

Jason: Okay. So, if path.node.openingElement.name.name=== button --

Laurie: Then do that thing.

Jason: Then do the thing.

Laurie: Otherwise, alternatively, we can do a return. Just an empty return and then make it does not equal, equal and do an empty return and go into it otherwise.

Jason: Sure, sure.

Laurie: This is worth mentioning only because if you're doing a bunch of logic for a subset of things, an early return will make things run faster. In this case, it doesn't matter because we're doing a single assignment. But if you had a bunch of calculations and logic that you were doing inside of this and you knew that you didn't actually care about the other things, early returns are your friend. Recursion is expensive.

Jason: Recursion is expensive.

Laurie: I mean, to a certain extent.

Jason: Recursion is expensive.

Laurie: Are you doing a recursion joke on me right now and it's going over my head?

Jason: Recursion is expensive.

Laurie: Oh, no.

Jason: [laughing]

Laurie: It's fine. Laurie gets jokes. It's fine. So, this works, right? If we look to the right, this works.

Jason: Yes! It's -- and I'm happy. I -- I do have some questions because it did -- like the thing with a code mod like this, I see a bunch of edge cases.

Laurie: Let's talk about them.

Jason: We learned that we can check the name. That's actually really cool. This is something that is immediately human-readable. I'm looking for buttons. Once I know where the button is, then I can tell, okay, I want to change these buttons to boops, perfect. And I don't want to check anything else. Great. I can check that. What I don't know -- because I can do the same thing up here. I can say for my import default specifiers, the button, change it to boop. But I'm noticing there's an opening element here. So, in JSX you would have sometimes -- and sometimes in the same component -- you would have an opening and a closing element. And so, we would want to catch that. And then that makes me wonder, like, are there other situations in JSX that we have to look for? Like other ways that elements can be categorized that they can be used as? And so, how do you go about kind of -- how do you even chase these down without just knowing all the ways this something can be used?

Laurie: You learn all the way that something can be used. I mean, that's really --

Jason: Issues get a file.

Laurie: The joke is that you've never found so many edge cases as writing a code mod. And it's really true. Because the number of ways that you can write things in JavaScript is a true Achille's heel for writing code mods. That being said, there are twice put all of those in our tests. So, let's try changing one of these so that they are explicitly an opening and a closing element instead of the self-closing element and see what happens. See if still fixes itself.

Jason: Whoops. Nope. It breaks.

Laurie: Exactly. So, this is -- we could -- we could go into the JSXElement and look for the closing element and do the same logic, right? Or we could try a slightly different way that works slightly differently because we have fun here. So, one of the things that Babel has is a bunch of different functions and sort of helpers throughout your code.

Jason: Okay.

Laurie: That you can use. And one of them is specifically for imports. And the ability to find usages of those imports.

Jason: ooo... okay. That sounds like what I'm after.

Laurie: So, if you want to go into our import default specifier --

Jason: Here.

Laurie: Yep. And console.log, path.scope. Let's see what shows up. There's this thing called "Binding."

Jason: Bindings. Okay.

Laurie: You want to click on that.

Jason: Button.

Laurie: Button. That's interesting, bindings, button. Reference pass. Let's click on that.

Jason: Ooo... 7. I like that. That looks like a number of uses.

Laurie: That does look like a number of uses. And more than the number of uses, it looks like the uses themselves. This is why path is what's passed into the visitor instead of node. Because node is literally what we see on our AST. But path is all of this other really helpful information about how JavaScript works.

Jason: Oh, my goodness. Okay. All right. So, then I can go in here and I can do, let's see. I've got my path.scope.bindings.button. So, if I want to do like uses. Path.scope.bindings.button.reference path, was it?

Laurie: .reference pass. Yes.

Jason: Wait. I did this wrong. Bindings, button -- and I need to do capital B.

Laurie: Yep. And then --

Jason: And then... button.

Laurie: There's a few different ways to do this.

Jason: Reference paths.

Laurie: Reference paths. You can also do -- there's a get binding function which can take a string if you wanted to do that.

Jason: Okay. That seems like that's probably the safer way to go. How would I -- is that on --

Laurie: Yeah, so, path.scope.getBinding is a function which can take a -- you could grab the local name from the import you're in. But we know we want button so we're going to cheat a little bit. And then that's .referencePaths at the end of that function.

Jason: Cool.

Laurie: Or we could do uses.referencePaths. Either way. And that's going on an array. And so, we want to loop through this array.

Jason: Okay.

Laurie: And we're about to make use of what is essentially an inner visitor -- so, we don't have to go this far, but if you ever wanted to look at identifiers that are in the subtree of an import default specifier, you can essentially make another visitor that you call and because you're calling it inside the scope of a previous visitor, it's only looking at stuff that's in that subtree. Because in this case, we're looking at references and we're -- if we wanted to, we could go, like, sibling -- we're going to a sibling and then going down again, it's not considered the same thing as an inner visitor.

Jason: Okay.

Laurie: So, we have our reference paths. And for each we are going to get the use. You called it use, right?

Jason: Yes.

Laurie: And let's log use. Let's just see what's there. Because these are those things that if I just --

Jason: Log use.

Laurie: If I just start saying things, people are going to be like, what's there?

Jason: Oh, so, each of these is now like its own path.

Laurie: Right.

Jason: So, we've got a node and we can touch it and do stuff with it.

Laurie: Exactly. So --

Jason: But. They are not the same.

Laurie: They are not the same. Do we know why they aren't the same?

Jason: Because they're different things?

Laurie: So, they are the JSX identifiers. Because it knows that's what button is.

Jason: Right. But they're not all -- are they all -- so, this is a JSX identifier. This one -- oh. But that's the parent.

Laurie: That's the parent.

Jason: Got it, got is, got it. Each of these -- but what if they didn't have the same type? Like, how would you -- let's say I use this -- I don't know -- like I put together something in here that's like... and for whatever reason I decide that that's a thing I should do. And I drop it in like this. So, this is still valid.

Laurie: Yes.

Jason: But we need to catch that now.

Laurie: Yes. So, we are still going to get -- that should still return with what we're using. As long as it's still that. Perfect.

Jason: It does. But now it's a different type.

Laurie: Now it's a different type. So, inside our uses, this is where we're thinking about everything as sort of its own visitor. So, we're gonna check the types to make sure we change each of these correctly. We know we're getting all of the references, but code mods are a series of edge cases. We do need to figure out what different types we're gonna be looking at so that we can change them correctly. Because we can't just default change everything the same way without worrying about the fact that AST is no -- like each node has a different structure and needs different information.

Jason: Okay.

Laurie: So, let's start with -- we can close our console now because this is getting hard to see.

Jason: It is very crowded in here. That is true. Okay.

Laurie: We're no longer in our JSX element, we're no longer in our opening element. We're in a JSX identifier. If we look at the code at the bottom where we were assigning .name, that's what we're gonna do again. But we want to check what type we are first.

Jason: Okay.

Laurie: So, you know how to do that.

Jason: Um... I'm gonna change this to be something that looks a little more nodey. I'm going to call it refPath.node.type. Then we would do like refPath.node.name.name is it? Or, wait, no, we're just write in here --

Laurie: Yep.

Jason: We can just do it like this. Okay. So, that's working. That's doing what we want. Let me turn this one off.

Laurie: Oh, yeah. Good idea.

Jason: Okay. So, that's not gonna just let me do that. I'm just gonna delete --

Laurie: Delete it. Delete it.

Jason: I don't want to delete it. I want to keep it so that we can show people what we did.

Laurie: Okay. Oh, no, Cassidy showed up, we're about to get boop-attacked.

Jason: Oh, no, Cassidy is here. Hi, Cassidy!

Laurie: Fear the Cassidy.

Jason: Yes.

Laurie: There's another way to do line 17. We got T types from Babel.

Jason: Okay.

Laurie: The types package comes with a bunch of is functions. So, T.isJSX identifier that we pass a ref path into is a valid thing.

Jason: Okay. I can go isJSXIdentifier -- that is hard to spell.

Laurie: It might be refPath.node. We'll double check.

Jason: Looks like it did it.

Laurie: Yes.

Jason: And do another one down here. If t isVariableDeclaration, I think it is? And refPath.

Laurie: And if we were doing something a more complicated, do a return. Or if-else. We are trying to cut down as much as possible on code we don't want to run.

Jason: Actually, before we keep going, I wanted to bring this up because I think it's important. The first time that hi did ASTs, I was really kind of upset by the fact that we're mutating state, right? I was like, this doesn't seem right. Like, why wouldn't we create a new copy with changes? And why don't they do that?

Laurie: So, there's a few -- there's a few reasons. One of them is because this is expensive to do. And you're doing it a lot. And creating more memory usage to assign things so that you're not mutating state is -- is a waste of resources that you don't need to be wasting.

Jason: Yeah.

Laurie: The second reason is that it's faster.

Jason: That was -- yeah. That was kind of the thing, right? And that's the visitor pattern, right? And the way that I -- the way I think about the visitor pattern and how I get this --

Laurie: Yeah, please do. This is not easy for me to explain.

Jason: So, I think of the visitor pattern as being like an actual visitor to your house. When you have someone come and stay with you, they're going to visit different rooms in your house. They're going to -- without meaning to, with all the best intentions -- rearrange your stuff. And then they're gonna leave. Right? It's still your house and still your rooms. But when you go in, things are different than what you left them. And that is basically what the visitor pattern is letting you do. Something is coming into a node and making some changes and then it disappears and you have the same tree that you had before, it's just the same differences.

Laurie: And we can take that analogy further to explain what is probably the most interesting thing about visitor patterns. If someone comes into your house, their house is different than your house. But they know that your bathroom is a bathroom.

Jason: There is a high probability that there will be a toilet in at least one room in this house.

Laurie: Right. And they know a bedroom is a bedroom and a kitchen is a kitchen. Even if they haven't been in the version that you have, they know what the function is, whatever house they visit, they know how to use that room because they understand what functionality is provided by that room.

Jason: Yes, exactly. I'm getting booed for not making that LEGO-based. I'm sorry. You know what? It's probably going to damage our relationship. But I'm just not a LEGO person.

Laurie: You don't have to be a LEGO person. As long as you don't hate that I'm a LEGO person. There's no damage to any relationship to that. I'm not a taco person.

Jason: Cassidy is upset.

Laurie: It's okay. I just admitted to the fact that I don't like tacos and burgers on a livestream.

Jason: Yeah. Hold on. I was gonna let that slide. But you brought it up again. So, you -- like, you don't like them at all? Like you don't eat them?

Laurie: No.

Jason: What do you eat?

Laurie: Lots of things that aren't those things. So, for most of my life I didn't eat red meat.

Jason: Okay.

Laurie: I eat a little bit more of it now. But the burgers thing just never really stuck.

Jason: Because you haven't had my burgers yet.

Laurie: And then the tacos, for me, it's -- I'm not a mixing ingredients person.

Jason: Oh!

Laurie: I know that's terrible.

Jason: Did you grow up -- okay. I have a question. Did you grow up -- like did your parents give you your meals on those plates with like individual trays for each side dish so that your food never touched.

Laurie: No. But I would have appreciated as a child. I was a very picky eater. Like, cut off the crusts, have grilled cheese multiple meals a day picky eater. So, the fact that I eat a lot of things is impressive. I just haven't gotten as far as tacos.

Jason: It's baby steps, you know? It's all right. It's okay. Okay. If the juice from the peas touches anything else, it's poison -- I don't necessarily disagree with that one. I have gone the other way. I thought may dad was weird for this, he would get a plate of food and mix it into a mash.

Laurie: No, can't do it. Just thinking about it! Blahh!

Jason: I'm into it now. I want all the flavors.

Laurie: Many I brother-in-law does this after Thanksgiving, for breakfast, he'll make a bowl with everything in it. I can't even look at it. I can't. No.

Jason: Yeah, my dad does this thing. This is going to gross out the people that don't like food to touch. He does a thing called garbage stew, when we get toward the end of a life span of something in the fridge, what's about to expire? He puts it all in a stock pot. I don't know what you would call it. It's literally just all the garbage from the fridge boiled and then we cans it so it doesn't finish expiring and then he just eats that.

Laurie: Okay. And on to topic. We can talk about desserts and I won't feel squeezed out.

Jason: All right. Okay. Let's focus up. What am I doing here? This is not what this show is about. We need to get something done here. And we got about 30 minutes to do it. Okay. So, I -- I now have -- oh, I had another question, actually. A JSX question that was not about food. So, someone asked, why would you do this versus just editing the file directly? And Chris made a good point that like one of the use cases is that you would want to be able to do this potentially thousands of files.

Laurie: Yes.

Jason: But there are other use cases. And you talked a little bit at the beginning about this. But now that we've looked a it the, let's revisit what Babel was created for initially and why you would use it.

Laurie: So, we're doing this because we want to modify code that, you know, we write. But let's say that a very common use case is new features coming to the JavaScript language. And you want to be able to use -- let's go, you know, back a few years. You want to be able to use arrow functions. You really like them and think they're cool. Browsers can't understand arrow functions. But they're valid in the spec now or someone's proposing that they'll be valid in the spec. And so, they write a Babel plugin that you can use and add to your configuration that will change all of your arrow functions into function functions. Using the function keyword. So, that any browser -- or JavaScript engine that can't understand arrow functions is fine. You can still write code with arrow functions. But when it's compiled and actually pulled up in the browser, it's using syntax that JavaScript engine can parse and understand.

Jason: And so --

Laurie: React does this too. Or did for a long time. Like, all of the components were turned into class components.

Jason: Yeah.

Laurie: React.classCustom element was a thing.

Jason: And asking is this how polyfills work? Sometimes.

Laurie: Sometimes.

Jason: Some polyfills are extending the browser to do more stuff when it's the case of the browser having an API that could be supported by the browser, but not released yet. But right now we're looking at nullish coalescencing or optional chaining just hit the browser. Up to that point, if you had written that into your code, you would need Babel to turn that into something the browser understood so you wouldn't get an error.

Laurie: And someone is asking, if I could grab the official plugin? Yes. Most people will not ever need to write these plugins. But if you're grabbing plugins or presets which are a bunch of plugins pulled in together, it's nice to understand what they are and what they're doing. We can pull up the Babel AST site. You can run any plugin with code and see what it actually gets transformed into a. I think it's actually on the --

Jason: Which?

Laurie: If it's on the Babel site, it's their top doc. I'm pretty sure. It's really hard not to pull up plugins when you do this. Try it out. Yep.

Jason: Yeah. Okay. So, one that is -- I wonder if it's gonna let us do this. It would be like...

Laurie: Nullish coalescing.

Jason: This is what happened when you go through Webpack and Babel, when you generate a JavaScript bundle, it's running through plugins. And the most popular one, Babel preset end. What present end is doing, it's looking at everything that's at stage 4?

Laurie: No. So, preset is updated every time ES is published.

Jason: Got it.

Laurie: So, if you're in stage 4, you hit ESNext. That's published once a year in July. Roughly July.

Jason: Got it.

Laurie: If it's in preset, it won't be in officially until the July publish date and then becomes part of the preset eng package.

Jason: Got it.

Laurie: Because the rule for being an adopted piece of syntax is that you have to have a working Babel plugin.

Jason: Here too, this targets thing, another really important thing here is -- is it like, if I just do chrome latest, does that work? Ah, what is it? Does anybody remember the syntax for browser's list to just get the most bleeding-edge version.

Laurie: Is it LTS? If you just put LTS, does that work? How does it go again, 1 to 4 -- it's in the language. So, when you propose a new piece of syntax, it's stage one, stage two, stage three, stage four is considered adopted and it's an ECMAScript @next. And the release happens with erg in ESnext. Yeah, I don't know how to get the targets either. I've never used that field.

Jason: There's a cool thing -- is it -- yeah. Maybe chrome last 2. Oh, I could have sworn that worked. I can't remember which one it is, but if you use -- actually, let's find this.

Laurie: Yeah, I'm Googling too. Get latest Chrome, browser list, last two Chrome versions.

Jason: What I'm looking at here, I want -- I don't want defaults. I want to say like, literally give me just the most -- this is what I said. Does it have to be capitalized?

Laurie: Yeah. I was just looking. Yeah, that's literally what you wrote, isn't it?

Jason: Uh... what is nullish --

Laurie: Nullish coalescing.

Jason: Is not dropped. Okay. So, let's do -- I want something that it will actually --

Laurie: Oh, that it's gonna drop.

Jason: Yeah.

Laurie: Yeah, nullish coalescencing was last July. So, it's certainly possible --

Jason: This should absolutely not -- hm. Okay. Whatever. So, the general idea is, like, if we have... right. We have a function like that. But then if I do IE11.

Laurie: Yeah, that will work.

Jason: Then it gets translated. This is kind of the power of Babel is that we can say which browsers we're targeting. And it will, like, make the necessary changes. So, like in Chrome, we don't have to make a change at all. We just ship what we have. But in IE11, we have to rewrite it to not have an arrow function. This is why Babel is so cool. It lets us write JavaScript the way we want to write JavaScript. And then using these AST transformations, we're able to target like older browsers without having to think through like the checks that we used to do. And in you've never had to write those browser checks, like you've never had to do user agent hacks or something to figure out which browser you're using and then rewrite your JavaScript or do like, you know, if something in had navigator, then do it this way or else do it this way. Those types of checks are -- I think it's a large part of the reason why people rallied so hard around jQuery is that prior to that, writing JavaScript was a nightmare. Because we didn't have that browser consistency. And Babel has almost made that a thing that nobody even thinks about anymore. Which is, I mean, honestly, unbelievable.

Laurie: Yeah. And what's wild to me is that there are now frameworks that are making people not even think about Babel. So, it's -- the abstraction is increasing, but there's also negatives that come with that. And I mean, not to be the, like, pessimist on the show. But if a lot of people don't know that this is happening. And so, if you're seeing issues where, you know, your site won't build because your -- you tried to use optional chaining and you saw a Tweet that said optional chaining is now working and it's not, and you don't know why and try to update the node version and it doesn't work, and then the build works in your browser, understanding all of these layers and where these plugins come from and how they're controlled is helpful and important. And there are plenty of people who will never have to understand any of this. But it's useful context. As you just explained, there's an origin story behind Babel. And there's an origin story behind frameworks that extract Babel. And as you add these abstractions, if you don't necessarily know those, it gets a little bit confusing to try and make changes when things aren't working as they're supposed to.

Jason: Right. Absolutely. I just tried to -- despite my best efforts, I still can't breathe coffee. Jeez. Okay. All right. We're ready! We're ready! So, what I would love to do is let's figure this the rest of the way out and then I would love to actually install this plugin.

Laurie: Let's try it.

Jason: We're so close, right? Then we can see the whole thing in action.

Laurie: Yes.

Jason: The last one we need to get is this one here. Is this just our identifier? How is that working?

Laurie: It's a variable declaretor that we're getting.

Jason: I did this wrong. Declarator. Okay.

Laurie: We might be getting the declaration. This is a variable declaration inside the declaretor. I think we're --

Jason: It's right.

Laurie: Declaration was right. We lost the plot and therefore we forgot it was right. Apparently that's a British phrase and I love it.

Jason: It's not there. I'm gonna return here so that we only log if it's not --

Laurie: Yeah, let's see what's going on. We probably just --

Jason: I just forgot what it is. The type is the node.

Laurie: Variable declaretor.

Jason: It just says --

Laurie: We were looking at the parent. I got caught by the same thing. The container.

Jason: Oh, the container.

Laurie: Container and parent. If it is identifier and then we're going to change the name directly, it will be the same. So, interestingly enough, it is the same. So, we may not even need this.

Jason: ooo, so, we could just double logic.

Laurie: We could double dip, yep. We don't need to. We grabbed the ref paths.

Jason: But wouldn't we want the guard we need it in another way? Put it inside a function.

Laurie: We want this guard if we are writing this for actual production code mods. Which we're going to change a very small number of files.

Jason: If this show has taught us anything, it's that we only produce production code on Learn with Jason.

Laurie: Absolutely. And we don't need to return -- we don't need to return anymore. It will return automatically. Because there's no other check.

Jason: It's not working.

Laurie: What's not working?

Jason: Boop. It then we lost 'em all. We broke -- oh, that's because I did bad math.

Laurie: Or.

Jason: Ah-ha. There. That.

Laurie: I wouldn't consider that math. I would consider that --

Jason: Math comparison.

Laurie: Logic?

Jason: Logic is math, right?

Laurie: That's true. I took a symbolic class as a math major. So, I consider it like a parallel. Because it was in the philosophy department which is really interesting.

Jason: I do think -- this is a little bit of a tangent that I'm going to take 10 seconds on because I really want to get this working. But I am truly convinced that learning logic, like as a discipline, is one of the most important things that we can learn. Like inside and outside of programming. Just like as a human being. Like when I started to think about how to apply logic to like situations, like how much I use it for deduction and like making predictions about my actions and like whether or not -- like if I do this, then this might happen. Then this might happen. Being able to think three steps into the future. I'm in the necessarily right. It doesn't making me like more capable as a human being. But what it does, is it lets me predict when something is gonna go horribly wrong in a way that I wasn't able to when I was like 15 and not thinking like that. And it helps me keep my foot out of my mouth which is really the big thing that I'm after.

Laurie: I also find it fascinating.

Jason: Yeah.

Laurie: I just think logic is really fun.

Jason: Agreed.

Laurie: We have to learn when to use what we learned about logic. I have not been good with keeping up with chat. But chat is popping.

Jason: Chat is always popping. I love chat. We have the Babel plugin. I'm going to copy-paste in what we did. This is huge today. What did I do?

Laurie: Yep.

Jason: I've got this Babel plugin now. It's in, it's here. We've got our code mod. And I'm happy, I think.

Laurie: I think you are happy. Scroll up to the top. Let's check. Export default function. I believe you are happy. Should we not be happy? Are you seeing something that I'm missing?

Jason: I like to be happy.

Laurie: Vanilla React -- do you like that I'm calling things vanilla React come with Babel? I don't think it does.

Jason: It has to. React scripts.

Laurie: Oh, it has React scripts.

Jason: Yeah, this is create React app. React app, custom Babel, are you going to let us do?

Laurie: Yes, but it's complicated. It's using React scripts. I remember because I looked this up the other week. So, we're going to have to get this -- there's a helper package. Oh, my, Max. Max is my colleague. He's in the GitHub, not in the chat.

Jason: Oh, I was looking at the chat like, where is Max? That would be uncanny. Look at Max, here and here. Okay. So, the point of this -- provide defaults. It looks like -- we can just eject it, right?

Laurie: Yeah.

Jason: Because then we get the Babel. Let's do that.

Laurie: Yes. There is some plugin that I saw the other day that's like customize Babel React scripts something. But I have not used it myself. So --

Jason: Oh, I need to install, I think.

Laurie: Ah.

Jason: Then I can do stuff.

Laurie: Then we can do things! Also, how did I know that we were going to wind up putting this into a project where I'm like, what are the configs already here? Instead of something that's got a Babel.rc setup. [Lovely elevator music]

Jason: Stracciatella. When I was in Rome, we were there for like a month, and there was -- the area that we were staying in, I can't remember what it was. But there -- it was like this kind of little section of really good food. And right on the outskirt of it was a main drag where a bunch of tourists hung out. And there was a gelato shop that had half of a mint green Volkswagen bus out front. And they like -- I don't think I liked gelato before I went to Italy because I'd never had good gelato. It was always like, this is ice cream, but not as good.

Laurie: I'm sorry, what?

Jason: I know. After I had gelato in Italy, I realized I was going to the wrong places and my world changed.

Laurie: Gelato not as good -- wow. I'm upset.

Jason: It was a lot.

Laurie: You're upset by my taco statement and I'm upset by your gelato statement.

Jason: Yeah. We -- okay. So, I'm going to eject and we have like 15 minutes here.

Laurie: We can do it! Are you sure you want to eject? Yes.

Jason: Oh, god.

Laurie: Maybe we weren't -- has untracked files. Oh, this is just because it's not...

Jason: Get out of town. Okay. So...

Laurie: Do, do, do -- now I have the, please hold, music, stuck in my head. And this is a problem.

Jason: All day. All day.

Laurie: Why did you do this? Okay. That looks more promising.

Jason: Okay. It's doing things. What happened? Where are we going?

Laurie: We're loading, loading, loading. Keep those prices loading! [Hold, please -- music...]

Jason: Not a gelato burger. But, oh! Speaking of gelato, there is a place that I went to in Toronto that made fresh cookies and fresh -- I can't remember if it was gelato or if they called it ice cream. But it was this really like kind of custardy-style of ice cream. Like very thick and creamy.

Laurie: The Rita's custard? Is Rita's an East Coast thing?

Jason: I don't know. I've never had that.

Laurie: Oh, Rita's custard is phenomenal.

Jason: But, yeah. This was the kind of place that it would be 11:00 a.m. on a Tuesday and they would have a line out the door around the block for these ice cream sandwiches. And, you know, we were in -- we spent a couple years like traveling full-time. Which is why I have been in all of these places.

Laurie: Right.

Jason: But I ate so many of those sandwiches. I also think I hit that gelato shop in Italy like 25 out of 30 days I was there. It was every day. Should I go try more of this gelato?

Laurie: The answer is always yes.

Jason: I'm only here for a if more days. I should eat all of that gelato.

Laurie: I feel like you would appreciate this. I went to Maine on my hone moon for three, four days. And I genuinely had lobster for more than ever meal that I ate.

Jason: More than every meal.

Laurie: There was a lobster role for like every single hour of the day. Because let me tell you, when you are trying to still be the same size as you were 2 months ago when the wedding dress was actually fitted to you, you're trying to be very good about your diet. And then when you're done, you're like, lobster roles for all!

Jason: Okay. So, it looks like Babel when they ejected, they put it into our package JSON. Can we use is like that make it a Babel RC?

Laurie: Let's make it a Babel RC.

Jason: Okay. I'm going to pull that out and go down here. It's .p.js?

Laurie: Yes. It can also be a JSON file. That's valid. But I think we want to use JS because of a specific reason.

Jason: Is it like this?

Laurie: I thought it was default.exports dot --

Jason: Yeah.

Laurie: I have been using Babel config recently. So, let me Google real quick. Babelrc.JSON and -- or.js -- scroll, scroll, scroll, scroll -- module.exports. That's what I thought.

Jason: Module.exports.

Laurie: Yep. Yay CommonJS.

Jason: And is it supposed to be an object like this? Does it need to be a function or just be an object?

Laurie: I think it can be an object if we're not doing anything with it.

Jason: I'm happy about that. Keep it simple. If I want to include our plugin, how does one do such a thing?

Laurie: Okay. Presets are things that we are already using. So, we want to have a key called plugins. So, we'll do a comma outside -- yep. Plugins. And we want to make a new array. And let's just see what happens. This isn't gonna work the way we want it to. But let's just see what happens if we do a relative path to our plugin file.

Jason: Like so?

Laurie: Yes. Like so. Wonderful.

Jason: Okay. So, then when I do a -- I think I do a build now.

Laurie: Yes.

Jason: I forget how this works.

Laurie: I assumed.

Jason: Let's just press start.

Laurie: I shouldn't say this out loud. I don't know the last time I used create React app. Don't hate me Max.

Jason: Do you want to do some code mods? [singing]

Laurie: I feel like I need some sort of animation for that. Oh, wait, did I lie?

Jason: It kind of liked this, but didn't like this particular setup.

Laurie: Unexpected token, export.

Jason: Is it because --

Laurie: It might be because of CommonJS.

Jason: All right. Let's fix that. We can do module.exports, right?

Laurie: Yep.

Jason: Try again?

Laurie: Yeah. Let's see if it likes that. Did we save it?

Jason: Yes. Please stop helping over there.

Laurie: This is -- this is honestly my least favorite thing about the JavaScript ecosystem. Remembering --

Jason: I fixed you.

Laurie: I think it saved after you ran.

Jason: Oh, wait. It's doing it.

Laurie: Oh, whoa!

Jason: Okay. How do we see the -- let's see. Does it have like a build? I should just run the build and we should see if it does the thing. I'm going to run -- are we on time? We are coming up against deadline. Let's do this.

Laurie: Go, go, go!

Jason: I'm going run the build, npm build.

Laurie: And I will tell you why it was a cheat and in a production app, we have to do it differently.

Jason: We're going to find out. It's an optimized production build.

Laurie: I think this is still going to work. Potato salad?

Jason: Too -- that is a joke from Family Guy that I have never stopped making.

Laurie: I see. I don't think I've ever seen Family Guy.

Jason: Let's see if we can find this.

Laurie: Oh, god.

Jason: And if this works, I should be able to search for "Boop." Oh, it's probably getting minified. Isn't it?

Laurie: Yep.

Jason: Hold on, that shouldn't be the case. I'm going to try to find button in here. Button!

Laurie: Maybe capitalized? Versus un-- oh, look. That looks. Okay. So, it didn't work.

Jason: It's not working.

Laurie: Yeah. Okay. I think the reason it's not working is because the path that we just gave it is relative to where our Babel config file is. Versus relative to the file that the code is running on. So, we want to do path.resolve. So, that we are getting the -- that it is finding the file relative to when it's running against each of the files. This is like explaining recursion. No?

Jason: Path is not -- oh, I have to import path. That's fine. That's -- I know how to solve that one. Try again.

Laurie: Yes. Let's do it. Can we do it in the nick of time? This would be amazing. Please, please work. Please, please, please work.

Jason: Code in the nick of time... okay. It did a thing.

Laurie: Did a thing.

Jason: This is the map, though. This is a whole different thing. I don't want the map. I want the built thing.

Laurie: Oh, I didn't realize that was the map. Minified.

Jason: It's in the main -- but like what's in here? Is this all crushed?

Laurie: Probably. Oooo... yes.

Jason: They are all crushed. So, okay. So, we're not actually seeing the output which means I'm going to do something... how do I -- hm? How do we actually see this? We might not be able to.

Laurie: Let's look at package.JSON and remove the my minified.

Jason: It's down here.

Laurie: Let's just remove the minified step. I don't know where this is doing it. Got to be somewhere, right?

Jason: Let's see. Build, then, searching, stats, print file sizes, app.

Laurie: Print file size after build at package.

Jason: You feel like it's gonna be in this build script, right?

Laurie: Probably, yes.

Jason: So, build, compiler.

Laurie: Webpack? Cool. Process node, that seems good. Messages and errors. Cool. Return --

Jason: Write stats.

Laurie: Right.

Jason: I don't think it's going to let us do this. Where --

Laurie: No, there's got to be --

Jason: Look in the folder. Maybe it is in the Webpack config in here.

Laurie: Is there a Webpack config in here?

Jason: I was hoping. No, not there.

Laurie: Ah, curses.

Jason: Curses! It is using Tersor, though, if we can find the Webpack config.

Laurie: Let's search for terser, it's got to be used somewhere. Got to be imported.

Jason: Not the package lock, not here, not yarn lock. Webpack config. We knew this was going to be here somewhere.

Laurie: Oh, it's in a config file. Yeah, go away!

Jason: Good-bye.

Laurie: Bye! Bye, bye.

Jason: Okay. Let's try this one more time.

Laurie: We can do it!

Jason: Okay.

Laurie: Also, now everyone is realizing why this stuff is abstracted.

Jason: For here. This is the whole game. We don't want to have to think about it or do it at all.

Laurie: Except we just thought about it for a whole episode. That looks better.

Jason: So, we're pulling in button, what about boop? No results!

Laurie: Curses.

Jason: That's also not doing what we want. So, button?

Laurie: button is there, I think. What?

Jason: It's still compiling down. We're not seeing the thing.

Laurie: I think we would have to change Webpack a fair amount.

Jason: That's okay. We saw it here.

Laurie: Trust that it would work.

Jason: Chat, do you have answers for us?

Laurie: That's a fair point, instead of running React script, run Babel. It's brilliant.

Jason: And let's see if we have... I don't have Babel here. And NPX, Babel --

Laurie: Babel is downloaded.

Jason: yeah, it should pull it from this folder if it's in here. Babel, and it's going to be source, components -- wait. Where is it? Source --

Laurie: I think we can run the whole source and it would work.

Jason: I'm just gonna do app so that we don't have to --

Laurie: Fair.

Jason: We'll do app.js and then out. Can I just -- will it just -- it will just print to stand it out if we just do it this way, right?

Laurie: Ne'er done it this way. Let's find out.

Jason: What? You have mistakenly installed the Babel CLI.

Laurie: What is happening?

Jason: Used Babel instead of Babel CLI.

Laurie: Oh, I was like, what is happening?

Jason: Do what we want! Do what we want!

Laurie: Do what we want!

Jason: Come on, come on.

Laurie: Come on, I have faith in you.

Jason: No! Oh, wait. What is that?

Laurie: Unexpected token.

Jason: Unexpected token. Okay. Now I need to look at this Babel CLI. We're out of time. We're out of time. It's okay. Here's how this works, though, y'all. If you -- you can see what's going on here where we've got an input file. We write the transformers and then we get this output here. And the problem that we're having right now is mostly that this project is already configured. And so, we were fighting against its existing config. But on that note, let me do one more shoutout to the sponsors. We've had Amanda with us today doing live captioning which we deeply appreciate.

Laurie: Thank you, Amanda!

Jason: And that is made possible through White Coat Captioning, the captioning company and our sponsors, Netlify, Fauna, Auth0 and Hasura. Laurie, where should people go other than Twitter if they want to follow you?

Laurie: Check out my website, Laurieondev, that's where my posts go. And I'm an Egghead instructor if you are on Egghead. There's a new course coming up soon. Spoiler alert.

Jason: Any hints on what it's for?

Laurie: No.

Jason: I love it. Yeah, definitely go check that out. And check the schedule. We have some really fun stuff coming up. Next week, I'm going food a solo episode on I believe Tuesday. Yeah, Tuesday, I haven't put it on the site yet. A solo episode to work on stream overlays. Hang out for that. It's going to be great. On Thursday, building flexible CMS stuff. It's like if we could take React components and move that into the CMS as well. That's what Prismic slice machine is promising to do. You can look at that. You can add this calendar on Google Calendar. It's going to be a great time. So, please, come hang out. It's going to be a lot of fun. Laurie, thank you so, so much fore hanging out with us today.

Laurie: Thanks for having me!

Jason: It's been an absolute blast. And I look forward to hearing more about LEGO.

Laurie: I'll teach you to appreciate it. I have faith we can do this.

Jason: I appreciate it. Thank you, we are going to raid. And thank you, Laurie, from the bottom of my heart for teaching us about Babel today. We will see you next time.

Laurie: Bye, y'all!