Introducing Closure Linter

Tuesday, August 31, 2010 | 3:45 PM

When collaborating with lots of engineers as we do here at Google, it’s important to keep a consistent coding style. To this end, we recently open sourced the Google JavaScript Style Guide.

Today we’re happy to announce we’re open sourcing a tool that will help you follow that style guide with minimal manual effort - the Closure Linter.

Take for example, this code:

var x = 10
var y=20;

for(var i = 0;i < 10; i++ ) {
x += i;
y -= i;
}

var z = [10, 20,];

x = y + z[0]
+ 10;

When we run gjslint --strict fixme.js we get
Line 1, E:0010: (New error) Missing semicolon at end of line
Line 2, E:0002: Missing space before "="
Line 2, E:0002: Missing space after "="
Line 4, E:0002: Missing space before "("
Line 4, E:0002: Missing space after ";" in for statement
Line 4, E:0001: Extra space before ")"
Line 6, E:0006: (New error) Wrong indentation: expected any of {2} but got 3
Line 9, E:0121: Illegal comma at end of array literal
Line 12, E:0120: Binary operator should go on previous line "+"
Found 9 errors, including 2 new errors, in 1 files (0 files OK).

Even better, if we run fixjsstyle --strict fixme.js, 7 of the 9 errors are automatically fixed for us!

We hope you can use the Closure Linter to improve your style consistency while simultaneously saving time. More information on how to get started can be found on the How to Use Closure Linter page.

We welcome comments and questions in the discussion forum.

This Var is My Var

Monday, August 30, 2010 | 1:34 PM

The Closure Compiler you know is very different than the Closure Compiler that’s familiar to Google engineers. The defaults at Google are much stricter. It forbids duplicate global variable declarations, performs type-checking, and restricts a number of other patterns that are common in non-Closure-style JavaScript. By default, the “Google build” of Closure Compiler is like running the "open source build" of Closure Compiler with the --warning_level VERBOSE flag.

Why? Almost every contributor to Closure Tools works on web applications. We want to be able to share code. Part of that means we should be able to fix the shared code, and integrate it into all our apps quickly so that, for example, fixes for IE9 will make it out to production within a reasonable time. To integrate those changes safely, we need to be confident that they won’t break anything. Compiler restrictions help us do that. Sometimes those restrictions are obvious...sometimes less so.

Suppose Joey writes some library code:

Joey.prototype.eatHotDogs = function(hotDogs) {
for (i = 0; i < hotDogs.length; i++) {
this.eat(hotDogs[i]);
}
};

Next summer, Nathan writes an application to feed Joey HotDogs by the boxful:

Nathan.prototype.runHotDogContest = function(player, boxes) {
for (i = 0; i < boxes.length; i++) {
player.eatHotDogs(this.unpackHotDogs(boxes[i]));
}
};

Surprisingly, when Nathan runs his code in a browser, it tries to feed Joey an infinite number of hot dogs and crashes the browser.

The problem, of course, is that JavaScript "helpfully" declares variables for you if you forgot. No one declared i, so a variable i got magicked into the global scope. When Joey originally wrote his code, he tested it and it worked fine. But when Nathan tried to use it, he found that eatHotDogs() was "resetting" the i in his loop every time he called it.

In this example, Nathan was directly calling the problematic method, and the bug was relatively easy to spot. In the general case, these bugs are "non-localized" —missing var in one file may trigger a bug in an unrelated file that hasn’t been touched in years. Or it may cause a bug years later in unrelated new code. For a library shared across many codebases, non-localized bugs can stop progress quickly because it’s so hard to know where to start looking.

In VERBOSE mode, Closure Compiler enforces that all variables must be declared with the var or function or catch keywords. Global variables may only be declared once. The Google JS style guide has naming conventions to make these collisions even less likely.

This rule has some corollaries that have a big impact on how we write JavaScript. For one, there must be a way to declare variables that are "owned" by the surrounding page, and not by the code under compilation. So Closure Compiler has externs files, which allow you to declare external variables. Conversely, external variables may not conflict with your code. If you use the default externs, you will not be able to name a variable Node because it will conflict with DOM Nodes.

Try running Closure Compiler with --warning_level=VERBOSE mode and see what you find in your code!