Build Fast and Smooth Web Apps from Feature Phone to Desktop (Google I/O ’19)

oh right good morning thank you for showing up at 8:30 I am Mariko I'm from web developer ecosystem team within Chrome let's talk about building fast and smooth smooth web apps so it's safe to assume I think that all of us use Internet using computers touch device or your phone every day but what if I tell you that millions more people are accessing the Internet or coming to access the internet using device like this a feature phone so for those of you feel remember a days of feature phone you might remember typing the text on those keys I actually have it here I grew up in Japan where the first popular mobile web network was built and using feature phone to access the website and doing all of the emails and text was like my part of high school and college years so it feels City nostalgic to me but also I went into the industry after that so I remember the days building a website specifically for feature phone in Japanese we call agaric a site oh it's really hard it you needed you to subset of HTML or sometimes completely different markup language yeah so bad memories a little bit but don't worry these phones are new phones that's coming out to the market it's developed right now sold right now all over the world and it's not just me telling you that these phones or popular according to a counterpoint research 303 hundred and seventy million smart feature phones are expected to be sold between this year and 2021 so what is that smart feature phone right this is a new feature phone so smart feature phone means it has a new OS sometimes such as kayo s there is a few other OS to Cairo S is awesome because it's all web-based so you can build an app using web technologies it has a modern web-browser it's a little bit about virgins behind but it supports HTML CSS in JavaScript for those who develop the website for feature phones in Japan it's a great news and then it also comes with app ecosystem which means you can download Google Maps YouTube games on your phone just like you would do with your smartphone so software wise it feels like a smart phone but it comes in the sides of hardware so the screens are usually small I think most of the KY OS devices or QVGA screen size the navigation wise it does have Mouse shows up on the screen but you have to navigate it with your d-pad and if you want to input anything any text on the field you have to use the number key a and the t9 key input to do that so that part is a feature phone so what does it look like to browse the web today using these new feature phone here's a website you might have visited once or twice before Google com no it's great it looks great but we all agree that Google com the top phase it's just a bunch of links in one input field so huh that's not impressive let's see how it's like to build load a web apps right so here's a Skoosh it's a web apps using web assembly you can do image completions it's a PWA we build it last year for c.d.s how does it perform not great the CSS layout is completely off so the thing is when we build a Skoosh our team built it we wanted Skoosh to be the best in class web app so the first load is only 16 kilobyte it lost nearly fast even on this feature phone but we didn't need it quite tested on the screen sides this small we tested it on the desktop tablet and iPhones but we never thought of having somebody accessing the site using these phones news for the one of the depressing layout of the website is at i/o website not great not great it's so frustrating to navigate i/o so using this or oh it's almost unusable but not everything on the web is bad my favorite is Twitter so Twitter mobile I'm evaldo twitter.com when you access that on the smart feature phone you almost get the same exact value you get the same exact same experience you can tweet you can lead to it you can load video you can search for gifs you can like a touch image everything that's provided in the Twitter website available on the smart feature phone that brings me to the project that I'm going to discuss today so I briefly mentioned I am part of web developer ecosystem team in chrome and within that I'm in the small subset of the team that tried to build a real-world web applications that we can share so that we can share our learnings by building something new right so our first project what Skoosh it's a image compression application that completely built within a browser we use what was them to provide a new were file formats like web P for browsers that doesn't support web beat and you can select all of the knobs and like bunch of settings to see how much better the compression can be and you can download it and I'm upload it to your blog so that's the idea and then after we build this last November we got to discussing what should be the next project and we decided let's just build a game we wanted to build a game because whenever we asked web developers what is the way of really good ad everybody says it's a document and we wanted to say completely opposite of document to see if we can handle that so games seem like a good topic and developing a game came with a bunch of problems that we faced as a web developer everyday such as like how do we handle a lot of inputs coming from all of these UI or can we really provide a graphics heavy application on the web and on top of that because we were hearing that the feature phones are getting popular decided that our apt this year it's going to support everything from feature from the desktop and everything in between so I would like to explain what we built first and then we're gonna get into how we build it introducing procs proxy the game of proximity inspired by the legendary game a minesweeper game is situated in the space and your job is to find black hole you can play it works on any kind of devices from desktop to tablet to d-pad even with screen readers one dimmed button column 9 of 16 hidden button column 10 of 16 it is a PWA so you can download it and save it on your desktop or on your phone and play the game wherever you want even when you're offline so that's the game we built and you can access the app at the procs dot app that's the URL so let's discuss how we build procs so even before we go into the project we decided on the baseline like three of us got together Jake Sora and me and talked about like what is this app going to be three points we decided that every device will get a same core experience meaning we are not gonna build a three different apps for desktop tablet and feature phone we decided that it has to be accessible both on the input device so like all of the mouse keyboard touch and d-pad to support it and then we said why not make sure that the screen readers accessible to performance wise our team Nene likes to build a performant web app so we said it has to be really really good performance so we said our performance budget to be initial payload of less than twenty five kilobyte time to interactive less than five seconds on throw 3G network and animation should learn 60 frames per second whenever you can so let's with that understanding three of us got to working so let's let me explain how this app is laid out so the game started with a game logic file the jaicro on the way on the long-haul flight because he wanted to play a minesweeper but there was no internet on the flight and he wrote it he's that kind of engineer game logic just contains the logic there is no UI element to it it just of like how big of the field is where the mine is and with certain points are clicked how should it the deal that kind of thing on top of that we built a new iron state services so you I we use pre-act and State Services is a thin leper on top of game logic to communicate game logic and the UI service we also rotate our own landing pipeline and which we will get into later later so for y and we also have a little bit of utilities to goo it all together so simple issue you can understand all of this could learn in main thread everything in one file well it could be separated but it could learn in main thread however from the get-go we knew we wanted to do graphics heavy design we wanted to animate it and we were like not sure about this so we decided to move a game logic and state service into web worker so web worker those of you who are not familiar is a way to learn your JavaScript off the main thread and separate thread to communicate between worker and main thread you use API called post message and it's like not an enjoyable experience keeping track of the message passing it's it's a lot of work likely team members are my foods sitting there wrote a library called a comlink it's a sin leper or abstraction on top of post message to make using worker a lot more enjoyable in fact we improve the comlink by doing this project calling vfo so we were working on this project using comlink and testing it on the feature phone and realize that it's not really working great and the eyes data comm link has a processing in intensive work happening so we fixed that and comlink v4 was the East so if you're interested in doing our offloading all of the tasks to worker you should definitely check out connect UI wise we use pre-act we chose pre-act because hmm three of us use pre-act on the previous project and we liked it and and also it's still the smallest UI library out there that fits in a performance budget the app wise it is a standard single page application all of the custom elements are blended on one div and then appended into the body but we knew we have an aggressive goal of initial payload less than 25 kilobyte so we decided to do a kind of strategy where we will build time pre-render the first load the first interaction using a little hack using puppeteer so basically we have app and whenever we build our up we learn a puppeteer and puppeteer will download oh by the way puppeteer is a way to control a headrest Chrome from your script so puppeteer will open up the headrest Chrome do the thing store download app react react will just build a HTML or put it into the Dom and then we just grab whatever the output that was in there and put it into index.html and that's what gets uploaded to our static site hosting notify and then that gets served to the user as a first payload this is just showing you how easy it is to start with puppeteer you just started instance browser puppeteer at launch and then create a page go to that link evaluate that link and just put it into the HTML and that's all there to it so the basic architecture whites two key points we use Walker to flee app the main thread as much as possible because we knew going in we want to do gothic heavy thing main thread can only up the graphic stuff main thread only can only do like Walker cannot do the graphic stuff so free that app for graph and then we also plea lender at the build time for speedy loading of the initial bundle so that leads me to talk about graphics perhaps the biggest performance choice we made was to have our own graphic rendering pipeline so uh when you show up Ram was to completely use the Dom we were thinking oh yeah we can just have a table and then put a bunch of buttons in it and you know we can use the CSS animation like transform opacity that think that lands on the GPU to do the animations and that would be great right well it turns out we think that we might hit a Chrome browser bug where when we what when all of this was in the one layer and I want to update a just a single button chrome was the painting entire table which is not a great for performance well way to solve these problem if you see it is to put a buttons or some elements that you want to update in the separate layers using things like world change transform but we have a lot of buttons on the game because each of them ice the game cell it's going to be a layers and that might solve a painting problem but then it creates excessive amount of layers and that hooks up the memory so we are creating another problem so we're like hmm this louder is not good we should go for another loud so we decided to do our all of our graphics in canvas in fact we have two canvas or no screen one is for background animation and one is for each animation that is doing the game cell so these are generated and Leonard every frame 60 frames per second using requestanimationframe so if you're not familiar with the crystal means your frame browser requestanimationframe is a way to schedule your script and every tick the browser the flash is the black graphics so you put some kind of JavaScript in our case the drawing drawing call for the canvas and you put that in callback of the request animation frame and next stick that one at the next stick and if you're doing animation stuff you probably want to recursively call that so that you put that task into every frame and then this is how we update our animation if you were curious about all the stuff that I was talking about painting layers compositors CSS requestanimationframe I wrote a full part blog series about inside look at modern web browser that explains what happens when you down when your code gets the browser and how its executed so you should check that out and so we have to canvas now and there's a few other things that we did for the graphics for performance for example the background animation which we call it nebula animation in fact it's only a 1/5 of screen size so whatever device you have we only create a canvas size 1/5 of your device and just stretch it out to full screen we were lucky because the design the designer came up was already blurry image so clearing a small one and stretching it didn't make much and saved us a lot of memoria do that so the for the grid animation weekly we basically do a sprite animation and we generate these sprites on the client side so we do not send any image data down the wire to users we send the JavaScript to generate the sprite and then JavaScript creates the sprites and once that's done it's saved in index DB this way we can create the most optimal sprites for each of devices so different devices have a different device pixel ratio some of them have won some bottom two sometimes three so this way any device is accessing our site we don't need to create an image they can create an image or two sprites on the client side so that's graphics let's talk about accessibility which is exciting point that I I work so nice I'm really excited so as I explained the game is now into canvas and we can totally build the game just with campus a lot of games do you know whenever use abuse of mouse or clicks on you just get the coordinate of the mouse and then you write your own JavaScript to say hey did it hit the square underneath and then you just lead roll the animation but we decided we are going to keep a Dom that table and buttons remember that was throwing a painting Yeller so we just fixed that by putting in opacity zero there's a reason why we kept the dumb version on top of canvas because if we have an element we can focus on it or we can attach our event listeners so when you are playing the procs what you are seeing on screen is a canvas but but your javascript is interacting with is an invisible buttons and tables and this way we can tap into browsers native accessibility features so here's a screenshot of me playing a game with voiceover it is written down to what the voice whoever said it says hidden button column fifteen or sixteen hidden is a state of the button and that's the only part that we manipulated from our JavaScript by adding a Ilia label everything from button to column sixteen fifteen or sixteen kind of like suggesting users where the locations are that just came out of the box by using the table so when we clear the start a new game we generate a table right clear the table and in theory you should just add a low grid and the screen reader things should be all taken care but somehow maybe because we are displaying the table opacity:0 the browser wasn't quite legislate as a grid so inside when we create all of the lows and columns we also needed to specify that this TR element is a low and this TD element is grid so and that's all this problem but at the beginning we were like why is it not working the documentation said that if we put the grid it should work so that was a fun challenge to do code or foe and inside of each cell we generate a button that user click on it speaking of buttons we use a accessibility technique called tab loving tab index when we clear a button for each cell first top left corner of the cell gets tab index of 0 which means it's tab accessible when keyboard navigation user hits the tab the focus on that button but then everything else we set having the X of minus 1 which means it cannot access it cannot focus by having it this way the keyboard user doesn't have to tab hundred times to get to the end of the game so that they can get to the other menu button down at the bottom of the screen and when the key screen keyboard user access the game they focus on one cell and they switch to using an auto key and a low key will emit like which direction how many times that the focus should move so the cell focus method basically takes like okay current focus is here just gonna make it and on top of all or focus on focus of all and then the new button that will be focused it's going to be focus of all by putting the zero and then just set the focus let's set the focus and this is how we implemented loving tabindex I did not any I did not know any of this until I did this project embarrassingly we got a lot of help from Rob Dodson who is on our team who does a lot of accessibility work and he has a guide on web dev for accessibility to all which explains all of the techniques that I explained right now so you should definitely check that out and thank you very much Rob so this is a half way of the project and we were feeling great our animations were learning future phones game was working fine but then we notice you know I explained that they feature phone to desktop everything in between so we were testing iPad Android go phone which is a low and side of the Android phone and we were noticing that the game is clashing on Android golf on quite a lot we were like how like feature phones or the weakest powered phone enjoy Goa's should be upgrade why is it why is it crashing what turns out how many pixels are on the screen matters a lot so on the feature phones case they may have a weaker chips but they only need to care about a certain number of pixels to drive right on under the girl phone which is a smart phone with touchscreen with much bigger screen they might have a slightly powerful hardware but they have four times or more pixels to drive and that makes them sad and just shuts down some time so we decided that okay at this point we should just check if the hardware can support animation and if not just lender a static version so basically when the game allows we do a little bit of a check saying can this harder we're a support animation and if they can we load a WebGL animations and if not we support a canvas city static graphics studied graphic is something we need to make anyway for accessibility for those who prefers a reduced motion action so we just expose that to a little lower grade hardware phones – so this is just a our our applets – checking this might be a little naive but this is just one check shader box this class is just a class abstract on top of WebGL and we check a high precision vertex shader and if that's possible then we just learned animation and if not we go with a studio animations oh sorry 2d static Len during we we know it is a little naive but we found that the devices that supports high P usually can handle animations of course if user have a preference set for prefers reduce motion we check for the media query and then that becomes a default – let's talk about supporting different with devices because I've been kissing keyboard touchscreen deeper right so game has a two main functions click to open the cell and click to flag the cell when you are playing on the mouse it is just regular click and right-click if you are doing that on the keyboard then we assign a toggle button to the F key for the flag so you click on it and then you can go back and forth with the mode and then navigation wise so you use number key and enter I sorry the arrow key and enter for the phones and tap we went with just tapped and toggle method so you can see at the bottom we have a toggle button and every time a user wants to switch to that mode you just click on that toggle and you might be feeling looking at this play video of a phone saying like I want to pinch zoom in to see if how many cells are left right I want to do means out to see like how our game is doing and this is something we discussed while we were developing this and we actually needed to discuss whether to do it or not because we had this goal of the app has to be performant planning smoothly we had this debate about like yeah but if we support pink zoom then we lose native scroll and that means scroll gets slow and it's that ok so eventually we just decided that we for this app we are going to go with native scroll over pinch zoom so we're not supporting the pinch zoom yet maybe hopefully the thing about pinch zoom is that once you have the pinch zoom action then you lose the native scroll and you need to implement your own scroll physics right and that it's not gonna be comparable to comparable fast to the native scroll and on a web platform we don't have the way to tap into browsers scroll physics we would love to have them and we would love to explore the possibility but for now native scroll only which also gave I also wanted this interaction with a double tap to flag I was like why do I have to toko the mode can I just double tap and if like it and it was immediately shut down because of performance if you implement the tablet app that means we all have to wait for single tap to check it's a double tap is it double tap which means we create a few milliseconds delay for the user the interaction so based on the baseline that we agree that it has to be smooth we said no that what up possibilities or in the future hasn't implemented it long tap holding on the thing we can do that performant Lee this is just a question of a UX and design we don't know how to flatter notify the user that you hold it enough to flag it now you can take it off and you know the black hole is not gonna get revealed so once we figure out the design we might implement it which brings me to this phone that does not have any of it yeah I mean it has a click you can click the button but like there's no right click there's no touch screen there a toggle key for F F doesn't exist it's only number key so what are we – we yeah we added a custom key navigation to the number key so when you click on five the number go the sales focus goes up when you click on hit on zero goes down and then when you hit on eight it is a click action and then when you hit a hash find the the sharp side then that's the mode toggle so another thing we found was that we need to show users where the focus are it's very hard on these small screen to see which button are they about to click they also have a mouse indicator or two but it's sometimes you can't really see like it's this mouse pointing to the one button or the other button so we made sure that we highlight the focus and tell the user this highlighted element will be open once you click on it another thing we added which my favorite is a key shortcut guide so if you access our game on the feature phone then you will see these tiny icon indicating you can click on the hash button to start the game or you can click on asterisk button to open the informations this is piece of UX that I took from a 2000 mobile development in Japan so the Japan had a feature phone web network and when you go to a long document site or something they usually have a table of contents on top and then the in page link inside and those are usually map to number keys so you will have a number emoji right next to the table of contents indicating oh if you want to go to chapter 3 just click on 3 and then you can just move down so I took that UX and then put it into this game another thing that's really important if you're designing a website or with game for feature phone it's to have a way for user to get away from that view so I have a close button there whenever user opens the settings model which is quite a long because it also contains how to play the game and Scrolls down whenever they think oh ok I got it they can just tap up though press on the asterisk key and in just close that model if we didn't do this UX and have the standard design that we have for the smartphone and desktop and all which is a floating X button this happens in the middle of the page user have to scroll up up up up up hit the top and finally the mouse can move to that close button to close it and this is really frustrating so the element itself the floating X button and the close button at the bottom is the same element but depending on the device if its feature form or not I just changed the CSS to put the location differently so that's the feature from designs let's talk about a fine strategy as I talked about this game is a PWA it used serviceworker to cache all of the resources so even if you're fine you can play the game and whenever you do offline there's always question of how do we update the game if there's a new update is there we might have seen these Mauro saying like hey update is available little this app or dismisses and then use the old version this is directly took from the previous project that we did but in this case we did not want to block the users of wanting to play the game or playing the game right now so we hit this logic inside of this page this button to be exact so whenever user comes to the app and hit start and whenever there is a network they make a call to hey is there updated and if there is update then it starts fetching down the new version and once that's done it Lowe's a new version of app skip the opening screen because we already know the how the game settings for it and launch it into game directly so when user sees this page the game is already updated to new versions and this is how we do the offline and versioning lastly I want to talk about resource loading so after all of this WebGL and feature phones and all of that our total packet became a hundred kill by gzipped we feel quite good about this site and out of 100 kilobyte gzipped packet twenty kilobyte is a first payload so we hit the goal of under 25 kilobyte D zipped first payload basically this is just an index.html that gets sense when the first request goes in which means this index.html contains this page I like actually this page so all of the animations and the opening title role that we hunter crafted with CSS animations or lazy loaded so this is the minimal set of features and the buttons that user need to start interacting the first action the first action could be starting the game first action could be opening the information icon clicking the information icon to open the settings or clicking the fullscreen button to go into the full screen mode so we even subset the font so we look at all of the glyphs that's used on this page subset the font and inline it into the index.html so nearly our index.html is the twenty kilobyte of data that kind of look like this yeah all of a lot of inlining but once that gets to the users and users start interacting then little by little chunk so download at least lazy loaded and then game fully interactive for doing this we used all up we really loved and enjoyed using dollop we even wrote our own plugins for things that load up didn't really provide out of the box but we even felt comfortable doing that and kind of mixing and matching it which was not the case on the previous project that we used a different building process and Lola worked really great for our setup using Walker's so as I mentioned our codes are separated into the worker and main thread and commlink is a shared dependency to communicate each other if you do this in web pack then webpack creates a two different chunks of the dependency and you know separated it and that's just duplicating it but load up out of the box just keep it as a one chunk and then share that as a dependency for worker and the main thread so this was out of the box great feeling for a project for module loading because JavaScript modules are not supported in web workers we used AMD and Soma wrote a a tiny pregnant called Lola plugin Lee loader which is a AMD like loader that is Leedy tiny specifically made for all app output so you might want to check that out but that's part of our build process and even doing that tools cannot be the help the fine tuning of shipping down the data we needed to go in and look at our index.html and what gets loaded and then see why is our indexing getting bigger and bigger and bigger so if you wanna check what kind of refactoring we did there's an epic PR up on the github code I need stuff smaller by Jake and things that he did or things he discovered was things like this so our game screen has a element called top bar that has a you know the number of cells that's open the timer counter all of that but those are only for game time right whenever the game is not learning like opening screen or win screen it's only just a title banner but when we are loading the index dot HTML which only need title banner they also load the logic of timers and logic of the open count and everything so we separate that element into top bar the full on version and top bar simple and just load it two differently and those shot some data so this is great if somebody have a time to go in and dig through and every now and then check if we're doing great but we try to keep reminding our self that every P for the quest that we make be conscious about the sides so every poll request we make on our Lippo we run a little script called Travis size report on a Travis CI to just check what changed it is says this file name changed or this file size changed and you know this screenshot isn't you know particularly interesting nothing really changed but sometimes you find an unexpected change like oh why did this file name changed or why did this file were suddenly this big so this was a good reminder so that's the process we took I would like to end with the three learnings that we had I definitely think that having a set baseline for the project was great we started with the story the project with understanding of what's important to us for this project and how we make decisions and that get got us you know showing up to the stand up saying hey I want to implement double top and immediately Jake says no you can do it's not performant and I'm like I wouldn't be offended or not feel like defending because I was just going oh that's right performance was an important thing for this project another thing we think the worker is a crucial for learning a smooth application we need to learn JavaScript off of the main set as much as possible I don't think we could make this game possible on the future phone if we didn't do the worker lastly if you're feeling like I'm not game developer I'm not gonna do the game on the web one thing you can take away from this talk is just study what's on the first instruction for your website or your web applications and just remove everything you don't need that makes your first load data small and an user can get to your service quicker so if you want to check out the app here's the link for the game all of us source code are open sourced on the github so you should check that out future Lee Quest or bug fix yourself very much welcome and if you have any questions or want to play them a game on the big touchscreen all of us will be at the sandbox tent a after this thank you very much [Music]

As found on YouTube