SURMA SURMA: Hey, I'm Surma.
I work as a developer advocate
for the Chrome team in London,
and I am here to talk about
my most recent mini project
that I did, which
is that I built
a proof of concepts
PWA but using WordPress
as the back end.
And so in my title
I have two words--
WordPress and PWA-- and I
feel like I should probably
justify both of them.
So let's start
with the easy one.
Why PWA?
Because most people, I
think, when they hear PWA,
they think about
installability, about getting
into the home screen.
And that's what something you
necessarily want for your blog.
Like, you don't really
care about your blog
being an app on your home screen
and triggering that banner.
So maybe the name is a
little bit misleading.
It's not a progressive web app.
In this case, it's more
of a progressive web site.
And that's OK.
Because PWA doesn't
really necessarily mean
that you need to be app like.
And also I think a lot of
people never thought about this
or approached this because
they were like, hey,
my CMS has been around
since way before the acronym
PWA was a thing.
So obviously it can't do PWA.
And that is wrong, because
you can use all these new PWA
technologies with very old
systems that are already
in place.
And that's what I
basically wanted
to prove with this project--
have an existing CMS, have
an existing infrastructure,
and still turn it into a PWA.
And I think the bottom
line, as Chris said
earlier today, it is about
drastically improving the user
experience.
And because you all know,
flaky networks are a pain,
slowing web sites are really
awful, and this can help.
And all decisions that you
make during development
should be made from
the user's perspective.
So the second word in
my title is WordPress,
and the question might
be, why WordPress?
Why not Joomla, or Drupal,
or any other kind of CMS
that is out there?
And maybe I should have used
another acronym in my title,
and just call it CMS plus
PWA, a because that just rolls
off the tongue right away.
And it doesn't matter.
Like, this talk is not going
to be WordPress specific.
Its about having
an existing CMS,
and all techniques that I show
will be WordPress agnostic
because I didn't need to
know anything about WordPres
really took to make this happen.
The reason why I did
choose WordPress, though,
because they are by
many standards the most
published CMS out there.
They have a 60% market share
in the CMS world so to speak
and they have a stat that
says that 27% of websites
are WordPress websites.
Just take that number in--
27% of websites.
But just to be clear--
if you are locked
in to your weird home in house
pearl written custom built CMS,
this talk is still
useful to you.
Like, I have not known
anything about WordPress
at the start of this
project, and I still
don't know much,
because I didn't
need to know much to make
the entire thing happen,
and to have good performance
and have all these PWA features.
So to talk a little but about
what WordPress is currently
doing in the PWA
world, I would like
to invite Dan Walmsley on
the stage from Automattic.
DANIEL WALMSLEY: Hi, my
name is Dan Walmsley,
and I am a code
wrangler at Automattic.
And I couldn't
help but overhear,
like he sort of glossed
over it, but he's like--
a very old system--
and it's only like
12, 13 years old.
But we live in technology,
and things move fast.
So Automattic is the
company behind WordPress.com
and WordPress VIP and
WooCommerce and Jetpack which
is a plugin for WordPress.
And Automattic was
founded about 12 years ago
with the goal of accelerating
WordPress adoption.
And I think you could argue
that we didn't do too badly.
You'll notice that
this is 28%, Surma
has not updated his slide.
I forgive him.
This number grows very quickly.
But it's now 28%.
So I think one of the reasons
behind the growth of WordPress
and the success of WordPress
is that our mission is
to democratize publishing.
And this is sort of a
mission that is deliberately
very ambitious in scope, and it
is underscored by a philosophy.
And this philosophy has
really stood the test of time.
It says that we should always
be making software that's
incredibly easy to
use, to install,
that it should ship
with sane defaults.
And I think crucially,
we should always
be trying to reach out to people
who may have been left behind--
web users who, for reasons
of language or geography
or the kind of browser they
use or the kind of network
they're on, have not been able
to use the web as effectively
as everyone else.
And so over the
years, we've engaged
in some really
ambitious projects
to try and live by
that philosophy.
Starting with the famous
five minute install.
Back when content management
systems took 15 steps
in some arcane wizard
to get installed,
we just asked you a couple
of questions and everything
else was done for you.
WordPress-- every release comes
out in 80 languages or more,
growing every year.
We have a responsive
and accessible UI,
which is really important
for the over 1 billion people
in the world living
with disabilities,
and we scale from a USB stick
to a massive installation
like WordPress.com, which is
one install of WordPress serving
millions of websites from data
centers all over the world.
So every year brings
new challenges,
new ways to live
by this philosophy,
and 2017 is no different.
So in 2017, uses expect to
be able to create rich web
sites with no
programming required,
and with no messing
about with text
based widgets or
custom elements.
And so we are creating the
Gutenberg Editor, which
is coming out in
WordPress 5, and it
enables really rich
block-based editing
that's fully pluggable
and usable by people.
And I think equally
important in 2017--
it's the year of
web fragmentation,
which is a huge challenge we've
been hearing about all day.
But basically, people
are accessing the web
on more devices, on more kinds
of networks, than ever before.
And this is like a really
important challenge for us
as web developers,
because most of us
are using the web
on fast computers,
on fast and reliable networks,
and it's not always clear to us
who we're leaving behind.
And of course, with
WordPress, we're
always asking, who
are we leaving behind?
How can we help them
access the web better?
Now I want to pause
just for a second
and talk about Jetpack
because I mentioned that
in passing at the start.
So Jetpack is the plugin
that powers WordPress.com
and is also available to
download on any WordPress web
site.
And why jet pack
is important today
is because it powers over 5
billion page views a month.
This is just part of
the scale of WordPress.
It's one of the more
popular plug-ins,
and it powers
WordPress.com and VIP
and all of our other products.
And so Jetpack has this
incredible reach, which
is both an amazing opportunity
and a really big responsibility
to make sure that the people
who are using jet pack
are not left behind, are
having a great experience.
And I also want to talk
about the work we've
done with Google in the past.
So Automattic and Google
were both pitching in
on the HTTTPS everywhere
initiative, alongside Let's
Encrypt, alongside
the EFF, and this
has borne incredible fruit.
We now have, I
think, 10x the number
of websites in the
top million versus
two years ago running
HTTPS, which is important
because it's a
foundational building
block of progressive web apps.
And also, we
collaborated with Google
to create the AMP
plug-in for WordPress,
which I think is probably
by far the biggest
way that our content is
rendered on the web, powering
billions of page views a month.
So this partnership between
Automattic and WordPress
has been really powerful.
So we got together and
decided to investigate, well,
could progressive web apps
provide a great experience
not just on a site by site basis
but in a cross-cutting basis?
Could you actually put
progressive web technologies
into Jetpack and get
them out in front
of people in a way that
works with any theme,
with any other plug-in,
out of the box,
so that we can get these
benefits to people?
And so we have some really
exciting preliminary results.
So what Surma has been
talking about today
has been how you might
take an individual theme
or an individual site and tailor
it to use progressive web apps.
What we're talking
about is basically
one click with a site running
this experimental version
of pack, and you get almost 100s
across the board in lighthouse.
And what we've seen is on slow
3G with an image rich home
page, say a photo blog, you
can get 10x or 15x, the load
performance on that
site, sort of the time
to your first content pane.
Now, how do we do this?
There's a lot of hackery
going on under the hood.
But a lot of it is sort
of traditional web hackery
about how you do deferred
and async scripts,
and inlining scripts, and
these other things, combined
with progressive web apps,
which let us kind of mangle
the first page load to make
it super fast, and then
in the background
load all the remaining
assets for the other
pages so that you
can have a traditional
web experience that
starts and loads quickly.
So that's just
some of the things
that we've discovered that are
possible with progressive web
Apps in WordPress.
And I would love to
turn it back to Surma
for some of the nuts and bolts.
Cheers.
SURMA SURMA: All right.
Enough of the
inspirational speak.
Let's get down to
the nitty gritty.
So this is the
blog that I built.
It had a lot of features.
I said to myself--
I want it to be really
fast on the first load.
I want it to have
nice transitions.
I want it to have a really
bandwidth conservative approach
to loading all these things,
work offline, full PWA.
But what I also
wanted to do was I
wanted to target
low end devices,
because I wanted to
make sure-- it's a blog.
It should not require a
flagship phone to render a blog.
So basically all my
development that I did
happened on a Moto G4, which
is the phone that we always
advocate for as a baseline
for low end devices.
It's not very expensive,
you can order it on Amazon,
and basically my workstation
just looked like this,
with always my development
server running open
on the phone, so I could see
that the animation would still
be running smooth, even on a
constrained phone like this.
Along the process, I basically
documented everything.
So whenever I did
something, I wrote in a doc.
As you can see, it ended
up with like 11 pages
of me just ranting really.
And this document
is really R-rated
and not fit for public
consumption at all.
So I will not had that out.
What I will do though
is I do a YouTube series
called Supercharged.
And I am working on the
next installation, where
I will basically cover
one feature of this blog
per episode and just
do a step by step thing
on how you could
implement this feature
or how I implemented
my features,
and maybe you could use
those to use it on your blog.
So definitely stay tuned on
that one-- like and subscribe
our YouTube channel please.
Either way.
Let's get started.
So if you are a
theme author or you
have a theme running
on your WordPress blog,
it's important to me that
you know that this is not
an all or nothing thing.
You can cherry pick the features
that you deem more important
for your blog.
Like, you don't have to do
it the same way that I did.
This is a proof of concept.
I wanted to show it
is possible, but there
are many different
solutions that might work
or might work better for
you, and you don't have
to do everything the same way.
Again, bottom line--
improve your UX.
So let's get started with
the first thing, a feature
that is very important to me--
it's the time to first
content full paint, the TTFCP.
It's a great acronym.
It basically means
how long does it
take from the second I hit
Enter or just navigate to a page
until the content is on screen?
It doesn't need to
be fully styled,
it doesn't need to
be interactive yet,
but the content
needs to be there.
And for blogs specifically,
this is very important,
because the content
is your content.
It's the thing that you
want to ship to your users.
And I set myself
a goal to get that
under one second on 3G,
which is fairly ambitious.
But it can be done.
And this is the
feature that you really
notice when you're on vacation,
and like on hotel Wi-Fi
when you're roaming on 2G,
when you're in a country
where bandwidth is still scarce.
So statistics have shown that
when you make users wait,
and we have heard this
today a couple of times,
if you make them wait,
they're going to bail on you.
So your mission should be get
on screen as fast as possible.
Get them busy.
Get them engaged with your
site one way or the other.
And I achieved this in
this case by putting
everything for the first content
full paint into my index HTML.
That basically means if the
user only gets the index HTML
and then the
networks breaks down,
the site will still be
useful for the user.
And this is basically
what it looks like.
On the left side, you
have the full load,
on the right side you
only have the index HTML.
And yes, it's a
great experience.
I mean, all my
assets are missing.
But the content is there.
It's still useful to the user.
They can start reading.
And if the loading is still
going on in the background,
this visual will enhance into
the full experience by the time
the assets come in.
And this is definitely better
than staring at a blank screen
for 20 seconds.
So that's why I wanted
to take this approach.
And here is a screen
recording from the Moto G4.
It's the wrong
device frame, I know,
but I didn't have any
other, so this is actually
a proper screen recording
from the phone in my pocket.
And you can see, once
I tap on my bookmark,
this is clear cache, no
ServiceWorker, over a 3G Wi-Fi
that we have in the office.
It simulates a 3G with
packet loss and delay.
And you can see I'm on
screen really quickly.
But the thing is,
loading continues
to happen in the background
for more than 20 seconds.
It doesn't matter though,
because the user doesn't
notice.
They're happy reading
at this point.
And this is the mindset
that I want people to adopt
more when developing web sites.
[INAUDIBLE] busy.
You can be pretty big,
actually, most likely,
it can be a big or website as
long as you get the user busy
and are on screen
fairly quickly.
Here is a video of a reload when
the [INAUDIBLE] is in place.
It's practically instantaneous.
There's things I
could do better here,
but with ServiceWorker stuff
like this gets really, really
fast.
So how did I do this?
Basically I started with
a WordPress Theme that
is completely empty, and then
just incrementally added things
that I needed for
the first paints,
and only added the things that
I needed for the first paint.
And the nice thing about
WordPress, or basically
any kind of CMS that is
PHP driven, for example,
is you are basically doing
server site rendering
by default because PHP--
when you have
these PHP tags that
inject content into your markup,
that's server site rendering.
And server site rendering is
crucial for the first content
full paint, because you need
to have the content in there
already.
And so it's really
easy to get a good--
or it's fairly easy to get a
good first content full paint
with something like WordPress.
For the styles, I separate
myself into two categories.
I had the critical styles and
what I called lazy styles.
That critical styles get in
lines into the documents,
and the lazy styles
get lazy loaded.
And that's something that
JetPack does already.
I think Dan mentioned
that in his segment.
So my lazy loader
basically looks
for elements of have
the lazy load class,
and loads the elements
that are inside those.
The interesting bit about
this is that for the styles,
I use a no script tag, and
that means that if JavaScript
is disabled or not running,
that the link tags inside it
will still get loaded.
It won't load as performantly
as with my lazy loader,
but it's basically a progressive
enhancement for lazy loading.
If you have JavaScript, you get
the better loading performance.
If you don't, you will still
get the full experience,
just loaded a little
bit slower, and I
think it's a really nice trick.
So just to separate
what is a critical style
and what is a lazy
style, critical styles
are just like the very basic
coloring and visual space
allocation.
So you can see there's no
embellishments, there's
no real, like, little things
flying around or anything.
Only the space is allocated.
So you can see the header is
not there, but the space for it
has been taken up
by the element.
But the styles for the text
and the background image
are all in the lazy
styles, because they're not
as important.
Second feature I want to
talk about is ES6 modules.
I wanted to use ES6 modules
through and through.
Why?
Because I think that's what
the future is going to be like.
We're just going to use
ES6 modules everywhere,
and because the
import syntax just
allow you to decouple your
code in a much nicer way,
and modules are deferred
by default, which is also
something that was
really important to me
to have a better
loading experience.
As you might know,
not all browsers
have ES6 module support,
and even back then even less
had support for it.
So I went for a
pretty bold strategy.
I just said, in
development, I'm just
going to use the browser
that have support for it,
and use no bundling, no
transpiling, and just native
ES6 module loading, and then
once I go to production,
I'm just going to rely on
Babel to transpile to SystemJS
and use SystemJS
in those browsers,
and then I'm going to basically
use the null module tag
to let the browser decide
which version to use.
So it is pretty ambitious.
It's actually kind of ignorance.
But it worked out.
So I can say, you all
should be doing this,
because it worked for me,
so it has to work for you.
At the same time, my colleague
Sergio wrote an article about--
where he did a
really in-depth study
how performant unbundled loading
currently is, and basically
his conclusion was we can't stop
bundling because it will impact
your loading performance.
And I really urge you to
look into the Bit.ly link
and read the articles,
because it's really good.
But also, it kind
of only is true
when your module
tree is decently big.
And for me, that
wasn't the case.
I had like a dependency tree
about four levels deep, maybe,
and a total of 15 modules.
So I said to myself, I
might be able to get away
without the bundling, and
so I continued down my path.
So let's talk about how I do
load my modules with my two
branch approach.
Basically, I have a PHP
array with all the modules
that I need, and then I have
a PHP4 each loop to generate
the module script tags, and
then I have another for loop
where I just turn it
into a SystemJZ calls.
The one has no module, the
other one has type module.
So a browser can
decide which version
to use depending on if they
have module support or not.
But also, as I said, I had a
dependency tree depth of four,
which if you have
high round trip times,
can still end up
being quite costly.
So I had an idea how I can
reduce that without having
to resort to bundling.
And there was a tweet
that I Sadly didn't find,
but basically it says, whatever
smart thing you think you did,
game developers have been
doing it for 10 years.
And I think there
is a lot of truth
to that, because game
developers, in my opinion,
are the pioneers
of architecture.
They usually have
very, very big teams,
and have to work in parallel
towards the same goal
and that requires the team
to have a very clear image
of the architecture.
And I think there's
lots of things
that we as web
developers can learn,
because we're just starting to
do big architecture on the web.
And so the thing that
I did, and it's not
going to blow anyone's mind
in here, is a message bus.
Woo.
The concept basically
is just that it
allows me to send messages.
That's a message bus.
But it turned out that this
simple concept actually turned
into a performance
primitive, and actually made
my developer experience
pretty great as well.
Here's an example.
So I have a pending
comments module,
because the block has support
for sent for writing comments
while you're offline and using
background sync to dispatch
them once you are online.
So with that, the
pending commons
has a dependency on my
background sync manager module
that I wrote.
It also has a dependency
on to my router model
because it needs to
know when I switch
from article A to
article B to update
the view of how many
comments are still pending.
And the router, in turn, has
a dependency on the analytics,
because it needs to tell
the analytics that we
switched a page, and we want to
update our view counter by one.
So as you can see here, this
by itself is a depth of three.
With a message bus,
which is a global thing,
is just basically
inlined, because it's
a very small piece
of code, we basically
remove all these layers, and
just have independent models.
You basically end up
writing micro services
in the front end.
And that turned out to be a
really nice experience for me
as a developer.
Additionally, I actually
extended the message bus
to span all my tab
and the ServiceWorker.
So it means if the ServiceWorker
used the message bus
and sent a message, it
would go to all the tabs.
I'm going to talk about later
on why this is really useful.
But here's an example--
my router has a
navigate function,
and when that gets called,
it does like the fade out
and switch and fade in and all
these little things and push
states, but in the
end it does a dispatch
on my PubSubHub, the
message bus that I wrote.
And turn on the analytics module
does all the typical analytics
loading, and in the end it
subscribes a navigation event,
and whenever it
gets one, it just
gets-- sets the
page to that URL,
and increases and sends
a page view event.
So these two modules
now are completely
oblivious of each other's
existence, and yet it works.
And I think that's really cool.
One thing that is
worth noting is
that no browser has support
for ES6 modules in workers.
So that means for
every piece of code
that I want to share
between my ServiceWorker
and my main thread
I had to resort back
to public-- or to globals.
Which is not nice,
but in the end,
it will be fixed at some point.
And for now it works, I guess.
The next big feature--
bandwidth conservation.
As I said, I wanted
to put everything
into index HTML for your
first content full paint.
But if you then end up with
an 8 megabyte index HTML,
you're not going to be fast.
So this is where I have adopted
a different mindset of what
I consider necessary
and what I consider big.
Because in emerging markets, or
especially in emerging markets,
people still often
pay by the megabyte.
It actually costs them
money to look at your blog.
So you have to be aware of that.
So the first load of my
blog is 230 kilobytes,
which I personally actually
think is still a little bit too
big, and it's mostly
due to the fact
that four different
weights of my web font.
So if I had variable
fonts, that would be great.
But for now, I actually
have 140 kilobytes of fonts.
And the rest is pretty small.
And here is one of the
major misconceptions,
and I hinted at it earlier, your
PWA doesn't need to be small.
You can load more data
in the background.
Your initial load
needs to be small.
And as I said, I have
everything in my index HTML.
So I can get on
screen very quickly.
And my index HTML
is 10 kilobytes.
So even over 2G, that
would be pretty fast.
My [INAUDIBLE] once
ServiceWorker is in place,
is one kilobyte, and
that's because I've
caching headers
and ServiceWorker,
and that's where
you want to be at.
But this is now the thing--
I have ServiceWorker,
and this is probably
the biggest feature I want to
talk about, and that's offline.
It makes resistance
against flaky networks--
I, in this case, hand-rolled
my ServiceWorker,
because I didn't want to
use yet another thing thing.
So I didn't look at Workbox
also when I was doing this.
Workbox was also pretty new.
In retrospect, it would have
been a good fit, honestly.
But in this case
I wrote it myself.
But the thing is, I
wrote a theme, as I said.
So if other people
start doing this,
we're going to end
up in a space where
we're going to have the
one ServiceWorker per theme
problem, which might
end up conflicting.
So at some point,
CMS assets will
have to start thinking about
providing a core service
worker from the CMS
itself and allowing themes
to tap into that rather than
every theme writing their own.
But as I said, for
now, I wrote my own.
It's part of the theme.
And the first problem here
is that the ServiceWorker
file is part of a
theme, and therefore
is in the folder of the
theme, and by default only
gets control of requests
to the theme folder,
but I obviously
want more than that.
So my generic solution was
to use the ServiceWorker
allowed header that allowed me--
allowed the ServiceWorker file
to take control
of a broader scope
than it was originally allowed.
And then it just inlined my
ServiceWorker file with PHP.
With WordPress
you could actually
use the mounting mechanism
or redirect mechanism,
but this would be a generic
solution that works everywhere.
My strategy was basically
just catch everything.
But it turns out
that I really did
get requests for everything,
because I'm now at the route,
and that means I would
have to accept some stuff.
And that would be things like
the admin panel, which I really
didn't want to cache.
The theme preview inside
the admin panel power
that I really didn't
want to cache.
And general and some
external resources that
were kind of tripping me up.
And that ends up with
an on fetch handler
that actually gets a bit
messy with earlier returns.
So again, this would
be an opportunity
for CMS is to provide
a function for you that
figures out for you if you
should be caching this or not.
My strategy that I think
[? Jaffe ?] mentioned earlier
is stale while revalidate.
That means I just sent a request
to the network and the cache,
and if there's
something in the cache,
I use it straight
away, no matter if it's
stale or not, just to be quick.
And then I can update the
cache in the background.
One thing it is super important
if you use this strategy is,
make sure you're e tags work,
because otherwise to revalidate
will become fairly expensive.
So every request will
all send a request
of the network to
check if there's
a newer version at the server.
And if it's not, it
should be super cheap.
But it will only be cheap
if you're e tags work.
So make sure that it actually--
you see this in Chrome,
lots of three or fours,
lots of very cheap requests.
But as I said, sometimes
there is something newer.
Sometimes your cache
will be updated,
and the question is,
what do you do then?
And this is where the second
opportunity for my message
bus into play.
So this is my stale while
revalidate implementation,
where I, as I said, I go
to network and the cache.
And then I wait for both the
network response and the cache
response, and figure
out if they are changed,
and I use e tags
to figure that out.
And if that's actually the case
that there is a new resource,
I once again send a
message to my message bus.
But this is running
into the ServiceWorker,
and that means that
this message will be
broadcast to all the open tabs.
And that means that
every tab independently
now has one of these
microservers again running
that subscribes to this events
and can check if the updated
resource is either a core
item like the header,
the footer, the header
image, whatever, or is
the item currently on display.
And if that's the case, it
will fade in a green banner,
as you can see in
the screen shot,
and asking the user to reload.
And I think this is--
it's not the ideal
experience in terms of user,
because they still
have to reload,
but it's something that's
very easy and very safe to do.
The last feature I want to
talk about is background sync.
The thing I did, so you can
comment while you're offline,
and because not
navigator.onLine is a lie.
Don't rely on it.
If it's false, you know
that you're offline.
If it's true, you don't
really know if you're online.
So you should always have
a ServiceWorker in place
to capture these
kind of requests.
The recipe I used
is pretty simple.
I basically cache my post
requests for the comment
in the ServiceWorker
and I synthesize
the successful response.
So I tried out what WordPress
does if you actually
send a comment to
an online version,
and it just redirects you
back to the blog post, which
kind of makes sense.
And so the ServiceWorker just
synthesizes that response,
and I store the actual
request in the queue in IDB,
triggered background sync,
whenever the background
sync comes back to me and
says, I think I'm online,
we can try to actually
send these things, I just
go to the queue in IDB and
send up the requests again.
Here is-- so if you remember,
this is my early returns.
There is one early
return for comments.
And the post
comments, as I said,
it's just-- it
doesn't do anything
if you don't have
background support.
Then it just goes straight
to the networks and fails,
or it doesn't.
And otherwise I just
generate the 302,
I redirect back
to the blog post,
and put everything in my
queue and the ServiceWorker.
Now here's the thing
that frightens me a bit.
First of all, it's open source.
That's a little scary.
Like I would love for
you to look at this
and if you're a theme author,
maybe rip out some features,
put it into your theme.
But I'm not going to give
you the hosted URL, which
is just one of my tiny
servers hosting this thing.
So I'm assuming it will
go down, but go nuts.
Give it a try.
Let me know what you think.
I would love to hear it.
And now for the last
couple of minutes,
I would like to invite
Dan back on stage
so we can talk about the
future of press and PWAs.
DANIEL WALMSLEY:
OK, so you've heard
like a lot of exciting
information here today,
and I'm sure, because
it's late afternoon,
your brains was super
receptive, and it wasn't just
all flowing out your ears.
But you know I do
want to just say
that what we've discovered
through this process
was actually even more
exciting than what
I thought were going to find.
Like, I thought we would
find one or two things that
are like, that's a cool hack.
But really, like the whole
surface area of this whole PWA
space is amazingly exciting
for content rich web sites.
And so what I would
love for everyone to do
is if you are interested
in broad adoption
of this technology,
think about WordPress
as a platform for getting
that adoption and check
out the Jetpack
branch that we linked
to earlier in the slides.
And if you are a WordPress
developer interested
in this technology, do
exactly that same thing.
Go check out that
branch, and see
if you can learn a bit
about progressive web apps,
and what they could mean for
the users around the world.
And I just want to thank Google
for the amazing opportunity
to get up here and
explore this technology,
and in 2018, we're are
going to be rolling
these features as they're
ready into Jetpack
and across the web.
Thanks very much
SURMA SURMA: Thank you.
