How Google does it

Using Closure Tools for large JavaScript applications

Who is this guy?

Rhys Brett-Bowen

What is Closure Tools

Closure Tools is a set of tools that are used by Google to develop their large JavaScript applications (you know, like GMail, Maps, Docs etc).

Written for Large Applications

  • Well organized
  • Stable - no versioning
  • Well tested - robust
  • Backwards compatible
  • Driven by Google for their products

Some complaints

  • Code is too long... autocomplete, or several coffeescript projects
  • Too large to learn... Namespacing makes it easier
  • No community... Discussion boards and a meetup
  • Looks more like java than javascript... Java has been building large applications for longer
  • Code in the library doesn't use well known performance hacks... We shouldn't need to write in hacks, let the compiler do it for us
  • Requires a build step...

Build Tools

The Tools

  • Compiler - like Uglify or YUI compiler
  • Library - like Dojo or YUI Library
  • Templates - work on client side or server side (java)
  • Linter - lints to Google specifications and can even fix some style issues like jslint or jshint
  • Stylesheets - css preprocessor like less or sass

Closure Compiler

Closure Compiler

Advanced Optimizations

  • Aggressive renaming
  • Dead code removal
  • Function inlining
  • sourcemaps

What does this mean?

  • More code - less bytes
  • We can be verbose - the code won't be
  • We can use longer name(space)s
  • Unused code is removed
  • Code will run faster

Closure Compiler

Static Analysis - type cheking

Means mistakes are caught before run time where they may go unnoticed

Coming soon - JSWhiz: Static Analysis for memory managment

It's awesome!

Prove it!

What's the catch

What's the catch?

Code must be AO compatible
  • foo['bar'] !== foo.bar
  • {foo: 'bar'} becomes {a: 'bar'}
  • but {'foo': 'bar'} stays {'foo': 'bar'}
Use property when internal only and strings when value is external. Read more

What's the catch?

Code must be AO compatible
var Class = function() {};
Class.number = 1;
  • must provide Class.number to use externally (enums)
  • goog.provide('Class.Number')
    /** @enum {number} */
    Class.Number = {
        ONE: 1,
        TWO: 2
    };
  • provide access through prototype
  • put under another namespace

What about using libraries that aren't compatible...

Closure Library

Closure Library

Built for use with the compiler
  • Namespaced & Functional
  • Classical inheritance
  • Type annotations
  • Dependency management
  • goog.ui.Component

Namespaced & Functional

  • Namespaced to separate code
  • Namespacing makes it easier to find functionality (not all on the $ object)
  • Functional makes it easier to override functionality

Classical inheritance

goog.provide('Class');
goog.require('Super');
/**
 * @constructor
 * @extends {Super}
 */
Class = function() {
    goog.base(this);
};
goog.inherits(Class, Super);

/**
 * @inheritDoc
 */
Class.prototype.method = function(arg) {
    return goog.base(this, 'method', arg);
};

Classical inheritance

Looks long, but autocomplete!
  • Code organization
  • Easy override functions
  • Well understood
  • Performance!

Type annotations

  • Annotating
  • Optional... mostly
  • Don't need to be explicit
/**
 * don't have to do this:
 * @param {{a: string, b: number}} param1
 * this will do to begin with:
 * @param {Object} param2
 */

Dependency management

goog.provide('my.name.space');
goog.require('other.name.space');

uncompiled

run calcdeps.py to let the application know where to download dependencies from

compiled

compiler will include all dependencies in a single file in the correct order
Want Dependency Injection? try Loader
Want to try it on your non-closure project? Mantri

goog.ui.component

goog.ui.component

goog.ui.component

Sounds great, but we use jQuery

jQuery has a great interface

$('.class').children().addClass('classChilren');
            

Closure Library...

  • Namespacing great for discoverability
  • Functional instead of OO
but...

goog.array.forEach(
    goog.dom.getChildren(goog.dom.getElementByClass('class')),
        function(child) {
            goog.dom.classes.add(child, 'classChildren');
        });
            

Learn a new library?

or just use an interface, the closure library is great to build upon.

$('.class').children().addClass('classChilren');
            
The G!

Using the G

goog.require('G');
  • Just like jQuery - almost
  • use $$.method instead of $.method
  • $$.setSelectorEngine(engine) for better selector support
  • Even some (simple) jQuery plugins may work - just add to $$.fn

How about a fancy MV* thingy?

PlastronJS or este.js
AngularJS Advanced mode may be coming soon - or just use externs

Closure Templates

Closure Templates

  • Compiled
  • Extensible functions
  • Client and Server-side
  • Translatable strings

Closure Templates

/**
 * Greets a person using "Hello" by default.
 * @param name The name of the person.
 */
{template .helloName}
    {msg desc="hello string"}Hello {$name}!{/msg}
{/template}

/**
 * Greets a person and optionally a list of other people.
 * @param additionalNames The additional names to greet. May be an empty list.
 */
{template .helloNames}
  // Greet the people.
  {foreach $additionalName in $additionalNames}
    {call .helloName}
      {param name: $additionalName /}
    {/call}
    {if not isLast($additionalName)}
      <br>  // break after every line except the last
    {/if}
  {ifempty}
    {msg desc="shown when done greeting"}No people to greet.{/msg}
  {/foreach}
{/template}

Closure Linter

Closure Linter

Linting

gjslint -r js

...
Found 17 errors, including 1 new errors, in 7 files (0 files OK).

... The script can be run by executing: fixjsstyle -r js
fixjsstyle -r js

gjslint -r js
...
Found 8 errors, including 0 new errors, in 5 files (2 files OK).

Closure Stylesheets

lint for style

Closure Stylesheets

Variables
@def WHITE #FFF
Extensible functions
width: add(LEFT, RIGHT);
Mixins
@defmixin size(h, w) {
    height: h;
    width: w;
}
@mixin size(100px, 100px);
Conditionals
@if (BROWSER_IE){}

Class minification

  • Use Closure Stylesheets (coming soon in plovr)
  • goog.getCssName() around class names in the code
  • {css className} in templates
  • done!

What's next?

Closure Please

All the latest and greatest tools including:
You should follow it too @ClosurePlease

Buy this book!

Questions?

How Google Does It