The Challenges and Pitfalls of Server Side Rendering

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
everybody welcome to our glf my name is Dan and today we'll be speaking about the challenges and the pitfalls of successfully implementing server-side rendering also known as SSR in your web project another way to put it is this is all the things I wish we knew when we implemented SSR at Wix as a solution for all the websites hosted on our platform indeed to a great extent this talk is the result of all the things that we encountered all the problems that we had to overcome while implementing server-side rendering at works so Bruce already mentioned my name is Dan Dan Shapiro I've been with Wix for five years more or less my role at Wix is a performance tech lead which indeed means that it's my responsibility to make sure that sites hosted on the Wix platform perform as quickly as possible load quickly in response to user interaction and indeed there are over a hundred million websites on our platform which makes it a not insignificant portion of the web so I really like to think that I can you know help make the web a better place at least in terms of performance okay then so you know when you've been in with high tech for as long as I've been doing software for so many years you see that technology is kind of like fashion in the sense that what goes around comes around and technologies that we used to have then kind of fade away and then kind of make a comeback so when I started doing web development essentially all the web of all dynamic web pages were rendered on the server side you know a multi-page applications or MPAs so you had technologies like a PHP or JSP or ASP all these three-letter acronyms that all end in P for some reason and then along came single page applications and then suddenly we were doing the rendering on the client side we had frameworks like amber and backbone and angular and the webpage that was downloaded from the server actually became essentially like an empty page it literally had nothing except maybe some you know the title and then reference to some JavaScript and then it performs some Ajax operation and all the Dom all the HTML was essentially constructed on the client-side and it made it possible to create really dynamic experiences that we came to know a single-page applications or s paas but now it seems that we are kind of coming back to this approach of rendering at least the first page on the server side and it's not exactly the same as rendering on the server which is why it has this new name as a SAR server-side rendering but there are a couple of important differences and distinctions between server-side rendering and as a rendering on the server and SSR so one important difference is this whole concept with this terrible name called isomorphic JavaScript where we are essentially using the same code written in JavaScript or compiled into JavaScript both on the server side and on the client side so we might be running that code inside on the node server on the server and then also running that same code on the client and the way that it works is that the server code essentially generates the HTML for that first page delivers it to the client and then when the client actually runs the same essential JavaScript code what happens is this concept of called hydration where thanks to technologies like virtual Dom the client is able to instead of rebuilding the HTML from scratch effectively just hooks up event handlers into this already pre-existing HTML so you get the the look and feel you could say or the display from the server and you get the functionality or interactivity from the same code running on the client and then from that point on as you navigate through additional pages on the client side then those pages are essentially client-side rendered like the you like you would do in any normal single page application now what are the benefits of this approach so there are some benefits that I didn't mention stuff having to do with things like it's a bit better for SEO even though search engines are getting to be really good about being able to process client-side JavaScript as well and it's also beneficial in case for some reason javascript is disabled on in the browser which can happen but in most cases the benefit actually has to do with performance and there are several reasons why performance with SSR especially as it relates to time to visible can be significantly better than the performance with just client-side rendering I won't go over this entire list because this is not the focus of the talk but just to mention a few so a first obvious one is the fact that you need to do to have fewer round trips in order to get the visible content with client-side rendering you download the HTML and then JavaScript and then some you do some Ajax or something so it's at least two or three round trips whereas with server start rendering it's just that HTML that arrives another benefit might be that your servers can be just bigger and faster with more memory than the client device especially if the client device as is most common these days is a mobile device it might be a really low end phone and other reasons as well okay then what's the impact so it works when we actually implemented server-side rendering for all the websites hosted on the works platform the performance gain was really significant in fact of all the actions that we took everything that we've done in order to improve performance over the past four or five years this has been the most significant change as you can see improve performance by something like sixty percent or another way to look at it is that what used to be the performance that only that was the median is now it now it's what we get with the 90th percentile and the performance that previously only the 10% of the users with the fastest connections and devices used to get now it's what half our users are getting so the performance improvement was indeed dramatic and we were very very pleased with that but it turned out that it wasn't really that easy oh yeah but before that one more thing another really useful thing about SSR is that now it's really supported by essentially all the main plots all the main frameworks so whether you're using react react was kind of the lead kind of innovated that but right now it's supported in view it's supported in angular it's even supported in amber and I'm sure that it's supported in other frameworks as well so whatever framework you're using you're basically kind of getting this functionality so in other words what not what's not to like you've got it a support built in in the framework the performance gain will be huge I mean you know we should all be doing SSR well it turns out that it was definitely not that easy in fact when I joined Wix 5 years ago one of the first things we were already then looking at as a star and it only took us over three years to actually succeed and like this boxer that has two black eyes it actually took us two failed attempts before we were actually finally able to succeed with the third trial and even that successful implementation took us more time requiring more resources than English initially anticipated when I'm thinking about the reasons of why SSR turned out to be such a challenge to implement the I like to group the challenges into two main categories the first one is our technical challenges if all of you are well some of you're familiar with the excellent article no silver bullet which I highly recommend just going out there and googling or you can find the link here in my presentation this is the concept that is often known as accidental complexity it's the fact that there are challenges or problems or limitations that we can overcome but it requires work and it requires using the best and the most appropriate tools then there are also the inherent challenges these are problems that are kind of built into the problem domain that you can't really eliminate they're there you can try to mitigate them reduce their impact but it's a challenge that you have to face and this is often known as essential complexity in the context of that article that I mentioned so let's start with the technical challenges and I'll just go through a couple of them not all of them domain ones um you know so we were as I was saying you know you're probably going to be implementing SSR using some sort of a framework but and I'm sure all of you are most of you are already using a framework in your divert in your web project regardless of whether you're using SSR or not but and it would seem that if you're using a framework that you should be accessing the browser Dom directly but the reality is that we all know that we all do it even though we're using some sort of a framework somewhere in our code there's a window dot something and if it's not direct use of the dome then it's probably something like jQuery and there there are legitimate reasons for that first of all obviously not all the browser Dom API is exposed by most frameworks so if I want to use some functionality that's not really part of the framework I need to access the Dom also sometimes even with the best frameworks it's just makes sense to circumvent the framework in certain cases special cases that we all seem to encounter in our applications and finally some of us are just lazy and you say okay we'll just do an inner tech innerhtml or something and and and you know it just works but this is a problem with with server-side rendering is that obviously while you can definitely use the browser Dom in the browser you can't use the browser Dom on the server because it just doesn't exist if you try to do window dot something on the server and node it will explode you could put something like JS Dom but obviously that's not such a good idea because anything you do will not actually get reflected down to the client so you really want to not use the browser Dom in your code when you're using when you're doing SSR so what can you do about it well the obvious thing is to basically eliminate it go over your code find references to window dot anything and just put pull them out but the reality is as I said before is that in some cases it's unavoidable and in those cases you probably want to you what you will need to do is you will need to safeguard that access using something like type of window different than from undefined you'll probably want to wrap all those Dom accesses in some sort of a helper library that does these tests and checks to make sure that your application doesn't explode on this when running on the server let's consider another challenge this one is kind of more insidious because it's not an issue because the previous one was kind of obvious you know you know you don't have a Dom on the server this one is more tricky and that's the concept of the JavaScript context when we running JavaScript in the browser the browser creates essentially a new instance whenever the page a new page is loaded and when you navigate away or close the tab the browser basically does a cleanup for you even if you just do an f5 to reload the page that's a whole new clean context and what do I mean by clean it means that all the memory all the objects that you've allocated in memory they're clean the way they're removed and if you modified various and Global's on the windows object those are gone so information from one session doesn't leak or make its way into another session but that's not the case when you when you're running on the server side because well obviously you could do something like shutting down the node server after each session and then starting it up again PHP kind of did something similar or does something similar between sessions but you know that's not the way you work you know you you basically want to reuse the same node session instance between between different sessions coming in over the network and that means that the same global variables for example will get continued to exist so if you have let's say a global variable that contains some sort of a mutable value that the session can actually write into that global variable then that value will actually the modified value will persist into the next session and obviously this can introduce all sorts of security concerns privacy concerns or just plain old bugs because you assume let's say that the certain counter is initialized to 0 but you end up with whatever it was at the end of the previous session and this could happen certainly when you're running multiple sessions at the same time but it can happen even happen when you're writing running multiple sessions sequentially within the same node session so it means that global variables in fact and and it's not just global as you know variables defined in a global scope it might be properties on the global object it might be module level global variables all these if they are mutable are not something that you can really use inside a server-side rendering solution so what can you do about it well an obvious solution is to basically just not allow mutable Global's but that's obviously much easier said than done because at the end of the day our applications tend to have state and state does change over time so one approach that we found to be fairly useful is to basically replace what will be simple mutable Global's with weak maps that we would keep based on a unique session ID so every and the great thing about weak map in this context is that once that session is done then the garbage collector is actually free to collect all that memory and you don't have to go explicitly through all these Global's and release the memory you know let me ask you a question it's kind of a rhetorical question if your applications say leaks 10 kilobytes per second is that a lot is that a little well is it is it a problem is it something that you have to solve well it turns out that for the client-side you could probably ignore that because if a session let's say lasts around five minutes in your case then you've talked about a leak that accumulates to around three megabytes which is at the end of the day something that we can probably live with but in the server side if a server is running continuously for 24 hours that adds up to almost 1 gigabyte of memory and that's not something that we can live with so that ends up in us in a scenario where you know you kind of have to restart your node servers every several hours because they are just running out of memory and potentially blowing up or starting or performance really degrades so problems like that that used to be non issues in client-side become real issues in the server side and and this is kind of a mental challenge because with client-side you know if you deploy your application and it seems to be running well after the deployment in production and you have enough users that actually play with it and you see no problem let's say an hour then you know you're probably safe but with service start rendering you're you're getting into this DevOps world where you can get a phone call on a Friday night at 3:00 a.m. that the server has blown up because it's it's leaking resources so that's definitely something to watch out for so in coming to grips with all these technical challenges we really had to consider the processes that we use and the tools that we use and some of the tools are one of the main tools one of the most significant differences that that made the difference between the successful as a SAR project and the ones that failed was that we went through a test first approach in our case we had a client-side rendering solution we wrote a ton of tests that passed for that client-side rendering solution and then we made sure that when we went with SSR all that whatever change we made all these tests continue to pass so if there's one key takeaway from here is write a ton of tests and and just make sure that they keep on passing turns out that if Flint was a very powerful tool or utility in our belt for successfully implementing server-side rendering for those of you are not familiar with it yes lint is as a linter tool that verifies that you're coding your java script according to particular standards and what's really cool about is lint is that it's extensible so you can add your own rules in our case for example we added rules that checked for unguarded Dom access or we added tools rules that checked for the use of mutable Global's and actually failed the build when when there was such code in being pushed into production this made it sure that once we fix the code in order to work successfully developers could not accidentally check in code that would cause problem in an SSR environment for memory leaks it turns out that we basically just had to learn more and understand the various nodejs tools that are out there stuff like node inspector and all and the various libraries and and tools that you can use there's no getting around that if you're going to be running your software on node you need to have people with no expertise on your team okay then so all of these problems were technical challenges now let's consider some of the problems that are inherent to the very approach of server-side rendering so with client-side rendering the time to visible and the time to our interactive are essentially one in the same that is you get a blank the blank HTML page you run the JavaScript code it generates that a to the HTML the Dom and it's incidentally visible and interactive meaning that if there's a button you can click a button if there's a menu you can select a menu item and so forth that's not the case with SSR with SSR these two become distinct SSR really improves the time to visible because you get that HTML with all the visible elements really really quickly but it turns out the time to interactivity at best stays the same in fact from what we've seen in most cases you actually even experience some degradation so it creates this scenario where you have a visible user interface but it's either non interactive or the best partially interactive and I recently saw presentation in which they mentioned that Akamai did the research that shows that if time to interactivity is more than 30 percent longer than the time to visible that induces range clicking which means that if there are buttons people actually start because they're annoyed that nothing responds to their interaction in other words what you get here is not so much a performance issue anymore it's it's actually it's it's you could consider it to be a bug a bug in the software you have a user interface that the user is trying to interact with and it doesn't actually work now this is an inherent problem because it's it's just a fact of life this is what SSR does it improves visibility it doesn't improve interactivity so what can we do about it we can try to mitigate it that is reduce the impact of it so one approach for example let's say you're using react in order to render your user interface you don't have to put all your react rendering under one node you can actually break it up and do rendering under multiple routes so for example you could split your page so that all the part that's above the fold maybe going a little bit below the fold is rent is rendered with one route and the rest is rendered with another and then you can do like sort of this sort of hydration in parts so you first hydrate the upper part and then you hydrate the rest and you can and with react now also hydration can be interrupted so if then somebody tries to interact with the part that's above the fold that will be already responsive while you're still hydrating whatever is exists below the fold but again this does not eliminate the problem it only mitigates it because for example if somebody Scrolls down or even just loads the page when they already scroll down they will try to interact with components that are at the bottom and it they will be frustrated you know another benefit is that in most cases people don't start clicking right away because people tend to look at the page before they start interacting with it but still again if if you're interactivity takes too long then you definitely have a problem another intrinsic problem is the problem of diverges diverges what happens when the HTML that's generated on the server side is different either partially or completely from the HTML that that was that is going to be generated on the client-side so it turns out that the hydration process instead of just hooking in the interactivity actually has to replace some of the stuff that was previously rendered on the server now there are actually two reasons why this might happen one is let's call it unjustified diverges you can think about them as bugs for some reason the code running on the server is generating slightly different HTML than the code that's running on a client maybe it's a timing thing maybe it's the version of some library you're using maybe it's just the fact that it's an old environment rather than the particular browser that that is being used the way to work around that is we built basically built-in tests that do comparison of the HTML that is generally received from the server where the HTML that exists on the client after the client finishes the hydration process if the two aren't sufficiently I equivalent then that is flagged as a bug and it breaks the build so that's the way to deal with unjustified diverges but they are also justified diverges think for example that your page has let's say the timing date at at the top left-hand corner of the screen and your server happens to be in a different time zone than your client then time will obviously be different maybe even the date will be different but even if that doesn't happen time will pretty much certainly be different when it's rendered on the client and on the server so that's a diverged that's not caused by so much as a coding problem it's basically an unavoidable result of the design of your webpage so in that case what can you do the best way is to basically try to design your page in such a way that these kind of diverges don't occur and if they're unavoidable then what we've seen is that a better user experience is to generally put in some sort of a placeholder rather than putting in a wrong value and then replacing it with the right value after a bit it's kind of disconcerting to see something like a flash all of a sudden with a different value so it could be like a spinner maybe or even a blank area with no content and that content is then later filled in when the client does its own work so to summarize what we've talked about so far as we've seen SSR can achieve a dramatic improvement in the performance that your users experience when they're visiting your website I think you can all agree can all agree that the 60 percent improvement in time to visible is is very very significant but on the other hand it does have its issues it's not a trivial undertaking it's it's not something that you can say okay I'll I'm using react I'm using view I'll just fire up a couple of note servers and I'm done as I said before test test and test again again if there's one takeaway that you need to either you should take from back from this talk you know testing is always a good approach we will have talks later about testing in this in in YGL F but in this context if you want to have a successful as a SAR project that's what made the difference for us that it was a test first approach at building this project second make sure to allocate sufficient resources in time for it again another difference between our successful projects and the ones that failed is the fact that after having failed we looked at why we felt a hey we didn't allocate enough people we didn't give them enough time let's let's do it right you actually setup at a fairly large team that actually worked specifically on this project and we gave them all the time that they needed and they actually needed more time than was initially given to them and remember that it's inherent problem of this approach that time too visible is going to be smaller than your time too interactive and you're going to have to face up to that and and start your project and and implement your project in such a way that your that visitors to your site don't consider it to be a bug because your site simply is not responsive to their interactions and essentially that's what thank you very much [Applause]
Info
Channel: Coding Tech
Views: 13,426
Rating: 4.826087 out of 5
Keywords: page load time, server side rendering, page performance, web sites
Id: sNpX8LLUgHo
Channel Id: undefined
Length: 29min 38sec (1778 seconds)
Published: Thu Aug 22 2019
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.