[MUSIC PLAYING]
MARIKO KOSAKA: Let's go
back to February 1993
on www-talk mailing list.
JAKE ARCHIBALD: This
man, Marc Andreessen,
he's the creator of Mosaic, one
of the earliest web browsers.
He wrote this.
"I'd like to propose a new
optional HTML tag, IMG."
MARIKO KOSAKA: And this man
replied, Sir Tim Berners-Lee,
he wrote, "Or how about ENTITY,
ICON6, SYSTEM, URL, &ICON6."
[CHUCKLES]
JAKE ARCHIBALD: And Marc
replied, "Quick, Tim, look over
there."
And two months later, Mosaic
shipped with the IMG tag.
[LAUGHTER]
MARIKO KOSAKA: It's
really fair to say
that IMG has been pretty popular
on the web for the past 25
years, right?
JAKE ARCHIBALD: Yes.
MARIKO KOSAKA: In fact,
according to HTTP Archive,
the average web page loads
650 kilobytes of images.
That means it's 52%
of page content.
JAKE ARCHIBALD: Yeah.
And images are less
blocking compared
to things like CSS and scripts.
But they can take bandwidth
away from more important things.
And of course, if the image
is your primary content,
loading it quickly
is very important.
MARIKO KOSAKA: Yeah.
Unfortunately, websites
throw those bytes away
by using really inefficient
codec like the one that
comes with Photoshop.
JAKE ARCHIBALD: And there
are better options as well.
So this is mozjpeg from Mozilla.
But there is also
WebP, which is probably
supported by the majority
of your visitors.
As you can see, that
WebP has beaten mozjpeg.
But both of them have
done really, really well
compared to Photoshop's
JPEG encoder.
MARIKO KOSAKA: Yeah.
But except you
can't really see it.
All you can see is
some text and numbers.
And these [? come-online ?]
tools are great for batch
processing and automating your
build process and everything.
But when you are
trying to build a site
and trying to choose
something, it's
really not a good experience
to change the option.
Because you can't really see
the effects of the image while
you are doing it.
So a lot of innovative,
small compressions
are hidden behind these texts.
JAKE ARCHIBALD: Yeah.
And this winds me up every
time I see a new image
format come out.
Because you get
these really bold
claims in a few sample images.
And I'm left feeling,
I don't believe you.
I don't believe you
unless I can try it
in an easy way using
my own images, not
cherry-picked examples.
So we thought, let's make
image compression easy
using the world's most
accessible GUI, the web.
MARIKO KOSAKA: Yeah.
So that's what we did.
I'm really excited
for this slide.
Because I get to do this
announcements of the product
thing.
Well, here we go.
Today, we are excited to
announce new progressive web
app, Squoosh.
JAKE ARCHIBALD: Yay.
OK, fair enough.
MARIKO KOSAKA: Did you
like that animation?
JAKE ARCHIBALD: It was
a beautiful animation.
Well done.
MARIKO KOSAKA: Thank you.
JAKE ARCHIBALD: So now
the most terrifying part
of any presentation, we are
going to give a live demo a go.
And with the big web
quiz failing earlier,
luck isn't on our side.
Actually, so with the
big web quiz stuff,
I had noticed some of
the answers changing
from underneath me as I was
correcting them and editing
them yesterday.
And when that happened,
I thought, well,
what could have happened here?
Could Surma have coded it wrong?
Or am I so jet lagged I don't
really know what's going on?
And I went for that one.
I just didn't believe Surma
could have done it wrong.
OK, are you ready to go?
MARIKO KOSAKA: Yeah.
JAKE ARCHIBALD: OK.
It's going to be fine.
So this is Squoosh.
This is squoosh.app.
So all we need now is
an image to compress.
And there are some example
ones along the bottom here.
But let's pick a
real-world example.
I'm going to go to the
Google I/O website.
This is the one from this year.
Now that header image there
is a massive 1.7 megabytes.
And that is a large portion
of the page weight here.
So I'm going to save
that image, and we're
going to drag it into Squoosh.
With Squoosh, it
supports the file picker.
It supports copy and paste.
In this case, we're just
going to use drag and drop.
There we go.
So on the left-hand
side here, we've
got the original
1.7 megabyte image.
And on the right-hand
side, we've got mozjpeg.
As you can see
straight away, mozjpeg
has taken it from 1.7
megabytes to 500k.
That's huge.
And to my eyes, I
can't really see
a difference between the two.
If we zoom right in to the
folks on the screen here,
we can start to
see the difference.
If we drag from
side to side-- there
you go-- slight difference.
But it's not going
to be displayed
like this on the website.
It's displayed zoomed out, and
you can't see a difference.
All this is a-- this
kind of interface,
this works with touch
events and stuff as well.
You can touch the
screen and do it.
So it works great
on a Chromebook.
I was paid to say that, but
it is, nonetheless, true.
[LAUGHTER]
But because it's
displayed for these--
it's optimized for
high-resolution screens,
this big image, well, we
can tweak the settings
based on that.
So we're going to bring the
quality down to 44, obviously,
one that we rehearsed.
And that's just
because it's going
to be resize down like that.
And we can't really
go lower than 44,
because it starts picking up
banding issues, especially
around the sky bit there.
But we've really
dropped the file size.
It's almost another 200k gone.
Now, lossy formats, they
work by removing data
that humans aren't very
good at seeing anyway.
So for instance, we're
more sensitive to changes
in brightness than
changes in color.
So these lossy formats,
they'll store color data
at a lower resolution
than the brightness data.
But again, since this is
aimed at high-density screens,
we can go even lower.
So we're going to dive into
these advanced settings here.
We tried to expose everything
that these codecs can do.
So there are some scary things
here like trellis multipass.
What does that do?
Well, I have absolutely no idea.
But I can check this.
I can see the impact of it.
It's really cheap
for me to try it.
I'm not breaking anything.
MARIKO KOSAKA: Yeah.
The great thing about
having UI is that you
can see it right here, right?
And you can figure that
out, like, toggle it.
JAKE ARCHIBALD: Yeah.
You can start to
learn what they do.
MARIKO KOSAKA: And if it's
[? a come-online ?] tool,
you can't really see until
you're finished, right?
JAKE ARCHIBALD:
Absolutely, and one
of the options we
are going to look at
is the auto-subsample chroma.
This is the thing that's
changing the resolution
of the color data.
By default, it halves it, but
we're going to quarter it.
And that's another
20k gone as well.
So we've now reduced it by
83% of the original that
is on the I/O website.
If we zoom right in, it's
looking like a bit of a mess.
You can really see
the difference there.
But again, zoomed out, which is
how it's displayed on the site,
it's really different.
It's really difficult
to tell the difference.
Mozilla have done an amazing
job at getting the most out
of an old image
format like JPEG.
But let's compare it to WebP.
So on the left-hand side,
we're going to switch to WebP.
And we'll drop the
quality down to 20.
WebP is a much more
modern image format.
It's based on the
VP8 video codec.
It's supported in Chrome.
It's coming to Edge
18, Firefox 65.
But straight off now, we'll--
we're going to be around about--
MARIKO KOSAKA: Sorry.
Sorry.
[INAUDIBLE]
Yes.
JAKE ARCHIBALD: There we go--
about another 100k
less than the JPEG.
That's 1/10 of the
size of the original.
If we zoom into those
people on the screen again,
we can start to see the
difference between the two
codecs.
JPEG goes for a very blocky
look, whereas WebP loses
details through smoothing.
In fact, the WebP,
at this size, kind of
looks in some ways
worse than the JPEG.
I don't know.
It's subjective.
But that's also
because we've been
able to drop the
quality of the WebP
a lot more because it doesn't
suffer from those banding
issues that we get with JPEG.
And again zoomed out,
there's barely a difference.
So now we've done that, we
can download the two images
and hopefully send them to
the people who on the I/O site
because that's 1.4 megabytes
saved for every visitor that
supports WebP, 1.3
megabytes saved for people
who like to support JPEG.
So that's lossy compression.
But we support lossless
compression as well.
The Squoosh logo
here, this is an SVG.
Vector formats are
great because they're
maximum resolution on any
device density, any size.
But it's worth looking
at how this comes out
in a nonvector format.
This looks a bit broken.
This is because we're
using JPEG, which
doesn't support transparency.
So we'll change
to another format.
We'll change to OptiPNG, which
is an optimized PNG format.
Once we do that, it's bigger.
It's over twice the
size, which is not great.
But we can optimize for
these kind of codecs.
So we're going to
reduce the palette.
We're going to bring it down
to, I don't know, 70 colors.
And we can turn off differing
because we're happy with just
a flat color there.
And once we do that,
we are now smaller
with the PNG versus the SVG.
It's just a few K.
If we zoom right
in, we can start to see, I don't
know, very subtle differences.
But zoomed out, it's
not a big deal at all.
But let's throw this at
WebP's lossless mode.
So we're going to
copy the settings
from one site to the other so we
keep the reduced palette data,
switch to WebP, and put
it in lossless mode.
So WebP's lossless
codec, it's kind
of like a completely
different codec.
They should have probably
called it something different
because it's much
more similar to PNG.
But now you can see we've cut
even more off the file size.
We're 34% smaller than
what we were with the PNG,
with the SVG even.
But this is yet another
cherry-picked demo.
Like, we have scripted this
to look good on stage, right?
What I am saying
to you right now
is literally written on
this screen, including that,
and that, and that, and this.
MARIKO KOSAKA: Excuse me.
[LAUGHTER]
Yeah, well, but
all we are saying
is that, just don't
trust our demo.
Just go to our app, throw your
own image, and try it out.
And see how many bytes you
can shave off the image
by keeping acceptable quality.
So we can go back
to the slides now.
JAKE ARCHIBALD: OK.
So that's the good parts.
But Squoosh is still in beta.
It isn't finished yet.
There are-- there's
a few rough edges.
And we do want to be
honest about that.
For instance, right now,
if you open it in Firefox,
you get this.
We're a little bit behind
on our browser support.
[LAUGHTER]
Oh, come on.
Look, we've run out of time.
We are hoping to fix this.
MARIKO KOSAKA: Yeah.
We had the big web quiz
to build and everything.
JAKE ARCHIBALD: We had
other things to build.
We are joking of course.
MARIKO KOSAKA: Joking.
JAKE ARCHIBALD: Come on, right?
MARIKO KOSAKA: Yeah.
As well as being a useful tool--
which we hope that you find it
useful too--
we wanted to practice
what we preach.
So we wanted to make the
Squoosh to be a great PWA.
So Squoosh works in latest
version of all modern browsers.
[APPLAUSE]
Well, this is kind of--
JAKE ARCHIBALD: Only Googlers
can get a round of applause
for just making things
work with other browsers.
MARIKO KOSAKA: Yes.
This is kind of sad that
we got applause for this.
JAKE ARCHIBALD: Yes.
In fact, what you're seeing
here is Firefox 63 opening
a WebP of my stupid cats.
And this is in Firefox 63,
which does not support WebP.
WebP support doesn't
land until Firefox 65.
MARIKO KOSAKA: Yeah.
But we didn't want the key
features to be missing.
So we needed to make sure the
Squoosh could lead and create
images in all modern browsers
using those codecs, which
brings onto--
let's talk about how
we built Squoosh.
JAKE ARCHIBALD:
Yeah, and this is
an idea I had around
about five years ago.
It's something I'd
been wanting to build.
And I tried to build
it five years ago,
but browsers weren't
quite smart enough.
But more importantly, I
wasn't quite smart enough.
So Squoosh is a real team
effort with contributions
from all of these talented
engineers and Paul Kinlin.
MARIKO KOSAKA: The
key thing that made--
[LAUGHTER]
Are you glad that joke
landed really well?
JAKE ARCHIBALD: Thank you.
MARIKO KOSAKA:
The key thing that
made Squoosh possible
is WebAssembly,
which is supported in all modern
browsers for over a year now.
I know we have
WebAssembly sessions later
in this conference.
But as a little primer,
Wasm, or WebAssembly,
is a compile target for the web.
So you have your code written in
C, Rascal, or whatever choice.
You would usually compile
it to run it on different OS
as the app.
But using WebAssembly,
the technology,
you can compile the same
code and run it in browser.
So for Squoosh, the mozjpeg,
the web WebP, the OptiPNG,
all of those codecs
are written in C.
So we used a tool called
Emscripten to compile the C
code into a WebAssembly so
that we can run it in browser.
JAKE ARCHIBALD: Yeah.
And this was really, really
essential for the project
because browsers
do actually ship
with imaging coders
like JPEG and PNG,
which you can access via
the Canvas API like this.
But they suck.
They are really, really bad.
We have made them
available in Squoosh.
So you can use them if you want.
They are actually quite fast.
That's the one thing
they've got going for them.
We thought, why not?
But you only get this
one quality option.
And ugh, they're just rubbish.
This is Chrome's JPEG encoder
on the left compared to mozjpeg.
And it's ugh, the Chrome
version is just a lot rougher.
It's blah.
It's horrible.
It's actually way
worse in Firefox.
MARIKO KOSAKA: Firefox.
JAKE ARCHIBALD: The JPEG
encoder in Mozilla's browser
is terrible compared to
Mozilla's JPEG encoder.
[LAUGHTER]
MARIKO KOSAKA: Yeah.
We see the same
thing for PNG too.
So that Squoosh logo that
we looked at in the demo,
if you use a browser's
native compressor,
then those are the
numbers you get.
The Firefox are significantly
better than other browsers.
But it's still not good compared
to OptiPNG, which Squoosh uses.
And this is for exactly the
same image, pixel-by-pixel, just
compression, different numbers.
JAKE ARCHIBALD: Exactly.
And Wasm let's us bypass
the browser's encoders
and use much better ones.
It also let us bring
in the WebP decoder
to use in browsers that don't
have native WebP support.
Now, I know almost nothing about
C. So that part of the project
was really down to this man.
So please, welcome
to the stage--
so good, we named him once--
it's Surma.
[MUSIC PLAYING]
[APPLAUSE]
MARIKO KOSAKA: So you made most
of the WebAssembly stuff work.
SURMA: Yeah.
[LAUGHTER]
JAKE ARCHIBALD: How was it?
SURMA: It was good.
JAKE ARCHIBALD: Cool.
SURMA: Cool.
JAKE ARCHIBALD: Surma,
ladies and gentlemen.
[MUSIC PLAYING]
[APPLAUSE]
MARIKO KOSAKA: Yeah.
Well, thankfully Surma
wrote an article about it.
So we have some things to share.
JAKE ARCHIBALD: Yeah.
Compiling a codec to Wasm, that
involved writing a little bit
of C++, which included the
codec and some of the Emscripten
stuff.
And then we wrote a function.
This is the function we want
to expose to JavaScript.
It takes our image data,
takes it as a string
because that's how Emscripten
represents binary data in C++.
So on the JavaScript side,
we're passing in a Uint8array.
And it ends up in
C++ as a string.
And we also have our other
arguments, width and height,
and the codec settings.
In this example, I'm
just using quality.
And then we call out to the
actual encoder under the hood,
passing in all the settings,
getting the output,
and then we return it.
And this vowel and
type memory view stuff,
this is annotation
to tell Emscripten
to treat the return value as a
Uint8array back in JavaScript
land.
And then all we needed
to do is tell Emscripten
which methods to expose.
That's it.
MARIKO KOSAKA: I'm
a web developer.
You completely lost me.
Do you get any of this?
JAKE ARCHIBALD: No, I
don't understand it either.
But I copied the patterns
from Surma's article.
And hey, it just works.
It's great.
MARIKO KOSAKA: Great.
JAKE ARCHIBALD: I was able
to take those patterns
and use them for different
kinds of C projects as well,
like text compressions
and stuff.
It's-- yeah, it's pretty
good, pretty good.
MARIKO KOSAKA: Yeah.
So compiling that
code with Emscripten
gives a JavaScript
file in Wasm binary.
So now you can
include that script
onto your page, which also
loads that Wasm binary.
And once all of the
script is ready,
you can just call
that encoding function
as if you're calling JavaScript.
JAKE ARCHIBALD: Yeah.
Using Emscripten, it feels a
little bit rough and ready.
But the docs are really good.
And Surma's article is good
enough to get you started.
MARIKO KOSAKA: Yeah.
But in this case, we are dealing
with a large C project here.
And those are really
CPU intensive.
So that brings us
to performance,
which we were kind of worried
about in the beginning
of the project because
we knew that's going
to be a thing that
we need to take care.
JAKE ARCHIBALD: Yeah.
We're halfway through the
talk, so we're actually finally
starting to get to the point.
MARIKO KOSAKA: Yeah.
So we used PREACT to
orchestrate the DOM
and webpack to bundle
it all together.
JAKE ARCHIBALD: Yeah.
We used PREACT
because it does what
it does in 3k, which
is kind of amazing.
We also had Jason on the
project-- that's probably--
MARIKO KOSAKA: That's true.
Clear it off the [INAUDIBLE].
JAKE ARCHIBALD:
--another reason.
We wouldn't want to upset him.
And we used webpack because
there isn't really anything
else that does what webpack
does, certainly, not
in the way we wanted it done.
We wanted a lot of
control over it.
And it was really only webpack.
MARIKO KOSAKA: Yeah.
So as a result, our app
is 400 Kilobyte gzipped,
all in all, everything.
But this is well
below the median
from HTTP Archive,
which is 1.5 megabytes.
So we're quite happy about that.
JAKE ARCHIBALD: Yeah.
We're winning.
We're winning.
We're happy with that.
So the vast majority
of that size
is the codecs and
the processes, like,
the stuff we brought
in from C land.
And that's-- yeah--
300 kilobytes of that stuff.
And I'm pretty sure there's
some waste and duplication here.
But like I said, Emscripten's
a little bit rough and ready.
And cosharing
between Wasm modules,
it doesn't seem all
that easy right now.
It's something we'll look into.
But we were able to limit
that damage by lazy-loading
these using workers.
MARIKO KOSAKA: Yeah.
As we've already seen,
compressor is CPU intensive.
So depending on
settings, encoding
can take 30 seconds
to sometimes minutes.
And when that thing is
happening and occupying CPU,
we don't want that
UI to be frozen.
We want users to
be pinch zooming,
and moving around, and
testing, and possibly changing
the options too.
So--
JAKE ARCHIBALD: Yeah.
Workers give us this
lazy loading stuff
for free, which is great.
But the main benefit
is concurrency.
We create up to two workers.
And both of those
are just going to be
pointing at the same script.
That's one for the
left-hand side of the image
and one for the right-hand
side of the image.
This means the left-hand
side can be encoding a JPEG.
And the right-hand side
can be optimizing PNG.
And all the while, the main
thread stays responsive.
And that was really all the
concurrency that we needed.
MARIKO KOSAKA: Yeah.
But it came with
another benefit too.
So the left-hand side--
let's say [INAUDIBLE],,
left-hand side worker is
compressing an image, right?
But what if a user
changes the setting?
The current job is out of date.
We need to update it.
But those compression
encoders are
written in a synchronous way.
So there is no abort API.
There is no way to kill it.
However, we put it into worker.
So in this case, we just
terminate the worker,
and then click new workers, put
the new job in, and then start
it back up again.
JAKE ARCHIBALD: Yeah.
And the implementation
for this is pretty simple.
So it's just like this.
MARIKO KOSAKA: Ooh.
JAKE ARCHIBALD: Oh.
Oh, go on, you click.
This is the problem.
We've got two slide clickers.
And we needed to
rehearse who was doing
the changing for each slide.
So what you saw there
was us messing it up.
[LAUGHTER]
Implementation is
roughly like this--
if busy, terminate, and restart.
But also, we only spin up one of
these workers when we need it,
like, just in time.
So if you're doing something
kind of like what we were doing
in the demo-- we had the
original image on one side,
JPEG on the other.
We only spin up one
worker because we're only
having one side doing
compression at the time.
And also, if one of those
workers is idle for 10 seconds,
we kill it as well.
And that is really just to
be kind to the user's device
to bring the memory
footprint down.
MARIKO KOSAKA: Yeah.
That worker is almost
empty when it started.
Heavy stuff is imported
when it's needed.
This keeps the worker
startup time down.
And also, you don't really need
to download and parse and wait
for the OptiPNG
and mozjpeg stuff
if user is just encoding WebP.
JAKE ARCHIBALD: Yeah.
And using a wait
import like this,
this is part of the platform.
It's supported behind
a flag in Chrome.
But it isn't supported and
stable or in other browsers.
Thankfully, it's something
that webpack can just handle.
It polyfills it,
and it just works.
Now, the final
piece of this puzzle
is how we actually
talk to the workers.
MARIKO KOSAKA: Yeah.
So request and response
communication with workers--
eh, a little tricky.
So the way worker works is that
you send the worker some job.
And at some point, they
come back with the results.
But you need to associate
those requests and response.
So in this code example,
we just give a unique ID.
And when worker is
done with that job,
then it gives back the ID.
But you have to write
your own logic for this.
And it's like, eh, eh, eh.
JAKE ARCHIBALD: It's rubbish.
I really don't like it.
It's one of the things that
puts me off putting stuff
into the-- of a thread.
It goes ah, I'm going to have
to do the post method thing.
I don't like it.
MARIKO KOSAKA: Yeah.
That's a layer to
worry about when
you're writing application.
JAKE ARCHIBALD: But again,
to the rescue, it's Surma.
[LAUGHTER]
He built Comlink, a little
library that you can use,
you can get from mPm to use it.
It's just like this.
You create a worker
as you usually would.
And then you tell
Comlink all of the things
that you want to expose.
These can be classes, values.
But we were just
using functions.
And then over in your page,
you just hook the Comlink up
to the worker.
And now you can call
those functions just as
if they're part of your page.
Comlink takes care of all of the
bookkeeping, the post message
stuff, all of that mess.
MARIKO KOSAKA: So once
we've split up that codecs,
our app came down
to 35 kilobyte.
Yeah.
But I want to make sure
that a user will still
have to download those
300 kilobytes if they
want to use all of the codecs.
But they don't need
to load those upfront.
But 35 kilobytes, it still
contains the pinch zoom logic,
the options panel, the fancy
slider, then this thing,
and that thing, this thing,
this thing, ooh, that thing too.
And what these have in
common is that it's not
here, our first page.
JAKE ARCHIBALD: Yeah.
Imagine going to a restaurant
and asking to see the menu.
And 10 minutes later, you
still haven't been given it.
So you're going to ask,
excuse me, where's the menu?
And they say, oh, well,
we're busy preparing
every single dish we do.
And then we'll
give you the menu,
so when you pick
something-- bam--
we will give you
that straight away.
It's ready.
[LAUGHTER]
MARIKO KOSAKA: Yeah.
You laugh but much of the web
is built this way, especially
JavaScript-heavy apps.
JAKE ARCHIBALD: Yeah.
Because you might look
at the menu and decide,
oh, I don't want
any of this stuff.
Or you might want
something simple.
You're certainly unlikely
to want everything.
So why should getting the menu
and making a choice be blocked
on them preparing
all of their most
complex, time-consuming dishes?
MARIKO KOSAKA: Yeah.
Same for JavaScript apps.
They prepare everything up
front before doing anything.
So the user really
shouldn't have
to wait for all of these
things to download, parse,
and execute.
They just need to
get to this page.
JAKE ARCHIBALD: And like most
web apps-- like most apps--
Squoosh has a limited set
of first interactions.
[INAUDIBLE] it's dropping
an image onto the page,
selecting one file
by the file picker,
or selecting one
of the demo images.
So we split all of that out.
This is roughly how things
looked at the start.
We had our intro.
And we had our compression UI.
If no file had been
selected, we show the intro.
Otherwise, we send that
file to the compression UI
and display that.
We changed this so the
whole compression API part,
that was loaded asynchronously.
And the tool chain
actually made that
a lot easier than I expected.
MARIKO KOSAKA: Yeah.
So first up, we
removed the URL import
and instead,
dynamically imported
that in the constructor
and set that as a state.
So dynamic imports are supported
natively in Chrome and Safari.
But using webpack provides
similar functionality
to all of the browsers.
JAKE ARCHIBALD: Yeah.
So the compression UI is
going to start downloading
as soon as the intro loads.
But there is a small
chance that the user
is going to be able to select
a file before it's ready.
So in which case, we
just show a spinner.
Very unlikely that the
user is going to see that,
but we put that in just in case.
MARIKO KOSAKA: Yeah.
So remember with
codec, speed it up.
We chopped that
300 kilobytes off.
But with the code splitting,
we made that into 15 kilobytes.
And this is despite our app
being JavaScript-driven,
using frameworks.
And 15 kilobyte gzipped
is even with empty cache
on the user's device.
JAKE ARCHIBALD: Exactly.
And that means on a
slow 3G connection,
the user gets the first
interaction in 3.3 seconds.
And that's a slow
connection on a slow phone,
but it's not the
worst conditions.
Even on 2G, we are
still interactive
in less than 5 seconds.
Now, I don't think many
people in this room
spend a lot of time on 2G.
I know I don't.
But this kind of
performance means
the app is really usable
even in emerging markets.
And this is why
I'm a huge fan of
these microframeworks,
like PREACT,
but also Lit-html,
hyperHTML, Svelte.
We couldn't have actually
hit these numbers with React
because that's 30, 40
kilobytes out the door.
We couldn't do it with Vue,
because that's 20 kilobytes.
Angular is 60.
Ember is bigger still.
But let's not get carried away.
15 kilobytes, 8 of
which is JavaScript,
is actually a lot of
JavaScript for these couple
of interactions.
MARIKO KOSAKA: Yeah.
So for instance,
let's look at how
we might build this user
interface with just Vanilla
JavaScript.
So here's a minimal
implementation
of drag and drop,
just a few lines.
And then add that to
that drag and drop
is the self-selecting
of file code.
That's not that much.
And then this is for
selecting one of the demos,
clicking, and loading the image.
So these, all of that
code, minified and gzipped,
it's only 550 bytes.
JAKE ARCHIBALD: Or 350 bytes.
MARIKO KOSAKA: Ooh.
JAKE ARCHIBALD: But whatever.
I'll go with the
number on the screen.
MARIKO KOSAKA: Can't
see the number.
Yes, 350 bytes.
JAKE ARCHIBALD: And
that's why I get really,
really grumpy when I see sites
like with this 600k or more
JavaScript bundle.
And that's for
first interaction.
I have friends who
build native apps.
And when they talk about their
two megabyte Android Instant
Apps, I love being able to
go, instant, 2 megabytes.
Great.
15k.
[LAUGHTER]
But then they--
MARIKO KOSAKA: With
your smug face on.
JAKE ARCHIBALD: Yeah.
[CHUCKLE]
I think it's called
a shit-eating grin.
Anyway.
[LAUGHTER]
But then they can
point to large parts
of the web that have
thrown this advantage away.
Parts of the website have
taken on the worst of native
but none of the benefits.
MARIKO KOSAKA: Yeah.
So if you take anything,
anything out of this
talk, please, please, please,
study your website or your web
apps, and find out what
the first interaction is.
And shift the reasonable
amount of code
for that first interaction.
Now, reasonable amount of code.
How do we find out?
We have a lot of tools.
Yeah.
Just experiment, and find out
what is reasonable to you.
JAKE ARCHIBALD: So you
also need to keep an eye
on the bundles between builds.
And with webpack--
and right now that,
unfortunately, means going
and looking at minified code.
Because that's
where it does things
like tree-shaking and
dead-code removal.
It's part of the
minification process.
MARIKO KOSAKA: Yeah.
We ran into a few bugs
because of that, right?
JAKE ARCHIBALD: Yeah.
We were still not quite sure
if it was a bug in webpack
or if it was our expectations
were different to what webpack
was doing.
But it was when we dived into
the minified bundle, that's
when we found that stuff out.
Alternatives, like rollup
are much better here.
They will show you the dead-code
removal during development.
So it's easier to see
when something's not
going as you expect.
But rollup doesn't have the
kind of holistic asset graph
that we really needed
for this project.
Anyway, my point is,
there are huge gains
to be had by keeping
an eye on this stuff.
MARIKO KOSAKA: Yeah.
So like we said, we used
PREACT to orchestrate the DOM
But we also used
Web Components When
we were building
this system, we were
talking to a lot
of developers of,
yeah, we are building
this cool app.
And we were using PREACT.
And you're going to be--
got Web Components.
And they were kind of surprised.
Because they were asking
questions like, well, wait.
Isn't Web Components an
alternative to frameworks?
JAKE ARCHIBALD: Yeah,
but they're not.
I don't know why you
would think that.
Well, actually, I don't know
why you would think that,
and I think it's
our fault. Well,
I think it's Google's
fault. I think
our messaging suggested
that Web Components are
the same thing as Polymer.
And Polymer is an alternative
to the frameworks.
But web-components,
they're not the same thing.
Web Components are
the lower level
primitive that Polymer uses.
MARIKO KOSAKA: Yeah.
We did use Polymer's custom
element polyfill for Edge.
But for other browsers, we
just shipped the Vanilla web
components
JAKE ARCHIBALD: Yeah.
We used custom elements for
some of our leaf components
that contained the
minimal amount of state.
For instance, this is
the pinch-zoom element.
Just put stuff inside it;
now you can pinch-zoom it.
And it has an API.
We also did this with our
side-by-side slidy thing,
comparison.
MARIKO KOSAKA: We
call it two-up.
JAKE ARCHIBALD: We
call it a two-up, yeah,
because we didn't know
what else to call it.
A fancy range
input, drop target--
we made components for
all these bits and pieces.
MARIKO KOSAKA: Yeah.
So we could have done all
of this in PREACT component
because we were using PREACT.
But using Web Components,
we can take that
and put it into some
other project using
different frameworks or just
use it as is in the project
that you don't really
need framework.
JAKE ARCHIBALD: Yeah.
And if you're open
sourcing client,
Web Components are the
best way to share things
like this, so we did.
We have released a few
of our Web Components
a separate project.
So we'll make more
available as we extract them
from the main app.
We were hoping to release more.
But uh, we've run out of Time--
Whatever.
We used PREACT,
but these things,
they can be used in Vue, Svelte,
Angular, React, whatever.
MARIKO KOSAKA: Yeah.
Most frameworks are
fine with Web Component.
But some have a few rough edges.
So if you are curious, check out
custom-elements-everywhere.com
to see how custom elements work
with whatever the framework you
are using.
JAKE ARCHIBALD: We
also released libraries
for some of the other
things we built,
like a pointer
event helper, thing,
and a webpack plugin for
dealing with asset inlining
and optimization.
So it has been--
well, we're vastly
running out of time--
20-odd minutes, and I haven't
yet mentioned service workers.
MARIKO KOSAKA: A new record
at the very end, very end.
JAKE ARCHIBALD: New
personal record.
Yes, the site does work offline.
Our service worker approach
isn't particularly novel.
We catch the things.
We serve the things.
That means it works offline.
And we also let
the user know when
there's an update available.
MARIKO KOSAKA: Yeah.
But there's one unique
thing about this Squoosh.
That is, when users first visit
the site, we cache all of it
in the next interaction.
But we do not cache any of the
codec, the 300 kilobyte bit,
until the user access
will drop the image
and then get to this view.
JAKE ARCHIBALD: Yeah.
And this was just being kind
to the user's bandwidth.
When the user just
visits the site,
it feels rude to download
the whole 400k app.
So we wait for some
signal from the user
that they're
actually interested.
And that's when we cache
the chunkier parts.
MARIKO KOSAKA: Yeah.
And this is what we love
about the web, right?
Write it once, build
it, and then put it
into phone, tablet, desktop,
with the fraction of the size.
JAKE ARCHIBALD: Of the
equivalent native app, yeah.
And those native apps are only
targeting one operating system.
Whereas, we can
hit loads of them.
And to share it,
just copy the URL--
MARIKO KOSAKA:
That's the best part.
JAKE ARCHIBALD: --and
send it to someone.
MARIKO KOSAKA: That's
the best part of the web.
JAKE ARCHIBALD: Love it.
MARIKO KOSAKA: So if you
want to dig into the code,
it's all on GitHub.
There are lots of
things we want to do.
There are bugs to fix,
codecs we want to include.
And if you're interested, please
come join us to build this up.
We really want this tool to
be really useful to everyone.
JAKE ARCHIBALD: Yes, absolutely.
So thanks for listening.
Now go Squoosh some images.
MARIKO KOSAKA: Please
never say that again.
[APPLAUSE]
Thank you very much.
JAKE ARCHIBALD: I
promise nothing.
Thank you very much.
[MUSIC PLAYING]
