Neehar Venugopal - A Beginner's Guide to Code Splitting Your React App - React Conf 2017

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
okay how you doing guys flew a long way to get here let me just scream this alright so we're here to talk about something really important code splitting hands up in the audience if you know what code splitting is alright that's a significant chunk of you how many of you do it with every app that you put out not so many of you so code splitting has always seemed before we jump into what it is has always seemed like something that's a bit historic something that you know let me just ship my web app and then six months down the line I'll think about it but I'm here to tell you that code splitting is actually really easy and the combination of modern tools modern infrastructure evergreen browsers and react itself make it really easy for us to do code splitting why should you code split so here's what we think as JavaScript developers we work on the fastest ISP known to man localhost 3000 and this is how we think we should buy JavaScript imagine each person is a JavaScript module everyone sitting really nicely together you're on a lovely little train which is your network connection but reality often ends up like this and it's just a giant mess of a lot of JavaScript right and every one of us was faced this before how do we tackle this and why are we trying to answer this question now I mean as Justin Trudeau said maybe it's 2017 it's about time we tackle this right and we live in a mobile-first world and what does that mean so these are stats that are pulled up from our own product and this isn't even a mobile majority it's overwhelmingly mobile first we're currently at 75% of our traffic coming from mobile and probably by the end of the year we're going to hit 80 85 % and this is back in India right a couple of years from now we're not even going to be talking about mobile first which is going to be talking about mobile only so it's about time that everyone gets on board a four coach realize that we live in a mobile-first world and as a consequence of living in a while first world we have evergreen browsers browsers that auto-update in the background because of which a lot of the really cool tech that's in terms of infrastructure that's happening like link pre-loading like HTTP 2 is already there for a majority of your users there's no reason for you to hold back saying that I'll do this later and most of all and this is what I want to stress on really in today's talk because it's easy here's how you do it this is how we ship our JavaScript we send the giant javascript file down everything looks easy peasy but there's a couple of problems with this the first is that a lot of our JavaScript doesn't change very often every time you update a single string somewhere and you ask the user to redownload all of your JavaScript you're asking them to redownload all of reactors will all of react Dom as well all of Redux as well all of react router as well but why should he there's no reason to so the first thing that you got to do if you're thinking about code splitting is think about long term caching take all the paths of your bundle which don't change that often which more often than not end up being third-party libraries or frameworks that you use and just keep them aside send two files down we no longer live in an HTTP one world where we have to worry about network connections and you have to wire that we need to send everything down in one go you can send two files down it's perfectly okay and your window file can be cached forever by forever I mean put a hash in the file name right as long as it doesn't change the user doesn't need to redownload it you change your components change your reducers change anything else he's not redownload agree act and that makes a huge difference in terms of the second time the user visits your site they're not going to have to redownload so much stuff cache it forever at the CDN level in the browser and you're good to go but how would we take this one step further and we say that application javascript that he was sending down what if we break that apart and this is where the real power power of code splitting comes in if I'm on the login screen imagine you're building a business dashboard I can't even see the dashboard till I'm logged in the way that most of us end up building it is I arrive on the login page but I already have all the JavaScript for the entire application even though I'm on the login page you don't even know if I'm actually a valid user you don't even know if I'll get to see the dashboard but you're asking me to pay the price of downloading that passing that and doing all of that work on a mobile phone which is five times slower than your desktop why so one of the easiest and most obvious things to do then if start splitting our application code itself send only the minimum amount of JavaScript required that's it whatever it takes to show the user what you want him to see on the current screen just send that down the wire how do we do this so for the first time in a really long time with es6 we finally have built-in modules there is no more a hundred different module systems and now we also have built-in asynchronous loading of modules it's a first-class citizen of the language itself so before this is what we do everyone I mean we've played around with systemjs we played around with require a lot of people invented their own ways of using modules and honestly this was a mess and now everyone's gotten on board des module trade we love this this is so easy everyone does this and now there's an extension that's recently been added to the language itself called dynamic input which is the last line over there and that loads modules asynchronously so it's currently in stage three which means that more or less all the key stakeholders have agreed on what it looks like and browsers are starting to implement how it works it's available today in web pack to all the other sort of module bundlers will also start having support for it it returns a promise because it's asynchronous in nature it can accept dynamic module names so you can pass it a template literal string and load something you know based on javascript that you execute and it's available today using that babel plugin this is not near future this is now you can use this right away here's a simple example of how that works we have two really simple modules a and B each do a simple console dot log and then the other index which loads asynchronously so it's bundled together but B is loaded asynchronously and in because it's a promise when that promise resolves we have access to the module right we run web pack on this I'm using webpack because that's that's the one which is support right now and shout out to the web pack team for having such an easy API we just run a simple web pack on it webpack spits out two files automatically that's it you have your main file which synchronously load stuff and that asynchronous file let the JavaScript that you were loading is created in a separate file you don't need to load all that JavaScript you just load the synchronous part of it in a script tag in your head but what happens when you actually load this in your browser since import isn't available or dynamic input isn't available in browsers yet web pack polyfills that and adds an asynchronous script tag to the head that's it it'll lazy load browsers will asynchronously load that it's not vendor blocking anymore as you can see you can look at the network waterfall it loaded later and you can look at the console you can look at the log to see both a and B were loaded and this is available right now it's really that easy right the first time I figured this out it blew my mind I was like oh my god right yeah teams am now coming to how we can use this in react so whatever I said right now is sort of more generic but the power of react where we're treating UI as a function of state and we're using functional programming paradigms lend to some pretty powerful things that you can do with code splitting so in react it sells components can be functions I mean we love our stateless functional components they can be classes which is our more surface right but they can't be promises not yet anyway with fiber that's definitely something that's on the horizon in fact I think there's a PR open adding support for promises as first-class citizens for components but today you can't do this and if you think about it Annie synchronously loaded component you'll want to add your own logic there as Sebastian said in is in a keynote yesterday the way you load it the loading steps are something that you want to define your user experience you know guy will tell you that this is how we do this right maybe you want to show a shell maybe you have a really fancy loading indicator maybe you do something like a slack where you display really happy message to someone but that's there's something that you want to do even before the component loads so you want to be in control of how do I load these components and what do I do when my component hasn't yet loaded and react because if it's state management makes it really easy for us to be able to do this let's take a look how so here's a really naive implementation of what a lazy loaded component will look like don't treat this as production ready but it will do the job we just treat the fact whether the module has loaded itself or not as state that's it because in react once you start feeling whatever once you start reading things as state and your UI is a function of that this lends itself to lazy loaded components really well when my lazy loaded component mounts it fetches the component that's associated with it sets it to state my render functions code which will either have a loader displayed when there's no when the component hasn't loaded yet or it actually shows the component that's it this is all you need to lazy node and react nothing else there's that there's a ton of edge cases that we might go through but at the core of it this is what it looks like and if you think about this this is a pattern that's really familiar to all of us why because it looks like how you would make an API call this is exactly what you do if you are a component that had a dependency on some data so on its a will mount or Deadman should make an API call fetch the data till then you show a loader loading components versus loading data is the same thing in JavaScript functions components are first-class citizens there is no difference and this is how you use it you create a simple functional component whenever that getcomponent is called yoga your lazy loaded component is loaded so what kind of patterns does this open up for us so a few things that we need to be aware of when you're using this with react you can use higher-order components to sort of decorate that this is a lazy loaded component pretty straightforward just like how you'd use it for data fetching you have to figure out caching which is you know so that you don't have jank in there you can cache it in a store just like how you do it data you can cache it as a static on the component itself you can write wrappers like lazy load children in parallel you can have independent components that say hey I'm lazy loaded hey I'm lazy loaded but for a better user experience you could wrap them all up in something that downloads all of them in parallel the thing is when you start thinking of lazy loaded components or components itself as data dependencies all these patterns start getting unlocked so effing modules are promises treat them how you would like any other data when resolved they return the component and then you can do whatever you want with the component now the next question that comes to mind is where should I code split so we know that we need to do it we know how to do it but where should I code split route level splitting this is probably the most intuitive one I mean everyone sort of gets it immediately it's almost always the best place to start but this only works with your route so very distinct from each other right it's also where you can have the maximum size reduction in your output bundle because if you have two views which are very distinct again I take the example of a login view and then your actual dashboard you know there's not a lot of code duplication going on over there they're very distinct from each other one loads all your fancy frameworks the other is just for some simple HTML form so you can have a lot of size reduction over there your router needs to be a sync aware with the cap if your router itself is not a sinker where it needs to expose the right kind of abstractions for you to be able to do this you need to be very careful of code duplication in your output we're going to talk a little bit of how to avoid that as well but if you have you know if you go crazy on the route level speeding and you say you know what my app has 20 routes or 20 different endpoints I'm going to go select all of them right and then you spit out a distinct file for each of those what you find out is you know a lot of them have a lot of code in common so you have to be very careful that is that you avoid the problem of code duplication and a lot of us end up structuring our reax apps in sort of here are our dumb components and here are our smart containers that know how to do this and what you find is when if you if you split a lot at the route level a lot of these components are reused across a lot of the runs so you end up adding code duplication where the same base set of components are there in every file seems to be very careful to make sure that doesn't happen so here's a really simple example right I have a login screen I have a filter screen I have a view screen there's very little in common between the three so this is an ideal use case for somewhere where you'd code split here's a simple example with reactor out of e3 the reason I'm using v3 and not v4 is because well when I was preparing the slide v4 wasn't out yet but and a lot of you how many of you are using react or outdoor v3 in production right now okay that's a huge chunk of you so changing the fact where you were synchronously passing a prop which is the component that needs to be matched changing that to use the get component callback instead is all you need to do to have asynchronous code splitting done at the route level right now that's it so even before you know if you're thinking about migrating to v4 how do I do this in we 3 itself this is the easiest way for you to switch and you can do this today with we four because it's become a lot more components itself with v4 it's a lot more simpler you can build your own abstractions you can build your own sort of custom logic on top to asynchronously load stuff so you split a top-level routes each async route gets spit out as a distinct output file which is why you need to be careful of goats leading and then whenever the route is matched you fetch the component parcel loaded and it's visible to your users but the real power of react right in a real part of the combination of react with code splitting is when you take code splitting to the component level right this is analogous to writing smart and dumb components you have your dumb components which is just UI or you have your smart components which do things like make API calls they're connected to your store so think about dumb components in the same manner as dumb components are displaying your UI they have smarter cousins that figure out when to lazy load them should I leave reload them right the lower down the component tree that you move the greater the flexibility that you get and the more the kind of patterns that you unlock with this and this is the part that I really want to stress on which I hope you take away from today is it enables useful conditional patterns and this is a really really powerful abstraction that you get with Reax model as well as code splitting which is you can conditionally load stuff let's take a look at some of the stuff that happens because of this so new buzzword alert I mean Tom tells me that this might become a buzzword but we've been experimenting with something called responsive components on inside of rotten and we doing it a fair amount so in today's day and age when you're building out something new this is sort of the methodology that we all follow you will do your mobile first design you will write your CSS mobile first but your JavaScript isn't really mobile first your JavaScript is still the same monolithic bundle that you run on your desktop and then ship to your users who are using it on a phone and we can change that imagine a very common use case like this right I mean everyone has seen something oh yeah this was pulled off our art production site where you have a hamburger icon that opens a menu bar on mobile the same thing on desktop gets pinned to the dog this is how it looks like right how do you model something like this in your component hierarchy right do you do one component with all the markup and then use CSS to mess around with that and say you know hang on let me do this do you do two components you call one mobile header ojs you call the other desktop header O'Jays and then on the client side you figure out you know which one to load but that leads to a subpar user experience right remember what we said we want to figure out how to do mobile first JavaScript so what we do instead is we always load the mobile javascript the mobile header and gracefully upgrade to the desktop one and how can we do this because we have lazy loading all right this is as simple as you loading a component that check something on the client side and then lazy loads another component and displays that that's it and then one of my favorite examples so when you're building this sort of square who's allowed and then I was trying to wrap my head around sort of how to get this working on desktop and mobile the designer and the team was just like why do you need JavaScript for this and then I took a step back in I realize actually hang on I don't how many of us have built Jerusalem our react apps which have used either our own carousing plugin or a third-party node module can I get a show of hands right and but the truth is if you're building a carousing on a mobile you don't need JavaScript it's just a horizontal div that overflows right why are you shipping JavaScript down to your 75% of your users which isn't going to be used but the same corrosion on desktop needs JavaScript you need to handle you know the clitty clicks on the arrows someone might be opening it on an ultrabook and they might have you know touch enabled so you need to figure out how to how to respond to touch events so you need to be really smart about that and build your components in a mobile-first way and then gracefully applied them to their desktop versions or to other feature-rich versions using lazy load this also applies to things like a be des to feature tests where you send something down the wire and then on the client you dynamically load other things and conditional imports are really easy right it's if you treat them just like how you would any other data it's just saying if this condition matches rendered this component which is lazy loaded otherwise rendered my default component that I shipped down the line right so there's a few gotchas that we need to be we need to be careful of when you are dealing with this the first is server-side rendering is really tricky with this the reason I say it's really tricky is because on this server you will end up synchronously requiring all of these dependencies right but the JavaScript that you'll be shipping down to your users will end up asynchronously loading it and what happens because react when it starts up eagerly attaches itself to the entire tree you end up getting this infamous elf right the the mismatch in markup error so you have to be really careful that you make sure that your server and client are always in sync when you are when you're lazy loading always profile on real devices this is really really important again as I said as developers we tend to test on the fastest ISP that we know test on real devices you know putting some sort of slowdown on your on your dev tools is still not good enough there's tons of great ways to do this happy to talk to you guys offline about how you can use analytics for example to figure out how much time at your actual users on mobile devices are taking to load all of this but all this profile on real devices avoid network waterfalls and this is actually really important you might get carried away with code splitting and say hang on I'm going to code split at the route level so my routes going to lazy load but my route itself loads five components three of which are lazy loaded and those components load something else which is again lazy loaded because every single developer in your team is like this is amazing I'm going to leave a note across the board and then you have this mess of a waterfall where it takes a really long time for your app to actually be interactive right so how do you avoid this by making sure you don't go crazy on the lazy loading the other is something known as resource optimizations that that browsers give you which is the link preload and the link prefetch tag which basically tells the browser that even before you've downloaded the first JavaScript which we know will make at some point of time lazy note the second JavaScript why don't you keep the second JavaScript downloaded and but with you just in case right and this is widely supported in most browsers today so you can give hints to the browser saying that my code while it's loading this might also load these other things so you might want to catch them and keep them ready and this can really help with waterfall issues now this is actually really really tricky and I'm actually not going to spend too much time talking on it but the key thing to note here is dynamic imports are always asynchronous as I said before dynamic imports return a promise and a promise by its nature will always resolve asynchronously so if you have a situation where you know if you are really smart about how you are prefetching or pre downloading or you are using HTTP server push and you have a lazy loaded component but it's already been sent down the wire the browser's already cached it it's there it's available you should be able to use it right away you can't because it's returned to you as a promise for at least one pic of the CPU cycle it's not going to be available to you this is a very fundamental issue I don't know the solution a lot of people have been thinking about it but this is one way where there's a lot of community effort that we need to do to figure out how to do this and lastly this is what I want to end on for all of you and this is the key takeaway that I think all of you should take away if you can write a component that makes an API call you can write a component that is lazy loaded it's that easy go ahead get started with it make your mobile users happy thank you [Applause]
Info
Channel: Facebook Developers
Views: 50,785
Rating: 4.927536 out of 5
Keywords: react conf 2017, code splitting, react, react native
Id: bb6RCrDaxhw
Channel Id: undefined
Length: 24min 1sec (1441 seconds)
Published: Thu Mar 16 2017
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.