If you have a code splitting-headache, this might help
Ben Halpern is co-founder and webmaster of DEV/Forem.
Katie Davis is a front end developer, who has previously worked at Shopify and League Inc.
[00:00:01] BH: A common scene in technology companies everywhere, big conference table with the CTO on one end, developer teams on the other, the showdown. We have an idea, “Will it get funded?” More companies are feeling the pressure to go faster and stay ahead of the competition. Projects that have long timelines or no immediate impact are hard to justify. DataStax is sponsoring a contest with real projects, real money, and real CTOs. If you have a Kubernetes project that needs a database, the winner will get funded with a free year of DataStax Astra. Follow the link in the podcast description to submit your project. It’s time to impress the CTO and get your project funded.
[00:00:41] New Relic helps engineering teams all over the world visualize, analyze, and troubleshoot their software. Discover why some of the most influential companies trust the New Relic One Observability Platform for better uptime and performance, greater scalability, faster time to market, and more software. Go to developer.newrelic.com to find out more.
[00:01:02] Eyes glaze over from debugging a remote Kubernetes service? Instead, run your service locally in your favorite debugger and instantly find the problem. Ambassador Telepresence is the easiest way to debug micro services on Kubernetes. Spend more time fixing problems instead of reproducing them. Ambassador Telepresence is free to use for teams with unlimited developers. Get started today at getambassador.io/devdiscuss.
[00:01:28] Educative.io is a hands-on learning platform for software developers. Learn anything from Rust to system design without the hassle of setup or videos. Text-based courses let you easily skim back and forth like a book while cloud-based developer environments let you get your hands dirty without fiddling with an IDE. Take your skills to the next level. Visit educative.io/devdiscuss today to get a free preview and 10% off on annual subscription.
[00:02:01] LB: It is complicated for that reason because when you are creating steps on an assembly line, you have to understand every single step that happens in the assembly line.
[00:02:22] BH: Welcome to DevDiscuss, the show where we cover the burning topics that impact all our lives as developers. I’m Ben Halpern, a co-founder of Forem. And today, I’m joined by a new co-host, Katie Davis, who is also one of our newest colleagues here at Forem. And she’s going to step in for Jess on today’s topic. Katie, do you want to introduce yourself?
[00:03:03] LB: Excited to be here. This is a fun topic.
[00:05:36] KD: That’s amazing. I mean, you kind of touched on what you work on at Gatsby, but do you have a specific project you work on? Or as like a staff developer, are you just all over the place?
[00:05:46] LB: I’m on the OSS side of things. So we do have a product, Gatsby Cloud, which is like the CI build tool for Gatsby, the framework, but I work on the framework side. And so we have a framework team that works on literally like the core Gatsby package, but Gatsby has a plugin ecosystem. And so pretty much all of the functionality is officially maintained packages. And so I am on whatever package is the flavor of the month that we either need to fix or add new features to. So we’ve been spending a lot of time on images lately. I was working on this really in-depth code mod. It’s like ASTs and Babel parsing. We were working on a brand new CLI interface. So it’s all over the place. It jumps around. It’s almost like consulting in some ways, because I joke, I’m like, “I have to dive into a brand new package library that I've not seen and worked with.” And all of a sudden, it’s, “Okay, learn a completely different thing with completely different technologies that integrate in a completely different way.” So it’s a lot, but it’s a lot of fun too. You learn a lot.
[00:06:45] BH: So Laurie, you wrote a post on DEV entitled, “Code Splitting Explained.”
[00:06:50] LB: I did.
[00:09:04] LB: Yes. I mean, newer is relative. Right?
[00:09:08] KD: Right.
[00:09:09] LB: Yes. But definitely. And I think for a lot of people, familiarity with working in browsers can be sort of strange and you’re like aware of Webpack or you’re aware of Browserify, but there’s all of these framework level abstractions where you don’t see these things happening. And so a lot of modern frameworks, because those things are complicated, are actually doing this for you. And so there’s code splitting that happens that gives you performance benefits that you aren’t even told about. But if you’re doing it natively or you see something weird in a framework that you’re working with and you’re like, “Why is this doing like Webpack chunk, whatever?” That’s what it’s doing.
[00:09:43] KD: So would you say like some of that was what inspired you to write a post about this topic?
[00:09:47] LB: So actually what inspired me was we were working on this image package and my colleague was dealing with this really gnarly situation where there was a lazy loaded import that we had that was causing a bug. And basically the bug was if all your first page that you went to in your site, you didn’t have an image, the lazy load on the second page that you went to would take too long. It needed to load the first time you went to the site, regardless of what site you went on, rather than just on route change. And so he was changing all these things around and he had this line that was just in line. It wasn’t at the top of the file that said import whatever from lazy hydrate. It was import lazy hydrate then inside the code. And I was like, “I know you can do this, but why are you doing this? It just sort of makes it messy.” And he was like, “Oh, that’s for the lazy loading.” And I was like, “Oh, of course, because we overload.” I have a post about this. It’s called, “Is It Web Pack or Node?” But it’s basically this idea that because we have CommonJS standards, because we have Equus Script standards, all of these things, there’s a bunch of function names that we overload because different technologies are adhering to the spec, but then you don’t necessarily know which version of that function you’re using. So that import function that I was looking at was not an ES6 import function like most people are familiar with. It was a Webpack import function, which has different implementation under the hood and operates slightly differently even if it appears roughly the same if you’re reading the code just as characters on a screen.
[00:11:22] BH: So let’s say I want to support an API that’s available natively in Chrome, but not in Safari and isn’t coming to Safari anytime soon. I may want to support that functionality, but I don’t want to load all the code for the polyfill for every browser. So I might dynamically import the code for that polyfill only for Safari web browsers, and that would be an example of code splitting via dynamic import as a function, but code splitting refers to a variety of approaches, I imagine, library specific, framework specific.
[00:13:16] KD: I would like to clarify though, like how tree shaking fits into this.
[00:13:20] LB: The best way to explain this is if you are working in an IDE and you get one of those little red squiggly lines in VS Code or whatever, that you’ve put a return statement and then you have this other line of code and it’s like this code will never be hit because you have a return statement for it. That’s sort of what tree shaking is about, but it’s not something that you can necessarily statically analyze. It’s analyzed at build time and it’s saying, “Okay, this code that you just built, there’s a whole section of code that will never be run in this scenario and so we’re not going to include it.” I mean, it’s mostly for dependencies, right? So there’s all of these functions in the dependencies that we’re not going to use. So there’s a lot of different ways to talk about how this ends up shaking out. I mean, tree shaking is a problem and isn’t necessarily implemented in a way that’s super usable right now. It’s great in concept, but it doesn’t always work, but there’s ways in which people have implemented things that are sort of tree shaking. So for a long time, when you use Lodash, you had to download the entire package and they created a Babel plugin that basically goes through and says, “Okay, we’re only going to conditionally import these three functions and you don’t need to include everything else.” And that was their way of sort of getting around, having to do tree shaking for the entire library, where there were just hundreds of functions and people were only using, let’s say, two of them, but they’d imported the whole thing.
[00:14:46] KD: Can you sort of give us some examples of different ways we can use code splitting to be more performant?
[00:14:52] LB: The good example is if you’re importing something into a file and you don’t actually need it for let’s say 50% of the use cases and there’s some kind of condition that says, “If you go here, I’m going to call the function I just imported,” you probably want to dynamically import it inside that code because then it’s not getting grabbed in these cases where it’s not being used. But for most people it’s having an understanding of how rendering on your site works. I mean, honestly, this gets into some of the nitty-gritty of like understanding how pages are rendered on screen, the order of operations, how things download, like when React comes to be, and it doesn’t always have to be React, right? This is just the example in my head, but there’s a lot of different steps that happen. And so if you understand those things and you can make intelligent choices and say, “I know that I want this thing to load before the layout of the page is available,” for example, then you get to start making choices. Or, “I know I don’t care about this thing because it’s an interactive thing and I need to have everything on the page before anyone’s even going to click on the form field or AB testing or whatever.” Like there’s a lot of those things, but it requires you having an understanding of how you intended people to use your application to a certain extent. It’s all context driven because for some people, the most important thing in the world is that the hero image is the first thing that appears on their page and nothing else can happen. For other people, as long as you can click the button, it doesn’t matter if all of the background images showed up because most people are just trying to click the button to get off the page. Right? Like different user experience concerns.
[00:16:48] BH: Sick of your laptop overheating every time you try to run your Kubernetes application locally? With Ambassador Telepresence, you can intercept your services on your local machine so that you can develop on your services as if your laptop was running in the cluster. Never worry about running out of memory again no matter how complex your Kubernetes application gets. Ambassador Telepresence is free to use for teams with unlimited developers. Get started today at getambassador.io/devdiscuss.
[00:17:18] New Relic knows that the planet needs our help. That’s why they partnered with our team at DEV to host Hack the Planet. From now through February 28th, you can take advantage of their free tools to build a climate change monitoring app with the power of software observability. It’s a great chance to win cash prizes, community bragging rights, swag from New Relic and DEV, a tree planted in your name and other prizes too. Learn more about the Hack the Planet Contest on New Relic’s dedicated community hub, therelicans.com. The Relicans is your place to connect with other developers, meet the team behind New Relic’s software monitoring platform, and show off the app you’re building for the Hack the Planet Contest. That’s therelicans.com. Happy coding!
[00:18:06] BH: Let’s talk about how code splitting comes to be in certain popular tools. So build steps, Webpack, Browserify, how it might work specifically in Gatsby. Can you give us a little bit of an overview about some of those things?
[00:22:35] LB: And then there’s like Rollup and Snowpack, which I haven’t looked in, like they’re in our code base and I’ve sort of seen examples of them and I don’t think both of them are in our code base. Rollup is, maybe Parcel is. I can’t remember any more. This is the problem.
[00:22:50] BH: Yeah. I certainly have some latent anxiety over different eras of this type of work. I’m really happy that Ruby on Rails integrated Webpack and won’t change that until some future decision that the framework will maybe make and allow us to transition. But it’s kind of like almost up to someone else to figure out if we need to move to something like Parcel, and you certainly could, but there’s a default and there’s someone else deciding like this is the decent default for now. I have really appreciated that because I’ve had certain periods of anxiety over someone in an organization I’ve been with proposing a new build tool and me being worried that this might also need to change six months from now. Webpack seems to have had some lasting power, even if it’s pretty complex, at least it gets a lot done and is fairly standard. And some of the new tooling maybe seeks to simplify what it does, which is probably a good alternative. You got something that’s very all-encompassing and has a lot of configuration options. And then things that came after it, which maybe seek to reduce some of that for simplicity, which is probably a good direction to move in. What you probably don’t want is something that’s extremely, exactly equivalent that is now replacing it and becoming the standard.
[00:24:17] LB: Yeah. I think it’s also worth noting that, I mean, anytime you switch out technologies, that’s stressful and depending on how much work you need to put in. But to me in terms of potential for catastrophic consequences, the build tools are the last thing you want to have to change. And so if you don’t have to and it’s working and you could keep it stable, I don’t care what the latest and greatest thing is. Just keep going.
[00:24:40] KD: Agreed.
[00:24:41] BH: Yeah.
[00:26:03] KD: Yeah. I mean the amount of recruiters that come back to me with ASP.NET.
[00:26:08] LB: Oh, yeah.
[00:26:08] KD: But most things like I think we’re safe with legacy code. My old work still has a Gulp file running first, like it’s fine.
[00:26:16] LB: Yeah. And then there’s stuff that intimidates me. Like you at Forem uses Preact and I’m just like, “I know it’s a thing. I don’t want to look at it. It’s a whole other world. Can of worms! Don’t want to do it.”
[00:26:27] BH: Well, the nice thing about Preact is it’s mostly a copy of React with a slightly different underlying.
[00:26:33] LB: So I’m told, but every time I have ever been told something as a copy, it is not.
[00:26:37] BH: Oh, yeah. It’s also diverged, I think over time. I’m not sure I remember how to do React development so much because I’ve been using Preact.
[00:26:44] LB: Right. And almost the worst situation is when someone tells you it’s a copy, this is how I feel about having use TypeScript in its infancy and then not using it for a bunch of years and then coming back to it is I have patterns in my brain of what I expect to happen because I think I know the thing. And then it’s changed ever so slightly, but not enough for me to notice. And then I’m like, “Oh, crap! I’m in trouble now.” So this is my fear of Preact, right? But like it’s close enough, but also different enough that it’s going to be 10 times worse. It’s harder to learn something when you have existing patterns in your brain that you have to break than it is to learn something from scratch.
[00:27:20] KD: Absolutely. I will say a week into it, Preact does seem exactly the same as React to me. So if that makes you feel better.
[00:27:26] LB: All right. I’m going to need a Twitter DM when you find like the four edge cases that are going to haunt my dreams.
[00:27:31] KD: I’m sure I will right after this.
[00:27:34] BH: On this topic, what I think is nice about dynamic imports in code splitting is that you can apply them selectively and get some wins. So you can start using some dynamic imports. You can take a look at what’s on the top of the file and say, “Hey, this isn’t needed until later, I can put this somewhere else,” without having to overhaul the code. It’s not really a structural change as long as it fits the needed pattern in line. And when I started getting into using some of those APIs, that’s how I felt. I was able to make a few optimizations within the file without any major decision-making having to happen outside of that context.
[00:28:13] LB: Absolutely. That’s how things become more approachable and something that you can onboard into because you can do it in stages instead of kind of like an entire rewrite. I will say, like, when you’re using the actual Webpack build script that you have, that one is maybe a little bit more challenging to do the overall code splitting depending on what your current setup is. But for the inline dynamic imports where you’re literally in a file and you’re using that import keyword within the function that you wrote, that’s great. I mean, you can go to five different files and say, “I have Webpack installed in my system. This is going to grab the Webpack import. I’m going to import this random thing dot then,” and it just works and I can remove the top line import. And that’s amazing. TypeScript, there was a streamer I was watching the other day and they were talking about sort of the phases of migrating over to TypeScript and that it’s not all or nothing and you can do it in sort of this. I’ll introduce this piece of it and then I’ll introduce this piece of it and then I’ll introduce this piece of it. And that’s awesome. And you can absolutely do that with code splitting. And so if you know you have these built-in wins, that’s a great way to get started and be like, “I know this thing is only used if you happen to hit this specific line of code, but we have to have it for this specific line of code.” Great, cool. Go in, add the import inside your code and make the whole thing a promise and then you can delete that top level and all of a sudden it’s automatically code split for you, which is the example in the blog post, by the way, if anyone goes and finds it. There’s a code snippet. You can steal that. Literally does just that.
[00:29:50] KD: I did want to ask. It was mentioned to me, there’s this thing called “SemVer” and it’s a tool that I use. Can you explain to me? I’ve never heard of it.
[00:29:59] LB: Okay. SemVer is a standard, but it is a standard that has been adopted by, for example, NPM. And so every time you install something for your project, you’re installing a dependency that someone has put up in a package repository, whether you’re using Yarn or NPM or whatever, it has a version number. Right? And we all know these. It’s like the 0.0.0. That’s the form that it takes. SemVer is the rules that package developers need to follow every time they bump those numbers up. So if you bump that last number up, you have literally just said, “I built a new version of this code. There’s some lines changed in it, but it’s implementation details. It’s not really going to affect you.” If you bumped that second number, then you’re probably adding some features. If you bumped the first number, which is when people talk about, “It’s V2, it’s V3, it’s V20,” you are introducing breaking changes and you can’t introduce breaking changes if you only bumped one of those smaller two numbers. It’s like breaking the code of SemVer or SemVer. It’s how I pronounce it. I’ve only ever seen it written. The reason this is really important is because in your package.json file, you have these extra characters. So if you look at your dependencies or your dev dependencies even, you see the keyword of the package and then the value is this version number. If you have a Tilde in front of it, it says, “If I run NPM install on this, I want you to download the version that I just pinned and increment the third number, the smallest number as high as it’ll go.” So like the latest, tiny upgrade bug bump. If you have a carrot, you want that second number. You’re saying, “I want to upgrade the minor releases every time I run NPM install.” There is no special character to do major release bumps automatically for you because most people would never want to do them because they introduce a breaking change, which is why this stuff is really important. Because if you introduce a breaking change outside of SemVer spec, then you’re going to break people’s sites because they have these automatic version increases set up so that every time they build their site, they get the latest and greatest, which is good. This is how we get bug fixes. This is how we address vulnerabilities. This is how we have small performance improvements, all of those things, but it requires that everyone sort of adhere and agree to this specification, both package authors and package users so that you know what you’re getting into.
[00:32:39] KD: Thank you. Thank you. No one explained that, like I use it. Thank you.
[00:32:44] LB: I have another DEV post on this. It’s called, “The Anatomy of package.json”.
[00:32:48] KD: Beautiful.
[00:32:48] LB: And it goes into the dependency section. It talks about SemVer. It talks about the different characters. There’s a bunch of different characters. You can have like a range of versions that you’re comfortable downloading. There’s a whole world, but there’s sort of a couple typical ones that are most commonly seen.
[00:33:05] BH: And as a consumer of some of these packages, this emphasizes the big no-no of using private APIs, which may technically be available to you. But the maintainer of this technology doesn’t think you’re using them. So feel free to change them as they feel like and call it a patch or a minor change. Whereas if you’re consuming a private API, your code could break when nobody else’s would.
[00:35:16] BH: Chances are, like other software developers, you learn better by doing than just watching. Unfortunately, most online learning platforms still have you passively sit through videos instead of actually getting your hands dirty. Educative.io is different. Their courses are interactive and hands-on with live coding environments inside your browser so you can practice as you go. They’re also text-based, meaning you can skim back and forth like a book to the parts you’re interested in. Step up your learning in 2021. Visit educative.io/devdiscuss today to get a free preview and 10% off of an annual subscription.
[00:35:52] A common scene in technology companies everywhere, big conference table with the CTO on one end, developer teams on the other, the showdown. We have an idea, “Will it get funded?” More companies are feeling the pressure to go faster and stay ahead of the competition. Projects that have long timelines or no immediate impact are hard to justify. DataStax is sponsoring a contest with real projects, real money, and real CTOs. If you have a Kubernetes project that needs a database, the winner will get funded with a free year of DataStax Astra. Follow the link in the podcast description to submit your project. It’s time to impress the CTO and get your project funded.
[00:36:36] BH: It must be challenging in the development of Gatsby to maintain a pace such that you’re giving people new things they care about while also maintaining all of these expectations. And that I would think that the pressure for Gatsby to not lose out to new things that maybe less sophisticated, but newer and don’t have legacy dependencies. I imagine since the company does this project and there must be a lot of strings pulling at you. Can you speak to some of that?
[00:37:11] LB: Yeah. I mean, it’s all a balancing act, right? So I will say we have a wonderful community. We’ve always had a wonderful community and they really help us when they see things that, one, we shouldn’t have done. Like when we make a breaking change in what we thought was a private API and it’s not, and they’re like, “Oh, hi! We were using this.” And we’re like, “Okay, cool, thanks. Appreciate it. We’ll roll that back or figure out a way around it.” And they’re also great when they find things that are broken and they’ll flag it or they’ll fix it, which is always wonderful. We love being open source in that way. Yeah. No, it is challenging because we have a lot to maintain. This official plugin ecosystem means all of these different integration and touch points that are relevant and that need to be maintained and need to be upgraded every time these things change. But I mean, that’s the nature of the job. Every job has their challenges and we do our best to try and make sure that we’re still pushing out new features and big, awesome things that people are going to love, but it takes a little bit more time when you’re dealing with things that you have to continue to support and you know that your users are relying on versus Greenfield programming. I mean, we all know this. If you have an empty file, you can create something potentially a lot faster than if you’re working within five different files that already exist and a bunch of integration points. And that’s what we deal with every day. And that’s cool. That’s great. We are happy to be at this point that we have a mature enough product with enough users where we have to worry about breaking those things. And yeah, sometimes it means that we have three cool features to release instead of ten new cool features to release. I mean, it’s probably like three versus five. Let’s be honest. But it means that we have done well by our users and we have a user base that is expecting those things from us. That’s super awesome at the end of the day.
[00:38:58] KD: I actually wanted to ask. In terms of you produce so many NPM packages, but while you’re developing, how do you make decisions around what you consume? Because obviously bundle size is important to you. What does that look like at Gatsby?
[00:39:11] LB: So we work in a monorepo. So all of our packages are in there. And every time we see if there’s something that we’re adding, that’s brand new to all of the packages. If it’s something that already exists in the giant yarn.lock that was being used in these other dependencies, we’re like, “Okay, this isn’t a big list.” It’s something that we’re using elsewhere. If we see something that’s new, that’s when we start making decisions. But honestly, we’ve done that a lot less lately. We pretty much know what our dependencies are. Sometimes we’ll be able to swap something out and say, “Hey, this is going to be smaller. This is going to be more performant.” We were doing a new CLI recently and we were like, “Oh, we think we’re going to use Enquirer instead of Ink,” for example, because it was something new. We got to make that choice. But at this point, unless it’s making an intentional change to move away from something, we sort of have our bases covered in terms of the dependencies that we require. It’s a lot of GraphQL stuff. It’s some image processing stuff. It’s a lot of small utility libraries. Lodash shows up there a few times. That’s actually the funny part. Most of the dependencies you look at in our different packages are other packages that we own. So it’s like we’re importing from our own APIs at this point.
[00:42:36] BH: Yeah.
[00:42:36] KD: Sure.
[00:42:37] LB: Okay. I want answers.
[00:43:05] LB: What? You don’t like the dollar sign? I talk about the dollar sign all the time as being like the worst symbol choice ever.
[00:43:11] KD: Please, one day, I will tell you about the framework I worked on that hijacked the dollar sign and used two dollar signs.
[00:43:18] LB: No, no. Oh my God! I can’t even imagine writing that parser right now. I’m going to cry. Okay. Go ahead.
[00:44:16] LB: Ben, you’re up.
[00:46:36] BH: Laurie, thank you so much for coming on the show.
[00:46:38] LB: I would never have guessed it was your first time, Katie. You did great.
[00:46:41] KD: Thank you. You were an excellent guest.
[00:46:43] LB: Well, I thank you. I had some mutual admiration for society.
[00:46:55] KD: Thank you all for listening. This show is produced and mixed by Levi Sharpe, editorial oversight by Peter Frank and Saron Yitbarek. Our theme song is by Slow Biz. If you have any questions or comments, email [email protected] and make sure to join our DevDiscuss Twitter chats on Tuesdays at 9:00 PM Eastern Standard Time, or if you want to start your own discussion, write a post on DEV using the #discuss. Please rate and subscribe to this show on Apple Podcasts.