Tip:
Highlight text to annotate it
X
JAKE ARCHIBALD: So back in 1995, JavaScript
was created by Brendan Eich.
And he did it in 10 days, which is pretty crazy, that it's
what most of the web is built of now.
JavaScript is 18 years old now, so it's
legal to drink in some countries.
It's also on Twitter, saying that they
think they've seen JavaScript drunk many years ago,
a lot of the time quite like that.
But in 2010, another team set about making a new language.
And from what we know now of the web-- we
know how the whole web is put together and the kind of tools
we need.
And that team is the Dart team, and here
to talk about it-- big warm welcome
to Seth Ladd and Kasper Lund.
SETH LADD: Thanks Jake.
So we won't be playing the Kenny G.
We don't want you guys to fall asleep.
This is Dart for the modern web developer.
My name is Seth Ladd.
I'm a developer advocate with the Chrome and Dart team.
KASPER LUND: And I'm Kasper Lund.
I'm an engineer here at Google.
I work as a tech lead on the Dart platform.
And before I ventured into Dart territory,
I spent a lot of years on optimizing V8
and the optimizing compiler in there.
SETH LADD: OK.
So many of you know Dart as a language.
And sure it's a structured, scalable, familiar language,
but it's also-- I like to think of it as a batteries included
platform.
There's a great core set of libraries-- things
like collections, things like asynchronous programming,
futures, streams, things like numbers,
booleans, dates, times.
We also ship a collection of productive tools--
a Dart Editor, an analyzer to give you warnings and errors,
a package manager we affectionately call Pub,
because you play darts in a pub.
We also ship a virtual machine which runs Dart code natively.
You can run that VM on a command line or on the server,
and you can also embed it in client browsers.
But probably most importantly, we
ship a Compiler to JavaScript.
So the Dart code you see here today,
and the Dart apps that you'll be writing,
you can compile that down to essentially ECMAScript
5, and run it across modern browsers, desktop and laptop.
You might have heard recently, we launched Dart 1.0.
It was a big milestone for us, hopefully exciting
for you guys.
The big point of this, really--
[APPLAUSE]
SETH LADD: Thank you.
The journey starts here, really, for us.
The big point here, the big take away,
is it's now stability you can count on.
We've been open source since about October 2011,
and gotten tons of feedback from internal developers,
external developers, hackathons, code labs.
And we've collected that all and launched
what is now a stable language, stable core libraries for you
to build production apps on.
So now is the right time to try it.
OK.
So when I said you can use Dart today,
I think I actually mean you can use Dart like in the next hour.
So we're going to do a lightning tour of the syntax structure
and semantics to show you how familiar and easy
it is to get started.
So Dart, by design, is very easy to learn.
We have semi-colons.
We have curly braces.
In fact, we got a little flak when we first launched Dart.
People were like, why don't you make the next big Haskell?
And we're like, we want more than five users.
And so we wanted to make sure that you guys can totally
understand this code.
We've run hackathons and code labs.
People get it.
So familiar, classes.
But just because it's a familiar language
you can dive into in about an hour,
doesn't mean we can't take this opportunity
to introduce new features, for instance, with constructors.
What do we always do in constructors?
This dot x equals x.
This dot y equals y.
This is getting boring.
So Dart says, hey, if the name of the field
is the same as the constructor parameter, just
say, this.strength in this case.
And that will desugar to this.strength equals strength.
Just those nice additions that make this
feel more terse, more scripty.
Speaking of scripty, Dart has operator overriding.
So plus, minus, et cetera, that's in this language.
We also named optional parameters.
Again, it's a structure language.
It may look like the structure language you've been using,
but it has those features that allow
you to have a terse programming experience that you might
be more familiar with than scripting languages.
In fact, this case here, hands is an optional parameter,
but also has a default value of one.
So say more without typing more.
We also support one-line functions.
This is critical.
There's a lot of callbacks going on in web programming,
and a lot of times you want to do
really small, inline function literals.
We support that with the fat arrow syntax.
And we also have string interpolation,
making it very easy and quick to create strings, just dollar
sign, variable, or expression.
And it's right there.
It's a lot easier than doing string builders or string
concatenation.
So Dart is its own language.
It's not just the syntax that masks another syntax.
We have our own clean semantics.
So we want to turn more of these "wat" moments, which I'm not
even sure what's going on here, into the totally
awesome atomic dinosaur nuclear rocks.
We want you to have more on the right, less on the left.
Some examples of the cleaned up semantics that give you
a more logical programming experience in Dart-- only true
is truthy.
There you go.
Now you know the truthy rules.
Good job.
There is no undefined, only null.
Yes, totally, cleaned up.
No type coercion with things like double equals and plus.
So when you try to do something funky, we're going to tell you.
Pop quiz time.
Here's a string "hello" we call .missing,
which obviously does not exist on string.
What would you want to happen at this point?
Undefined?
I don't want undefined.
I want to be told that there's no missing method on string.
And sure enough, at runtime, when you hit code like this,
the program tells you with a very clean error.
So a much more logical programming experience.
If you were to compare 'hello', which is a string,
is it greater than one?
I think this returns false, but actually I'm
not really sure why.
So what would you want this to happen?
You want an error.
You want to be-- hey, man, string
does not have an instance method greater than.
You get told at runtime exactly where the problem happened.
Much more logical programming experience.
Variable scope.
This one's a little bit longer, so take a look at this.
We have a main function.
if(true), there's foo, and then print(foo),
but there's also a top level foo.
So the question I have for you is-- when I run this,
what will it print?
KASPER LUND: Any takers?
SETH LADD: It's 50/50 chance.
Top top-level.
Right.
This prints top-level in Dart, no variable hoisting.
It's a totally logical lexical scope-- lexical
analysis-- of what's going on.
If you hand most developers this code,
they'll be able to understand what's going on here.
Speaking of lexical scope, even this
is lexically scoped in Dart.
This is one of the things that totally tripped me up earlier.
Here's a class AwesomeButton.
And in its constructor you set up a Click Handler.
And when the button is clicked, call this.atomicDinosaurRock.
Well, what is this at this point?
The lexically scoped this that is
an instance of AwesomeButton.
You give most people this code and they will tell you
what method this is calling on, which is, I think,
a pretty big improvement.
So that's a little bit on the semantics,
and a little bit on the syntax.
But Dart is also designed to scale
from just a couple lines of code.
You could certainly write a ten line Dart script
and have it look very scripty.
But you can scale all way up to millions of lines of code.
Now we saw functions.
We saw classes.
We have mixins.
We have interfaces.
I want to talk about libraries, which is a nice piece
to help you modularize your code.
Dart libraries are very flexible.
You simply define a file as a library.
You can import libraries from the core SDK.
You can import libraries from other people, or other files.
And then you can define any number of top level constructs
in a library.
So no more one public class per file thing,
if you come from Java.
So in this case, two classes and even a top level function.
In Dart, you don't have to wrap everything in a class
if you don't want to.
So nice, scalable structure for you to grow.
Hopefully, you guys saw that this
is a language you can start using right away.
But of course, we use Dart to get onto the web.
And to get on the web, you have to compile Dart to JavaScript.
And to do that and to show you how it works,
I'll turn it over to Kasper to tell you all about dart2js.
KASPER LUND: Thank you Seth.
So finally, now I can say something.
It's wonderful.
I'm going to tell you a little bit about how
we compile to efficient JavaScript.
And it's very, very important to us to make sure
that Dart runs really well on all modern browsers,
so we put a lot of effort into that area.
Our goals are fairly simple.
We want to generate small code, we want to generate fast code,
and we want to make sure that we retain
the nice, clean proper Dart semantics while doing so.
So simple goals is a good starting point.
But to do this, and to do it efficiently,
we need a real optimizing compiler,
something that doesn't just do a one
to one translation in a simple way.
We actually need a lot of the neat, modern compiling
techniques we've learned to love from other more
involved projects, like V8.
So we need function inlining.
We need loop-invariant code motion.
We need global value numbering.
We need a lot of these things-- type propagation,
redundant lode elimination, dead code elimination,
and much, much more.
So we need a lot of things in this compiler.
We want to do a good job in optimizing your code,
so you don't have to worry about it.
So let's take a look at a very simple Dart method, just
to give you an impression of what we actually
translate the code to.
Here's a main method that allocates a few points,
and then we compute the distance between these points.
Very simple code.
Luckily, a simple Dart method actually
compiles to relatively simple JavaScript too.
So you will allocate points the same way
as you would expect it to.
The only real difference here is that when
you call the distanceTo method, we actually
encode the arity, the number of parameters passed,
in the method name.
Now why do we do that?
The reason why we do that is because in JavaScript, we're
allowed to pass any number of arguments.
Too few or too many, it doesn't really matter.
But usually it leads to weird and surprising behavior
at runtime if you do that, so we want
to be a little bit stricter there.
So to live by Dart's proper semantics rules there,
we actually have to check that you're
calling with the right number of parameters.
And the fastest way of doing that
is just encoding it in the method name.
If you call with too many parameters,
you'll get an error that that method doesn't exist.
So when you have large applications,
you need some sort of tool to make sure
that you're not actually shipping
too much code to your clients.
In particular, in the set up where
you have a nice, rich set of core libraries
and a nice set of third party libraries you can include,
you want to make sure that whatever
you ship to your clients is only the needed
bits, not all the other stuff.
To do that, we have an implementation
of an algorithm called tree shaking in the compiler.
It works a little something like this.
If you have an application that has a main method, and perhaps
a few other methods close by, foo and baz,
but it's only calling the foo method,
and maybe the foo method in return
calls code pulled in from another library--
the bar method down on the right--
the library may actually have unused parts too like the boo
function here-- we want the dart2js compiler
to actually take this set of methods
like the transitive closure of everything
that you have available to you, and shake it really good
and get all this stuff that you're actually
not using out of the system.
It's a process called tree shaking.
We do that and the result is a lot smaller.
It only contains main, foo, and bar, the needed parts.
So to implement this in the compiler,
we actually go through a few steps.
First we read all your Dart sources.
We don't actually parse them fully.
We don't look into all the methods.
We just look at the structure of your code,
find all the imports, look at the libraries
that you depend on, and read those in too.
When we have everything read in that way,
and we know the structure of your code,
we can actually start doing this first level of tree shaking.
We have two levels.
This is the first one, and this actually
is what we call the resolution tree shaking.
And resolution is the process of not really compiling
code, but just trying to figure out what you're referring to
at certain points in the code.
So it actually starts by looking at the main function,
and look at what kind of classes or instances of which classes
you allocate in there, and which other methods you're calling.
All those methods need to go into a queue
so we can process them, parse them, get them resolved.
And you just keep doing that until nothing new is added
to the queue, and then you're done.
It's relatively simple to do this,
and it gives us a good approximation
of cutting down everything, but only based on method names.
We can do a little bit better.
So once we're done with that, we actually
start the process all over again in the compilation queue.
And this is where we actually will
start looking at what you really put inside your methods,
and do data-flow analysis, and we
will track how types flow through that code.
And that gives us more information
about what you're actually needing to emit.
And we do the last level of the tree shaking at that point.
The end result is that we do a really good job of making sure
that things that you really don't need
are not pulled into your application.
Finally, we actually emit the code to a single JS file.
So you can run it in your browser.
Fairly simple stuff.
SETH LADD: I love this because this is the tools helping me.
I don't need to be crafting my application.
I just let the tool analyze my program, take care of it.
KASPER LUND: That's the way it should be.
So let's take a look at how this actually works in practice.
Just to give you a feel for how dart2js does its magic,
I'm going to dive into a well-known algorithm.
It's a constraint solving algorithm.
The reason why I'm choosing this one
is it's a well understood piece of code.
It's been used to benchmark lots of different language
limitations over the years.
It's actually part of the Octane benchmark
Linus mentioned this morning.
So it's a well-known piece of code.
It is structured.
It has inheritance, and classes, and everything
we need to actually do a good job in making your code
run fast.
So let's take a look at it.
DeltaBlue is a constraint solver.
What does that mean?
Well, basically, it's a fairly abstract thing
that works on constraints on variables.
Constraints can be one way or two way.
There are binary or unary constraints of different kinds.
And they can be used to, for instance,
model the constraints involving laying out something
on your screen.
I'm pretty sure that some of the things you just heard about
from Eric actually use this constraint to think
of that internally when building layouts.
So doesn't lose an implementation of such a beast.
It uses constraints and there's a nice hierarchy of them
with unary and binary constraints and variables.
Let me show you a piece of code from this thing,
to make it a little bit more concrete.
This is a function from the DeltaBlue algorithm.
It's fairly simple.
You don't have to understand all the details here, but just
note that the way it works here is that you take a variable v,
and you try to figure out all the constraints that actually
consume that variable, and put them
in a list that is also passed in as a parameter.
Hopefully this code is reasonably readable to you.
It's Dart code and to me this looks like what I--
SETH LADD: Kind of representative of code a lot
of us would write.
KASPER LUND: Yeah.
So in Dart, we have an optional aesthetic type system.
So you do not have to write the types if you really
don't want to.
Sometimes it's nice to have the document what
a parameter means, which is why I've done it here.
But it's important to us to make it clear
that the types that you put in are not actually used
for up optimization purposes, because we don't really
know if you want to type them in.
So we don't want to force you into typing them in the places
where you don't want to.
So I can go ahead and remove them.
SETH LADD: And they might also be incorrect.
KASPER LUND: They could be incorrect.
Anyway, I've gone ahead and removed the types.
The semantics of this algorithm is exactly the same,
no differences at all.
It's just a little bit shorter, and maybe a little bit harder
to understand.
But anyway, the code is there, it's the same thing,
and this is what we're going to try to optimize.
So first attempt at actually compiling this code
to JavaScript is somewhat large.
So this is the unoptimized version
of the method you just saw.
It compiled to 500 and something characters.
It's a little bit too long.
I'm not even sure you can read it in the back of the hall
here.
But it works.
It has the right semantics.
Everything works as specified.
And it runs reasonably well.
But it's-- I hope you agree-- it's simply not good enough.
We want to do a lot better.
So let's try to dive into how we actually do better
than just this blob of code.
Even though the semantics is really important to us,
we also really care about performance.
So what makes this big?
Well, this is just one of the examples
of why this code is little bit bigger than what we'd like.
So as Seth mentioned, we have strict semantics
about what you can compare to numbers, for instance.
So we don't want to run into issues when you end up
emitting JavaScript code that just ends up comparing numbers
and strengths for instance, because we don't really
want to rely on that behavior.
So in this case we're reading-- see
if I can get this to progress, there we
go-- so we're reading the length of something that probably
is an array, but we're not quite sure.
So we don't know that the length is actually a number.
So before we continue to actually compare
this length against a real number,
we have to make sure that it actually is a number.
So we insert an explicit check in the code that
makes sure that we don't end up relying on this somewhat
surprising behavior of JavaScript,
where you can compare numbers against strengths
and get some result out.
So this adds code-- more checks.
So our challenge is fairly simple.
We want to have clean semantics, unsurprising behavior,
but we do not really want those extra checks
when we're compiling to JavaScript.
So how can we go about doing that?
The trick is right behind me-- global optimizations.
So we really need to do better, and we
need to do more aggressive optimizations in the code
to make it end up being very fast and very good.
So let's look at that.
First up-- Dart is structured.
It has classes.
It has methods.
It has a good structure.
We can actually do whole program analysis.
So when we compile the program, we
can look at every single bit in it,
and we can actually understand what's going on.
That's a huge win for us.
This allows us to actually do code navigation
and great refactoring tools.
But maybe even more dear to my heart
is that we can also do a global compile-time optimizations.
So we can actually analyze your code,
understand the dependencies between things,
maybe, to a certain extent, better than what you actually
care to do yourself, as a developer.
And then we can optimize based on that.
It's pretty powerful.
One of things that we do, and one of the things
that really work well for something like DeltaBlue
and for most applications in general,
is that we infer types.
We compute what types we actually
will see at runtime at different points in the code.
And the way that works is-- Here's
a simple example of how that works.
Main function calls foo, that calls bar,
that calls foo again, basically.
So a bunch of functions calling each other.
So how do we infer types for the parameters of these things?
How do we get the compiler more information?
Well, we start by looking at main.
So it's very simple.
And by analyzing main we can see that foo is actually
called with an integer parameter.
OK, so far, so good.
So we analyze foo, under the assumption
that this called the integer parameter.
Do we learn something from that?
Sure.
Bar is apparently also called with an integer parameter.
So far, so good.
We can finish this game a little bit.
So we end up in bar.
And we realize that if bar is called with an integer
parameter, then it ends up calling foo
with a string interpolated version
of that parameter, which is a string.
So foo is now called with a string
too, so we have to go back and iterate.
So foo is now apparently also called with a string.
That means bar is called with a string too.
And finally, inside the bar method,
we realize that that means that print is called with a string.
So far so good.
All in all, the compiler can actually
conclude that x and y are both either integers or strings.
This is a very, very simple example,
but it actually works really well in practice for large apps
too.
So let's look at DeltaBlue and see
how that actually works there.
It's pretty simple.
So there are a couple of things here
we want to infer types for.
For instance, the two parameters, like v and coll.
And the infer actually does that by looking
at all the coll sites that call addConstraintsConsumingTo.
And we actually learned that v is either null or a variable,
and that coll cannot be null.
It always is a JavaScript array, containing
only subclasses of the class constraint.
That's pretty powerful.
So that's good to know for us.
The rest of the method here can also be analyzed,
and we can learn something about all these constructs in there.
So we can actually get a pretty full picture
of what the types in here are.
So I just listed them here.
You don't have to look at all the details,
but this is very good information for our compiler
to have.
SETH LADD: And it does this without running a program,
just statically looking at the program.
KASPER LUND: This is global analysis at compile time.
So let's make this play to our advantage.
So here's the code again without type
inferencing-- 526 characters.
So first thing off, we know v is either null or a variable.
So we can do a little bit better than just
calling this getter on it.
So we can actually see that it always
has a property determined by, we just fetch it.
Simple stuff.
There are other things that we can
win even more by recognizing.
For instance, v, the variable dot constraints.
Since v is a variable, the constraints in there
is always an array of the constraints.
So we don't have to go through this calling a lengths getter
and calling an index operator.
We can just do the real JavaScript way.
Just fetch the length and just index into the array.
Simple stuff.
Even better, we know that v.constraints, that length
is actually an integer.
So this whole notion of checking whether or not it's a number
goes away.
So that is a helpful thing.
It's starting to improve.
Now the condition that we have in the loop is turning simpler.
We can change the y-limit to a for-loop.
And at that point we're already down to 33%
smaller than the original code I showed you.
We have more to go, but it's pretty simple stuff.
coll is an array.
So this calling add on it, in a weird way,
is not really necessary.
So we can just use the JavaScript push
method to do that for you.
Looks good.
Even further, the t1 is initialized in a simple way,
so that can just move into the for-loop.
And we're down to 41% smaller than the original JS output.
We're starting to get there.
c is known to be a subclasses constraint,
and it cannot be nulled.
We've inferred that.
So this whole notion of checking whether or not c is nulled
before doing a comparison-- this is necessary because of null
and undefined in JavaScript by the way--
we don't have to worry about that because at least c cannot
be null.
So we can simplify the code.
It's a good thing.
Finally, we know that calling is satisfied on c, actually always
returns a boolean.
And true is the only truthy value in Dart,
so usually we have to compare against true before we
branch on it.
But because a boolean is always either true or false,
it's just fine.
We can get rid of that last thing.
And there you have it-- an optimized version
of this method that runs fast.
It's much smaller, but it still has exactly the same semantics.
It's just we've proven we didn't need some of these checks.
So what's that do to performance?
Well, here's the graph of that over time.
So the top line is the native Dart VM
running the DeltaBlue algorithm.
So you see that that's the best performance we have.
And it really comes from the fact
that Dart is designed from the get
go to be an efficient language.
So we have a very good implementation of that.
The next two lines might be more interesting in this context.
The yellowish line is actually V8
running a handwritten version of the DeltaBlue benchmark.
This is the Octane version of the DeltaBlue benchmark
that you might have seen in other places.
As you can see, V8 improves on that over time, slowly,
and that's a very good thing for the entire web.
Maybe more interesting to me, at least,
is that the dart2js generated code
has improved a lot on this benchmark.
It's still the same V8 that runs it,
it's just that the code we generate
is actually a little bit faster than the handwritten version.
How could that be?
Well basically, we do optimization
that you probably don't want to do by hand.
Because we know the entire structure of the app,
we can do some inlining for you, and some code motion and things
like that for your loops that you probably
don't care to do by hand.
So it's a little bit faster.
In general, what we see is that we
were very close to handwritten dart2js performance
on everything.
There are cases where we're faster.
And unfortunately, there are cases
where we're a little bit slower.
So anyway, the performance looks really promising
and it's nice to be able to write in a very clean language
and get good performance.
So let's take a look at how you actually
go about using this Dart thing in a real setting.
SETH LADD: Yeah, thanks Kasper.
So that's dart2js.
A little bit about the workflow--
how and when do you apply that?
Compiling JavaScript of course is great,
but I don't want to do that every time.
I want those quick iterations that the web is known for.
So what does it look like?
Well, we have a build of Chromium
with the Dart virtual machine embedded in it
we've actually called Dartium.
And that's where you spend most of your time.
Those are your quick edit reload cycles.
So let's look at what that feels like.
Here's a build of Dart Editor.
You don't have to use Dart Editor,
but it does ship with the project.
It's a stripped down version of Eclipse.
In fact, I like to show this.
I showed this screen to somebody, and they're like,
oh you have a bug?
You're missing like 78 more preferences in there?
Like, no, no actually, we took those out.
So it's optimized for writing Dart code.
Probably the best way to get started
is-- let's just create a sample app.
So luckily, Eric showed us Polymer before.
Dart has been porting Polymer, polymer.dart.
So we're totally in bed with this web components things.
We think it's the bee's knees.
Here is a sample application.
You get all the skeleton for you.
You've got the HTML.
You've got the custom elements, the CSS.
So let's just run this here to see what it's like.
It's very simple here, but we're going to run in Dartium.
See, it pops right up.
No compiles time needed.
Click me, OK button.
Click counter.
OK, cool.
So it gives you just the core to get started with.
Let's look a little bit at how this application is written.
Hopefully you can see this.
So the polymer element looks pretty
much like what Eric was showing you earlier.
So the HTML aspects of building highly declarative apps
with Dart are very similar to the JavaScript side.
The difference though, instead of implementing the custom
element with JavaScript, you can implement it with Dart.
Dart has classes, so it makes a ton of sense to be able to say,
one class for one custom element.
So this is cool.
And I'll show you a couple other features, because Dart
is structured, and this editor gives you
some nice productivity benefits.
Let's say I want to add a reset count, and then a method here.
OK.
Code completion.
Because we can statically analyze your program,
we know what you can call right here.
And it's real time.
So that's pretty awesome.
Now I'll also go in and infer the local stuff as well.
OK, that's pretty cool.
Now, the other neat thing about statically analyzable language
is it can understand your program.
So let's look at this field count.
Notice how it only highlights the uses of that field.
It's not doing a string search and replace here.
So it leaves out some of the other accounts,
even though obviously it's the same string.
So we can rename.
We can say my account.
And it only renames actual usages of that field, again
the power of a statically analyzable language.
I'm going to undo that because I'm scared of bugs.
OK, cool.
Once you're in an editor, and you
have an actual virtual machine, you can set breakpoints.
So let's go back.
We set a breakpoint there.
We're going to re-run the app.
And if I click the button, and it all works-- yes, OK, great.
So it jumps back to the editor, and you're
in the familiar editing environment,
with full breakpoints.
You can inspect.
This is really cool.
I can jump in here.
I want to inspect this instance.
I don't know if you guys can see this, actually.
Trust me, that says count and then five,
so it's a live object inspector.
So that's really cool.
Let's move on.
This app was kind of neat, but it's also kind of boring.
So I think we can do a little bit better.
In fact, that gray button, I want to make fancier.
So this is where a package management system comes in.
Our package management system, Pub-- and let's
see if we can go here-- has over 500 packages in it
already from our open source community, everything
from server-side stuff to client-side stuff,
to game, crypto, you name it.
Ah, here, look at this-- fancy button.
OK, so our Pub package management system
also has custom elements in it.
So if you like web components, you want to reuse them,
package management system is a great way to do that.
So let's make our button a little fancy.
Let's load up the pubspec.yaml file.
This defines my application and its dependencies.
And certainly I depend on polymer.
Let's depend on fancy_button.
OK, great.
So now the editor is kicking off pub.
He's going to go download it, and install it, and make
sure it all works for my app.
I'm a little impatient, so I'm going
to go over here and show you what that looks like.
We're going to go into click-counter.
And just like regular web components and HTML imports,
you can import the definition of fancy button.
You can say that this button is a fancy button.
Now this is all backed by Dart.
It's a real web component, and it came to us
from that package management system.
Let's see if I indeed made it a little fancier.
So run in Dartium.
And yes, awesome.
OK.
Pink, OK.
So it's a nice demonstration of how
you can use a package management system and reuse code.
Finally, we need to get this out into the wild.
It's one thing to iterate very quickly in Dartium,
but it's another thing to be able to-- find
my original slides, boop, OK-- do your final testing
in production browsers like Firefox and stable Chrome.
And this is our pub build system comes in.
So iterate very fast with Dartium and the editor,
and then run a nice build process.
Now more and more web developers are
moving to a build process that does really nice optimizations.
For one, ours runs dart2js.
You saw some of the nice optimizations
it can actually do with your code.
Tree shaking-- it can minify your app.
If it totally knows your entire application,
it can do a really smart job at minification.
It can also do concatenation.
It can take all your dependencies,
all your custom elements, and jam them all in together
into one single file, making the deployment and performance
very, very good.
In fact, in this particular example,
you saw we had a lot of dependencies, third party
stuff, custom libraries, core libraries.
This app compiles them and gzips down
to smaller than some CSS frameworks you guys use.
So I think it's kind of cool.
And just to show you that that all works,
here we have it in Firefox.
This is Dart, compiled to JavaScript,
using web components deployable to a production browser today.
This stuff is real and you can use it.
And then, when you're finally ready to go,
you have a nice build directory, which
has just the assets, just those minified files,
in a very nice directory you can pick up and put onto the web.
All that concatenation, all the minification, done for you.
KASPER LUND: Nice and simple.
SETH LADD: Nice and simple.
So, how do you get started?
Well, we relaunched the website, and we have a really nice code
lab.
It takes under an hour, walks you through zero to 60.
You get to build a really cool pirate name badge generator.
A really nice way to try Dart, built
for if you don't know anything about Dart.
And I want to leave you with a reminder
that Dart 1.0 is for the modern web.
It's a platform you can use today.
It's easy to get started.
Go to dartlang.org.
We have APIs, code labs, articles, tutorials.
And everything you saw here, even the web component stuff,
all compiles to JavaScript.
So you can write Dart, take advantage
of those great semantics, language, and tools,
and still deploy across the modern web.
So I think with that-- I think we're all ready to go.
Thank you very much.
Appreciate it.