[MUSIC PLAYING]
CHRIS THOMPSON: Good afternoon, everybody.
My name is Chris Thompson.
I'm a software engineer on the Firebase team.
Day to day, I work on the Emulator Suite,
and so I'm excited to be here today
to tell you all about why I think the Emulator Suite is
the fastest, safest, and no-cost way to develop on Firebase.
So today, we announced the Emulator Suite
was graduating from beta to general availability.
What does that mean exactly?
Well, we have Firestore, Realtime Database, Storage,
Hosting, and Authentication, in addition to
the Emulator Suite UI that have graduated to GA today.
And there's three additional emulators
that are going to stay in beta for now.
They are the Functions, Cloud Pub/Sub,
and Extensions emulators.
This effort started in 2018, so it's
been a long road to get here.
And I'm excited to finally be GA.
So before I go to the agenda, just a show of hands,
how many people here have used the Emulator Suite before?
A pretty good amount.
How many have never used the Emulator Suite before?
OK.
And how many are just waiting patiently for lunch?
Good stuff.
So before we go any further, a quick agenda--
so we're going to talk about what is the Emulator Suite
today.
What is it good for?
We're going to take a look at running a project locally.
We'll take a look at the Emulator Suite UI.
And finally, we'll test making and testing some changes
live today.
So first off, what is the Emulator Suite?
The Emulator Suite is a set of binaries that run locally
on your machine that create a near-hermetic environment
and enable things like local development, prototyping,
unit testing, and even continuous integration.
So today I'm going to demo some of the features that
make the Emulator Suite fast and secure.
If we could switch to the demo, please.
I'm going to set the Mirror button there.
So today I'm going to use the completed Codelab
application that we developed as part of our tutorial.
I recommend everyone check out the Codelab.
It takes under an hour and covers
three out of the five emulators that are going GA today.
Prerequisites for this demo real quick--
I have Node Package Manager installed.
I have the Firebase command line interface installed,
and I've logged in under my account.
And finally, we'll be using Git to pull down
the changes or the app.
So first up, I'm going to do a git clone .com/firebase.
This is going to pull down a completed
app for us to use here today.
And one additional step, I'm going
to navigate to my functions directory
and install our npm dependencies.
Now, I think the Wi-Fi is running at about 2 megabits
per second here.
So this might take a second.
While this is chugging along, the next step, rather than
dive right into the code, we're just
going to execute the application and take
a look at what we have.
Perfect.
So I'm going to use the Firebase Emulator.
Let's do a clear.
Firebase emulators:start, and I'm going to pass it my project
ID flag.
And I'm going to import from our seed directory.
This is going to give us some seed data that gets us rolling.
While this is starting up, I want
to point out the special project ID that I used here today
with the demo prefix.
In the Firebase Console, it's not
possible to create a project with the demo prefix.
And so it tells the Emulator Suite
that we want to work completely offline.
And it's going to sub in some configs locally
rather than fetch them from the Firebase Console using my login
credentials.
And we see that the app is now running.
We'll take a look at it here on localhost 5000.
So everything you see here is running locally on this laptop.
And the initial state is populated
from that seed directory.
This is an example of a typical e-commerce app.
So I can log in in the top right.
I can add some items to my cart.
And we can see in the top right the card is
updated with the number of items and the new total.
So the magic of the cart happens--
there's a calculate cart cloud function
that's running locally that's triggered whenever we add items
to the cart.
And we'll take a look at that a little bit later.
The other thing I want to showcase
today is the Emulator Suite UI.
You can see the top.
We can see at the top we have a series of emulators.
Some of them are running right now.
Some of them are not.
Let's take a look at the Authentication Emulator tab.
You can see here this is the record
that I created when I performed the anonymous login
a second ago.
If we take a look at our Firestore,
these are the items that we imported
from the seed directory.
And the items have a description, image URL, name,
price, and this is the card that I created when
I added some items to my cart.
It's got a number of items, owner ID, total price.
The last tab I want to show you today is our Logs tab.
And this contains logs for all the running emulators.
And this is the first place we're going
to look when debugging our app.
So diving into the code, let me load this up.
And there's two files that we care about today--
first being the public directory, index.html,
and second being index.js from the functions directory.
So taking a look at index.html, this
is your typical, exactly what you'd expect.
This is the HTML landing page for our app.
And I'll point out here that the body is mostly empty
because we're populating this with JavaScript
as we read from Firestore.
On the index.js side, we have our calculateCart function.
And this is responsible for listening to changes
to our cart in Firestore and updating it
so we can see it in the app.
So to prove that this is a live demo,
I'm going to make a quick change here.
I'm going to save this.
And this is automatically going to be picked up
by our running Emulator Suite.
And let's go here.
Do a refresh.
Nothing happened.
I think what might be happening here
is the emulators are a little bit shy today.
So we can give them a quick round of applause.
Get them hyped up.
[APPLAUSE]
There we go.
Perfect.
There's our change.
And so I got this change--
I loaded this change by refreshing the site
and not reloading our Emulator Suite, which is still running.
And you can see that the initial state
with the card in the top right is still preserved.
So I know what you're thinking right now.
You're thinking, HTML hot reload, that's great.
But I came a long way to New York to be here today,
so you're going to have to do a little bit better than that.
I hear you.
Let's take a look at our index.js.
So again, this calculateCart is responsible for listening
to writes to our cart, the items in our cart in Firestore.
And let's say I want to make a change here.
I'm going to add a last updated timestamp to our cart and items
so that I know for debugging purposes
the last time they were updated.
So I'll declare a constant, lastUpdated.
And using the change object above,
I'm going to get the reference for the cart item.
And just for the heck of it, I'm going to throw it in here.
This is our cartRef.
Perfect.
So we take a look at our Emulator Suite UI.
You see the bottom of the logs that this function change
is hot reloaded.
It's ready to go on our Functions emulator.
And so let's add some items to our cart.
If I scroll up here, we'll see that the cart is updated.
We have four items now--
51.96.
Everything's looking good.
And if we take a look at our cart here,
we can see that the last updated timestamp is here,
just like we expected.
But something unexpected is happening here.
What we accidentally introduced was a function loop.
And so because the function is listening to changes
to Firestore, when it writes the last updated timestamp, itself,
it triggers the function.
And this is a not uncommon thing to encounter
when using Cloud Functions.
And so I will point out there, too,
that there are some protections against this that I gingerly
stepped over in order to make this work.
So the typical solution here is we
want to detect if this is not the first time that we're
in this function.
So we can do that because our app can only
add items to the cart.
It can't update or delete them.
We can simply check if the item existed before.
So if the item existed before, this
must be at least the second time that we're through the loop.
I'm going to save this.
It automatically gets picked up.
And our last update is stable.
So back to the slides, please.
So just to linger on this point a little bit longer,
let's say we had 1 QPS of users who
are adding items to their cart.
That means we're introducing a new function
loop roughly once per second.
And let's say that function loop executes once a second.
So after about one hour of time, we're burning about $23
per hour in compute.
And after a whole day, we have about $560 per hour in compute.
But we saved all of this by running our functions locally,
and testing locally, and vetting them
before going to production.
So to recap, what did we cover today?
We covered what is the Emulator Suite and what is it good for.
We downloaded and ran an existing application
within 60 seconds.
I think that's fair.
And we updated our function, introduced a bug,
and caught the bug, and fixed it.
I invite everybody to check out the emulator collab at the URL
here, firebase.google. com/codelabs/firebase-emulator.
Thank you all.
[APPLAUSE]
[MUSIC PLAYING]