[Applause]
we are anxiously waiting I mean oh the
other way it's giveaway it's always the
other way right yeah we good I think
we're good press press the have to think
right okay okay oh the full screen yeah
yeah yeah
f4 full screen there we go yeah oh okay
right ah so earlier this year a few of
us went on a fact-finding mission to
India to see how folks use the in turn
out there and one thing stood out to us
and that is that feature phones are back
yeah the future phone market doubled in
2018 in India and the sale of
smartphones by kind of flattened out and
at the current rate to this projected
that 400 million feature phones will be
sold in India this year alone yes and
the one on the right over there the very
far end that is a geophone which is the
most popular brand and it costs just 15
pounds and I compared to all the phones
you all have here everything about all
of these phones is extremely it's
240 pixels wide it's single pixel
density there is no touchscreen and the
CPU is god-awful
but it's 15 quid and that allows people
to be on the internet that previously
couldn't afford to be there yes and also
the geophone on the end there this is a
web-based phone that is running Kai OS
which is a fork of the old Firefox OS so
this phone is kind of is running Firefox
42 for pretty much everything so a
little team of us got together
consisting of Surma Jake and Mary Coe
she's in America Mike Mike is in America
America is that way
if you actually think it's quicker to go
that way that way yeah either way if you
just keep your phone so yeah what we
wanted to see if it could we build an
interactive web experience that would
run on devices like this but you know
with responsive design and progressive
enhancement and enabling it to also
scale up to something that looks
on a desktop yes and that thing became
procs it is a game if you like
minesweeper you will like procs because
it's the same play it now on proxy a p--
so here's on desktop and as you can tell
like we through all the animations at it
and like make it fancy but keep in mind
this entire thing scales down nicely and
is playable on one of these 15 quid
feature phones with the exact same code
base yeah so we put a lot of effort into
making it run really fast so we figured
we'd go through some of the tricks and
techniques that we use because none of
its really unique to this particular web
app it's stuff that you can apply to any
site or all right but before we dive in
I think it's important that we address a
question that we still often see on
Twitter yes should I care about
performance should I care about
performance I'll go to article 4 this is
this one on web fundamentals there by
Jeremy Jeremy where are you where is it
he's actually here is he here he's
supposed to be here the guy said to me
last night really looking forward to
your talk Jake where are you man it's
just rude fine
well okay well if you want to read
Jeremy's article whatever you can find
it at this bitly link it's like your
points to all these web performance
studies carried out by a variety of
companies such as Pinterest who reduced
their perceived wait times by 40% and so
on increase by 15% in signups or cookie
reduced a load time by under 50
milliseconds and saw an increase in
conversions on session time or the BBC
velocity initial times of users and
everything that's how they paid it to
load or also anything huge is playful
time by half and some boost in sales
well no but responded by 250 seconds
terms ignition supply right although
that's a large variety of sites like
we'd still see folks saying like mmm
this yeah it's all very interesting but
it doesn't apply to my sites because
like my site is somehow different yeah
they sound like one aspect in the study
that they feel like their own site
doesn't match too and therefore the
entire evidence provided is invalid we
don't buy that now I think everyone in
this room right is a you
of software we know how frustrating it
is when something performs badly and low
time is just such a big part that the
performance optimizations if you're
going to talk about in this talk are
pretty simple dead easy literally two
minutes on paper but when you've got a
build system wrapped around your project
as most of us do just adding something
like a tag to a page can become like a
real pain so we're going to take a look
at that side of things as well so let's
rewind to the first alpha version of
trucks before we had done any of our
performance work yes this is totally the
real alpha version not a version we just
retrofitted for the sake of the shut up
you're ruining the illusion I'm sorry so
aside from being a bit slow it wasn't
really all that different from your
average everyday JavaScript driven app
yeah so HTML was pretty basic right it
content a little bit of metadata
JavaScript file that took care of
populating the page we've got a style
sheet there that star sheet is just for
a web font the rest of our CSS was
embedded in our JavaScript via post CSS
the notable difference from most web
apps I think is that we used pre-act
instead of react react is 33k pre-act is
3k react can do much more but none of
the things that it can do more we
actually needed so for us was really
like a no-brainer to be able to save 30k
it's straight out the start yes
absolutely any other difference is we
used roll-up basically because we wanted
to give it a try like we'd use roll-up
in before for like libraries and stuff
but but not for full web apps so if the
last year we build a web app called
sploosh and to build swoosh we used web
hack and when I say we I really mean our
colleague Jason handle the back side of
things and he basically had to make use
of lots of undocumented and internal web
pack api's just to achieve basic stuff
and he has years of web pack experiences
really comfortable with it the two of us
on the other hand don't yes so as a
result like we didn't understand the
project build system if something went
wrong that was non-trivial which most of
it was non-trivial
we were kind of helpless until Jason
woke up on the other side of the
and talking to some other teams
internally and exhale we hear similar
stories there's like one or two people
who are considered the webpack
whisperers on the team it's their sole
job to like maintain the built system
and nobody else actually really dares to
touch it and maybe this sounds too
familiar to some of the people here in
the room yes so when I use webpack I
don't feel like I'm using JavaScript I
feel like I'm switching like pulling
levers switching switches and I get
massive config objects like and herding
lots of plugins around a varying quality
that often don't really play well
together yeah and so we tried roll up
and we found lots of plugins of varying
quality that don't really play well
together but the big difference is mere
mortals can write their own plugins roll
up has this simple well-documented
plug-in system so it's easy to get
involved in the innards of the build now
if you know enough JavaScript to wrangle
a web pack config you know more than
enough to write a rollup plug-in and we
knew we were going to do unusual stuff
if it was clear to us and on these super
low end feature phones it's gonna be
hard to have everything on the main
thread so we wanted to make workers core
part of our architecture straight from
the start
yes and there's you know the problem is
that we now have multiple threads and
the problem is that there's often shared
dependencies between these multiple
plant fats so to solve that we use
common link and that facilitates the
communication between workers the main
thread library that you wrote but that
means that library needs to appear you
know on all of the workers and on the
main thread now web pack can't share
chunks between workers and the main
thread so news would end up downloading
it well at least twice once for every
worker plus one and this would happen
for each additional shared dependency
and the roll-up kind of handles this for
free out of the box because at least the
choice of format up to you yeah it
wasn't just JavaScript needed handle
either because you know we needed HTML
as well and there is what plugin for you
to create HTML for your project but here
is the code for that plugin and its
massive and again it relies on loads of
internal and undocumented parts of web
pack yeah this booking is so big it has
its own plug-in ecosystem as well and
it's kind of the way it works it doesn't
really want you touching the HTML itself
instead it wants you to learn the
configuration options and
you know all of that and learn all of
their quirks as well like it turns out
that your skills in HTML which I imagine
even many of us already have they are
completely useless when you're using
this plugin so we try to find the
equivalent plugin for roll-up and
couldn't find one to make us comparison
fair so we decided to write our own so
roller plugins are just functions that
return objects and that object has a
name key just so that your plugin can
have a name and Rob can generate nice
error messages and debug messages and
the rest of his object are just
callbacks for the various stages of the
build and these are all very
well-documented yeah so the one we're
gonna use for this one so we're gonna
use the generate bundle hook and this is
called just before it writes everything
to disk you get the options that roll-up
was called with there and you also get
this bundle object which looks like this
this tells you everything about the the
build you know so so as for the
JavaScript files for example you get the
initial path the path the source file
you get the output filename which has
been hashed for long paths which are
caching and but it also loads of other
data like dependencies and which exports
it has and JavaScript files you do get a
subset of this kind of information did I
go too fast through my bit and not keep
time to open the bottle I'm sorry is
that the fizzy water or the still water
I feel very strongly about this stuff
which will that still okay right yes so
this is the whole build config tells us
everything about what's going on inside
roll ups little world but we can use
this to create our HTML so what we're
going to do is we're going to load an
ejs templates and compile it and now you
know we're just using a GS as an example
well it's the one we use but you can use
any templating language you want like
roll up doesn't care all we all it cares
about is it wants to know about this
HTML and it wants to know where to write
it to so we're going to use roll-ups
Amit file method there you tell it's an
asset and you give it a file name and
you give it the source of the HTML and
now roll up will write that file along
with everything else so here's our
template now we've got a placeholder
here for the JavaScript file name which
we don't know ahead of time because as I
said roll up will add a hash to the file
name so we need to pass in that final
file name into our templating engine
after half
and we can get this as I said from the
bundle object since it tells us both the
input path in the output path so we
create little helper here called get J s
which we just goes to the bundle and
finds the corresponding file yes so now
all we need to do is add that new
plug-in into our rule of config and
that's it we're done
now you know everything you need to know
to write a rollup plug-in and I realized
that you know that it's a pretty quick
introduction just throw at you but again
compare it to the web pack version and
I'd argue that what we wrote is simpler
just a little bit and and the good thing
is that everyone on our team I think
felt like they were comfortable with
touching that piece of code and
adjusting the plugin if it needed any
kind of changing and even better like
we're writing code to do what we want
rather than wrangling config so if we
wanted our HTML to be a slightly
different shape we could just go into
the template and change it on to add a
new tag rearrange things it's just HTML
but what do we actually need to change
to make things faster so I was slow on
the slow end on the flow and phones but
we need to figure out where procs was
actually using performance our tool of
choice for testing websites in as real
world conditions as possible
it's webpagetest.org it lets you run
tests on real devices which makes a big
difference and also has an excellent
emulation of worse network connections
yeah I always like to test on a moto G
for this is a fairly old now phone it
was a mid-range phone even when it came
out but it's not dissimilar to the kind
of phones that a lot of people have in
the world we're also going to test on a
3G connection and 3G is actually a
really good speed to measure I know
we're mostly used to here to like 4G and
LTE and maybe even 5g soon but you know
often due to signal strength and
contention you will be experiencing
speeds closer to 3G and sometimes even
worse so here's the results for the very
first version of procs before we'd
optimized it and whenever I look at
webpagetest the first thing I look at is
this film strip along the top because
there that shows us what the user sees
as the site is downloading yeah so let's
break that down for the first 4.2 second
the user sees absolutely nothing that's
what nothing looks like quite literally
no things totally Finglas
but out of nothing emerges our first
render that's our first render we can't
really count it as interactive though
until let the user sees the full UI with
with all of the interactivity and the
user doesn't get that until they have
been waiting five point one seconds so
we're well over that three-second mark
that causes fifty percent of people to
abandon according to some studies but
like we said we are targeting these 15
dollar feature phones in these fifteen
dollar feature phones are most popular
in emerging markets like India and their
speeds like 2g are much more on a daily
basis happening so on 2g the user gets
8.1 seconds of absolutely nothing than a
pretty useless render and in total it
takes almost 11 seconds until the user
can actually start playing the game 11
seconds let's put that into perspective
Usain Bolt can run 100 meters quicker
than it takes to load our dumb game
right so so all in all the user had to
load 62 kilobytes before the site was
actually interactive surely we can do
better but what is a realistic goal for
us here and that's what I asked Jake to
figure out yeah so I went and did some
competitor analysis and here it is so
this is a graph of the size of Windows
minesweeper over time it starts off at
11 kilobytes in windows 3.11 that's
pretty small it actually gets smaller
which is kind of amazing like 9.3
kilobytes and Windows 95
much smaller than procs the piece of
we made right like they're doing
really well but then in Windows 2000 it
became bigger seven times bigger in fact
70 K now this is now bigger than procs
the site's crept up again in Windows XP
there so it's up to 80k but then BAM it
became 50 times bigger three point eight
four megabytes in Windows Vista roughly
the same size in Windows 7 but then BAM
it became 25 times bigger still it's a
hundred and four megabytes in Windows 10
absolutely seriously minesweeper is
growing so fast we have to switch the
graph to a logarithmic scale if you
sometimes wake up at night and worrying
about how you CSS code base is growing
on proportion don't worry you're still
doing better than Microsoft yeah and if
you analyze this trend which we did by
2025 - people would be 2 terabytes by
2030 we predict two thirds of the
planet's surface will be covered by a
single hard drive containing one copy of
Windows minesweeper
I mean Rotenberg is doing some great
outreach of raising awareness with
climate change but really should be
worrying about the biggest threat to
mankind which is Microsoft minesweeper
absolutely so you have my conclusion is
really that procs is 62k not really
doing that badly so there you go thank
you good night thank you for this
insightful report so but on the other
hand we do know that my super can be
done in like 11k 10k that kind of
territory and so admittedly our version
has a bit more going on graphically but
still 62 kilobytes to interactive we
should probably reduce that yeah we
probably should so if you want to
improve the performance of your site and
you only have like a few minutes to
spare
identify the important resources that
start loading too late and so we're
looking at the timeline here we're
getting stuff we're getting this render
it like 4.2 seconds and our JavaScript
is loaded at that point so the site is
completely ready to go but it is useless
because the text is not rendering you
guessed it we are using a web font a web
form so we're using space mono from
google fonts both the normal and the
bold version and they're about 10k each
which as far as web fonts go is it
actually not that bad so why are they
giving us so much trouble yes and find
out we need to dive into the network
panel of webpagetest or in dev tools it
gives you the same information and
here's the pattern that we were seeing
first off the HTML downloads the filler
line here is a convention that both
webpagetest and chrome dev tools
actually use it means it's setting up a
new HTTP connection and the thicker line
is then the time it takes for
request and response yes and once that's
done it will download the CSS and then
it downloads the actual fonts now when
you're looking at these sort of diagrams
especially compared to rendering it's
worth noting that they don't always
exactly align and that's because once
the browser is downloaded something it
then needs to parse and execute it and
then paint it which takes time so
there's like an offset compared to you
know actual painted things on the screen
anyway the red flag here is that both
the CSS and the font files have their
own thin line meaning there's a TP
connection being set up and this is
because the CSS is actually on another
server it's on Fahnestock Google API
it's calm and so it has to start a new
connection to actually be able to
download that file yes but if we look
inside the actual CSS we can see the
fonts are actually hosted on yet another
server so this is fonts G static com so
that's yet another connection and the
quick fix here is to copy the CSS in the
fonts to our own server that way the
browser can reuse the already existing
connection and in theory we feel safe
around a second but wait you can't just
do that fonts are protected by various
intellectual property laws including
trademarks copyrights and design patents
Cottenham to your own server may violate
the policy of the rights holder valid
concerned but doesn't apply when you use
Google phones all the phones on Google
phones are open source and have
permissive licenses that you can just
copy to your own server Oh disaster
averted
I for one will sleep tonight in fact the
CSS turns out to be so small that we
might as well just inline it into our
HTML all about these fonts now the
browser tries to be smart here when it
comes to font downloading it won't
download fonts until it finds something
on the page that actually needs them so
that means it waits for the CSS to be
loaded and then an element appearing on
it in the dom that contains text that
needs that font and this is good in some
ways because it means the browser going
to avoid downloading fonts it doesn't
need but in this case we know it needs
both of those fonts from the very start
and the answer is a link rel preload tag
in the head of the document these tags
basically allow you to tell the browser
that it should download a thing and keep
it in memory until it's actually being
requested by the page and then it's
already there and with those small
changes we should see the yellow line
shrink when we pass it through
webpagetest the next time that's dude so
note that
Wow let's go back let's do it again hey
don't run Chrome Canary for your slides
I should know this by now okay have some
Atari yeah yeah I should have learned oh
so in theory we should be saving a good
amount of time here right but we have to
get it working within the build tools we
have so this is the plugin we saw before
the one that creates the HTML what we
need to do is inline the CSS for our
fonts and we need to add a preload tag
for each of them now
I'm not gonna go for it step by step
we've only got like 30 minutes or
whatever but it looks a little bit like
this whoo there it goes so at the start
of the build we use roll-ups Amit method
to bring the fun files into our build so
now roll-up is aware of these files and
we'll add hashes to the file name and
put it into the output folder all these
little things and when it comes to
generating our HTML we pass that data
into our template now so that we can
where this helper will actually give us
the final URL off the font files yes
that means we need to go back into our
template and we need to loop over that
font data and output a style tag that
defines the font and this is just all
the stuff we passed into the template
before there's the weight there's the
source and then we're gonna add a
preload type for each of those as well
so what I really like about this that
the roller plugin handles all the
roll-up specific stuff like making it
aware of the files putting them into the
build pipeline and adding hashes blah
blah blah blah blah but then for the
HTML part we use our HTML skills there's
nothing specific to roll up about this
template so roll up isn't preventing us
from rearranging or even adding new HTML
tags to our markup but we are not done
yet the fonts aren't the only asset that
is loading too late at the same time
like our main script loads and it also
will load to the other scripts it needs
so this is the code splitting thing we
saw before
because we're sharing scripts between
the the main thread and workers they sit
in different files but you know we know
once again that the main page will
always need all three of these scripts
so we should be pre loading those as
well yeah but the question is what what
faults should be pre loading we know
there are dependencies but what are
their actual names and luckily the role
of bundle object gives us the answer as
I said for each JavaScript piece of
output that we have
it will list give us an array of files
that are being directly or statically
imported so in this case we pass that
data into our template engine by just
looking at the dot imports property and
back over an hour EGS template we can
now just loop over these dependencies
and generate a preload tag for each of
them yeah just like that
so we've now moved our fonts onto our
own server we've added some preload tags
for them and for our scripts as well
better in theory but what does
webpagetest tell us about the real-world
impact well we have eliminated the know
fonts for I know the second anything is
on screen its interactive and good to go
and it's a one-second improvement on 3G
and a massive three second improvement
on 2g we haven't really impacted the red
bar though the time where the user sees
absolutely nothing yeah and four seconds
that's a lot of nothing
eight seconds is a lot a lot of nothing
this is the part where the user is just
staring at a white screen they don't
even know if the server is even think
about sending them a response so looking
at webpage tests network waterfall
confirms that we achieve what we set out
to do everything that's important is now
loading in parallel it's just taking too
long yeah so we have two options here
like we can have a try and make this
just shorter by shipping less code or we
can just make it matter less yep so
right now we are fully reliant on Java
Script to put anything on the screen so
let's put a stop to that let's use
server-side rendering but at build time
and that's often called a pre render or
a static render yeah so we want used to
see something like this like it's not
interactive at this stage so we've
removed all of the the buttons that
depend on JavaScript but this can appear
while the JavaScript is loading and this
really improves the perception of
performance because the user sees that
something is happening and then once the
JavaScript loads it can sort of lazily
enhance the page and there are a few
ways to actually do this every Dom
orchestration framework that is we're
talking about has a way to generate an
HTML string from its components and imp
react and react land that is called
render to string this is pretty fast
it's not as fast as a general-purpose
templating engine but pretty close to
the point where actually
people do run this on every request
although we only want to use its built
time so super high performance is not as
big of a requirement for us in this
particular use case however render to
string runs an ode and we actually see
that as kind of a downside because if
you have any codes in your components
that assumes to be running in the
browser which usually is a fair
assumption to make that will break and
not so we had a component with index DB
and that would just break we could fix
that by adding like code branches for
node versus browser but that will get
really messy over time over all ready to
string is probably ideal if you can bend
your components that way it's not what
we ended up using though no we looked at
JSON which is kind of like a browser
environment but it runs inside node the
problem there is the word kind of like
jest um it's like an entirely new
browser that you end up having to
support and we try to use it this is
what we thought we were going to settle
on but then we hit all these kind of
weird quirks like as part of our
inlining process we had some inline
Styles and we resource some of those
just going missing and it turns out that
JSON doesn't understand linear gradients
so it's just getting rid of them and
this is the right thing for it to do
this is what the the spec says the spec
says if there's an inline style you
don't understand it just just discard it
and JSON was dutifully behaving like a
browser according to that spec just it
was a browser that doesn't understand
linear gradients and also 4x12 is slower
than render to string so it's not
something you would want to be running
on every request but it's really matter
to us so in the end we ended up with
puppeteer babbity launches a headless
version of drone that you get to remote
control you can load pages you can
inject JavaScript you can inspect the
Dom it can read back any results and so
your code is running in an actual Chrome
so you don't have to it's not a new
browser for you to support it is however
obviously slower than render to string
it is also slower than j/s Dom but
actually surprisingly only by a tiny bit
but as I said we only to run it once per
build so it's not really that big a deal
it is really easy to install to you so
if you haven't done that yet take a look
at it and tell us what you think but
let's be honest adding an entire
from to your build setup is a pretty big
jump in complexity it is what we ended
up doing for procs though and it wasn't
about yeah so how did we get it working
well we wrote another plugin didn't we
here it is I'm not gonna go through it
line by line just wanting to show you
it's a relatively small chunk of code
puppeteer lets us launch this invisible
version of Chrome we run our JavaScript
and we collect the HTML that it
generates as a nice bonus like since our
CSS was inside our JavaScript it was
creating style tags for all of the
components that were used in that first
render so we sort of got CSS inlining
just for free yep
so one thing we haven't covered is how
do we prevent the pre renderer from
rendering components that aren't
interactive yet so we want this landing
stream to actually look a bit more like
this yeah so the simplest solution to
get that is you know give a little bit
of code to puppeteer just before we end
it the rest of our script and that means
in our app we can branch on that in an
if statement and do stuff like you know
hide buttons you know rearrange things
whatever and since that is only ever
going to be true in puppeteer land it
won't run those steps for real users but
it doesn't mean that you're shipping
code to real users that they don't
actually need but then again it's
probably not a lot of code and it's
probably not worth putting in the effort
to strip it all out can we fix this
please can we fix this all right so our
aim is to remove this kind of code to
ever-reaching the production bundle that
is being shipped to use this here's our
current set of plugins can you guess
what we are gonna do now I don't know
but I'm excited about it we are gonna
write a plugin out yes so the plugin
means that we can write code like this
and the value of this pre-render will be
exactly what the value of pre-render in
our roll-up config script is yeah the
plug-in like this is great for all kinds
of constants like passing in late
version numbers of things or different
kinds of flags now I've seen similar
plugins that do this they don't require
the import statement they just go
through your code and replace a variable
of a given name with a particular value
but I don't know I kind of hate that
because to me it's not obvious on the
source code that some build magic is
going to happen where it's like here you
look at that and you go well this import
is not normal this is not how imports
normally look so you can do a quick code
search for like the start of that string
the Const call on bit and then you'll
find the the bill tool that's actually
doing that it's really easy to discover
and also roll up it's really smart here
so if you do a build where preload is
true it will actually optimize it to
this and if you do a build where it is
false it will optimize it to this and so
that's what we did we created two builds
one for the user and one for puppeteer
so let's take a look this is legit the
entire plugin the plugin only does
anything when the import statement
starts with Const school and if it does
it just generates a string of JavaScript
on the fly containing the value that is
being imported that's it that's all yeah
here is the comparable webpack plugin
that does the same thing if you want to
have the dead code elimination again
it's not something I would feel
comfortable hacking around with and you
might feel like we're you know kicking
web pack a lot here you were right we
are but the honest truth is like the
difference that we felt between working
on a project with web pack and working
on a project with roll-up was really
really night and day for us like not
only did we feel like we understood what
was happening we felt capable of
changing what was happening if we needed
to
especially with less Jordan past like
you know making work as a core part of
your architecture it was incredibly
valuable to be able to go in and just
change how roll-up handled these kind of
things yes ok now we have an optimized
server render what do we win what is the
real world impacts let's take a look so
we have pushed that read nothing
rendered time right back we've put it to
almost two seconds of white screen on 3G
we've cut it by three seconds on 2g this
is a massive improvement to the
perception of performance so the yellow
area represents where we have something
on screen but the app isn't really
interactive yet because the JavaScript
hasn't loaded but at least the user is
seeing something to feel like they're
being informed about the progress of the
app loading so what can we do next well
looking at the network waterfall to
remind you the thin blog is the setting
of a connection and the stake block is
the time it's
for the request and the response to go
with a wire but there's another feature
of network waterfalls that we can look
at here and that's the time to first
byte
now both webpagetest and chrome dev
tools they highlight the area before the
first byte of the responses received so
this is the time taken up by the request
and waiting for the server to start
sending the response and as you can see
there is a pretty big gap between
receiving all of the HTML and receiving
the first byte of any of the resources
used in the HTML it's about 400
milliseconds on 3G and about a second on
2g there are two solutions to this one
is HTTP to server push No
so how achieved approach turned out to
be incredibly difficult to get right we
have seen a couple of teams with a good
number of like networking experts try to
use it and they struggle to just break
even in terms of performance yeah so the
alternative then is inlining like we
take these assets and we just put them
straight into our HTML so first up let's
do that with our fonts aligning both
ARRA funds would add about 20 kilobytes
to our HTML which honestly is kind of a
lot yeah that's why I took a look inside
these font files and I found some
interesting stuff
3/4 an upside-down question mark and
indecisive vowel the surprised face no
one knows what this is that's an asset
so what sorry it's an s10 no one knows
what this is fine if you want a P and a
B at the same time Scott you saw it and
this which it kinda looks like a rotated
elephants I think that's what that is
for the point is that none of these
characters are in this set which is the
set of characters that we are actually
using on our landing page so we figured
we just inline the characters that we
actually need which are these characters
and that's you know it's kind of like
tree shaking but for phones and for
funds its called sub settings and there
are command line tools that do this for
you but they're written in Python and I
kind of loathe Python and so - so
there's a little feature about about
google fonts the URL for the CSS of your
font actually takes a parameter which
looks like this but it was the first
language I learned I know
move on here so if you include this text
parameter the CSS will contain a URL to
a new font file which is specifically
generated to just contain the characters
that you are using in this text
parameter yeah I still have - anyway so
we used build script to go into these
files we generated and open them and
spit them into our template as base64
URLs and this only added 4.5 k to the
HTML which is much better than the 20k
for the full fonts we do still load the
full fonts because the future screens
will have more than just that initial
set of characters but you know they're
an interactive 40 away so we can wait
for like you know you load those lazily
in the background so how do we do this
well back to our create HTML plugin or
at least the part that feeds data into
our templating engine for each font
we're passing in the weight and the URL
but you're also going to pass in the
inline fund as a base64 encoded string
yeah and this is just using built-in
node API is nothing special but we're
also going to pass in the Unicode range
for each font now if you've used web
fonts before you'll have seen that you
need to specify the Unicode range to
tell the browser exactly what's inside
the font there we use this little
library from NPM which just takes a lot
of characters and will give you a valid
CSS unicode range for all of those so
now we're passing everything into the
template that we need to in the font but
what about our JavaScript yeah so here's
where we're getting the file name you
know that we're passing into the
template but roll up instead could just
give us the entire code job done we're
also passing in the file names for all
the dependencies as we talked about
earlier so instead we'll map over those
and return the code for those instead so
we had to change the HTML template as a
result to handle that but again this is
using our skills in HTML nothing plug-in
specific so here's where we're doing the
inline font there as part of the base64
URL we can add the Unicode range there
and there is the the inline script so
we're done in theory but how does this
impact our real-world performance we've
already improved things a lot but with
inlining we've reduced our interactive
time by half a second on 3G and by about
a second on 2g but we're not done yet
now this javascript is inlined as well
we've reached the point where the only
thing that matters for first interactive
everything that's inside of the HTML
file like we've come a long way so even
over 2g we're now interactive and just
under six seconds not too bad but we can
do better
yeah like looking at our HTML file or
index.html file it's 43 kilobytes and 32
kilobytes of that our JavaScript and
that is the code for everything it's all
the fancy animations it's our rendering
engines the WebGL bits it's the end
screen and the user duty doesn't need
the end screen at the start of the game
yeah what we've done here is we've we've
done a Photoshop right sure you've
experienced this before where you're
staring at this screen while it loads
like a hundred plugins even though like
the first interaction all you can really
do when it when it starts up is create a
new image or load an existing image you
don't need all of those plugins until
sometime later on yeah my my my favorite
plugin is halida bottlenecks like series
when you first showed me this I thought
like well ironically I thought you'd
Photoshop just a silly name in there
like a poem oh I wasn't getting but this
is a real it's a real pile of this it
sounds like a Swedish folk singer like
highlight the bottlenecks yeah so let's
not load everything before the user can
do anything let's prioritize the code to
do this the first interaction is
basically the user picking what kind of
game they want to play and the only
thing we to react to is the user hitting
the start button and if for some reason
the user manages to press the start
button before our game logic has loaded
that's when we can spin up a loading
screen everything else can really just
Louis liking later it won't really
matter yes so this is where we need to
code split at this point because this is
our first interactive bit we don't have
the fancy animated background or the
logo that you know that stuff is
non-essential really Co splitting in
roll up works much the same as it does
in WebKit and web pack and parcel
imports like this this will cause
whatever dot J's to be bundled into the
same file if you want to be code split
instead you'll use a dynamic import and
this will return a promise so if you
want to use that module sometimes later
you will have to await it just in the
usual way
so the difference now is that whatever
dot J's is not going to be bundled in it
is going to be put into another chunk
and that makes it a sink which can bring
its own problems for example most of the
UI framework we are using nowadays
expect rendering to be synchronous and
can't really handle promises so react
suspense is aiming to change that by
allowing you to lazy load components but
pre-act doesn't have suspense so of
course we wrote it ourselves in 20 lines
seems like it obviously it can all half
of the things of that react suspense can
do but it can do everything that we need
it that we needed to do so really well
does if you give it a promise of a
component it wrapped it and returns you
a real component synchronously and you
can use that component as a placeholder
with two parameter spacing it will take
a loading function which will read
people used for rendering a placeholder
until the underlying component is ready
and at that point just switches over and
uses the other function like for aura
nebula yes so with that we moved all of
our components to a lazy model except
the ones that we needed for the first
render and this cut off over 20k
of the HTML that the JavaScript is now
down to just 11 K now I mean honestly I
think 11 K is a lot of JavaScript for
but is basically just a simple form on a
button but you know it's it's done its
job it's given us like that really quick
first bits of interactivity but you know
you're going to develop this app you're
gonna add stuff fix bugs how do we stop
this creeping up over time and this
turned out to be quite hard quite
interesting so you know you're sitting
there you write a new comp or you want
to add a new feature to the app and you
do everything right you think about
performance you think about file size
and it's Friday afternoon and none of
your colleagues are looking and then and
you have a weak moment and then you do
it you use vias code autocomplete and
bam suddenly you have a static import it
pulls in 200k of more code and that that
exactly is how Microsoft minesweeper
happens
yeah so we tried to know about how ways
ways we could fix this we tried the
comment system where we just put a
warning in files that we should encode -
yeah
bulletproof isn't it it did help a
little bit it was acted as a reminder it
was something we'd look at and in diffs
but yes we know it wasn't the best
solution your tools not rules so we felt
a little thing this hooks up to Travis
CI and so on each build it will go and
look at everything in the dist folder
and it will record the sizes of it and
that means when you create a PR it will
compare that against master so it'll
give us the Delta for all of the files
and so that means for every PR we just
go into this we have a look and you know
we'll be able to see if that index.html
file it's ballooning in a way that we
didn't expect this this works for all
projects that use Travis so you know
feel free to give it a go so what do we
win what do we gain since this is our
last optimization let's rewind all the
way back to the start to see where we
started yeah we started at like five
seconds until ready on 3G and 11 seconds
already on 2g we moved upon since we're
on server we pre-loaded the fonts and
the scripts and that improved the time
to interactive we added aesthetic render
improving perceived loading performance
and getting pixels on the screen earlier
and then we aligned our scripts and
subsided the fonts bringing down the
time to interactive again and then we
split the code we focus on the code that
we needed for interactivity and split
off everything else and that slashed the
time to interactive by over a second on
3G and by two seconds on 2g yeah so from
the stying point we've like half the
time to interactive and so let's
actually feel what that difference is
so here on the left is the original
alpha version and on the right is the
latest version this is loading over a 2g
connection so it's all got a bit of a
delay at the start because I think
setting up connections but then our
optimized version there it is and now
it's interactive the user can use it the
old version it gets there but come on
it's like still not interactive because
of the fonts and finally it's like so
much later remember when you are at a
festival or on a train on conference
like here or you just on vacation and
using roaming you will be experiencing
speech like speeds that closer than 3G
or even 2g sometimes yeah I also once
they're playing the game we install the
serviceworker because you know I'm not
allowed to ship anything that doesn't
have a
and that means like it's going to work
offline first but you know as a side
effect it means it cuts down the timing
to like well pretty much instantly just
a second for all caches to split so you
might be wondering where did we end up
with our plugin counter well to be
honest ii wrote way more plugins than we
talked about in this talk so this is
what our roller plugin looked like in
the end it's probably easier to me to
highlight the plugins that we did not
write which is these and so in total
that brings us to 16 plugins it's not a
bad thing I don't know I'm not so sure
I prefer wrangling code than I do
wrangling come to give someone else's
code I think it's really empowering to
be able to go in and just fix stuff
without spending days learning a new DSL
or something like that we're not asking
you to use our plugins absolutely not
because they're kind of dependent
interdependent and unique to procs but
we're saying like write your own cuz it
probably be quicker than using someone
else's plugin for especially for a lot
of fairly trivial stuff and if your
current build system is in the way of
shipping features that improve
performance for your users get a better
built system by right
you