tag:blogger.com,1999:blog-24379098741603538362024-02-25T13:13:25.917-08:00Closure Tools BlogUnknownnoreply@blogger.comBlogger23125tag:blogger.com,1999:blog-2437909874160353836.post-71888348626573095942017-01-05T09:02:00.000-08:002017-01-05T09:02:17.813-08:00Common pitfalls when using typedefs in externs<div dir="ltr" style="font-size: small; text-align: left;" trbidi="on">
When writing typedefs, it is easy to make mistakes and write definitions that are not supported by Closure Compiler.
The source of the issue is that type checking for typedefs is unfortunately quite loose, especially for typedefs defined in externs files.
As a result, the compiler does not warn about some malformed definitions.
Then, the user thinks their code is getting typechecked when it is not.
(Checking is stricter with the <a href="https://github.com/google/closure-compiler/wiki/Using-NTI-(new-type-inference)">new type checker</a>.
You may want to consider it for your project.)
<br />
<br />
The goal of this post is to show the common pitfalls, and suggest correct ways to define typedefs.
This will alleviate the problem until the typedef-related checks are enforced by the compiler.
<br />
<h2>
What is a namespace?</h2>
<br />
In addition to the built-in types such as <span style="font-family: "courier new" , "courier" , monospace;">number</span>, <span style="font-family: "courier new" , "courier" , monospace;">Object</span>, etc, a programmer can define and use their own types: classes, interfaces, records, and typedefs.
If a user-defined type is defined as a property of an object, this object must be a namespace.
For example:
<br />
<pre>/**
* An object-literal namespace
* @const
*/
var ns = {};
/**
* A new class Foo as a namespace property
* @constructor
*/
ns.Foo = function() {};
/**
* This is also OK. The new class is not defined as a property.
* @constructor
*/
function Foo() {}
</pre>
<br />
Object literals defined with <span style="font-family: "courier new" , "courier" , monospace;">@const</span> are namespaces.
So are classes and functions.
Typedefs are <b>not</b> namespaces.
<br />
<h2>
Do not define new types on typedefs</h2>
<br />
Since a typedef is not a namespace, you should not define new types on a typedef.
The compiler may not warn, but it will not check such types correctly.
<br />
<pre>// Externs
/** @typedef {{prop1: number, prop2: string}} */
var MyType;
/**
* Wrong!
* @constructor
*/
MyType.Foo = function() {};
// Source
/** @param {MyType} x */
function f(x) {
var /** null */ n;
n = new MyType.Foo; // Typechecked
n = new x.Foo; // Typed as unknown
}
</pre>
You can see that <span style="font-family: "courier new" , "courier" , monospace;">MyType.Foo</span> is not properly checked.
It is checked when we refer to it directly, but not on a formal parameter <span style="font-family: "courier new" , "courier" , monospace;">x</span> typed <span style="font-family: "courier new" , "courier" , monospace;">MyType</span>.
You can try this example using the <a href="https://closure-compiler-debugger.appspot.com/#input0%3D%252F**%2520%2540param%2520%257BMyType%257D%2520x%2520*%252F%250Afunction%2520f(x)%2520%257B%250A%2520%2520var%2520%252F**%2520null%2520*%252F%2520n%253B%250A%2520%2520n%2520%253D%2520new%2520MyType.Foo%253B%2520%252F%252F%2520Typechecked%250A%2520%2520n%2520%253D%2520new%2520x.Foo%253B%2520%252F%252F%2520Typed%2520as%2520unknown%250A%257D%250A%26input1%26conformanceConfig%26externs%3D%252F**%2520%2540typedef%2520%257B%257Bprop1%253A%2520number%252C%2520prop2%253A%2520string%257D%257D%2520*%252F%250Avar%2520MyType%253B%250A%250A%252F**%250A%2520*%2520Wrong!%250A%2520*%2520%2540constructor%250A%2520*%252F%250AMyType.Foo%2520%253D%2520function()%2520%257B%257D%253B%26refasterjs-template%26includeDefaultExterns%3D1%26CHECK_SYMBOLS%3D1%26CHECK_TYPES%3D1%26CLOSURE_PASS%3D1%26MISSING_PROPERTIES%3D1%26PRESERVE_TYPE_ANNOTATIONS%3D1%26PRETTY_PRINT%3D1%26TRANSPILE%3D1">
debugger.</a>
Note that if we had defined <span style="font-family: "courier new" , "courier" , monospace;">MyType</span> in the source instead of the externs, the compiler <a href="https://closure-compiler-debugger.appspot.com/#input0%3D%252F**%2520%2540typedef%2520%257B%257Bprop1%253A%2520number%252C%2520prop2%253A%2520string%257D%257D%2520*%252F%250Avar%2520MyType%253B%250A%250A%252F**%250A%2520*%2520Wrong!%250A%2520*%2520%2540constructor%250A%2520*%252F%250AMyType.Foo%2520%253D%2520function()%2520%257B%257D%253B%250A%26input1%26conformanceConfig%26externs%26refasterjs-template%26includeDefaultExterns%3D1%26CHECK_SYMBOLS%3D1%26CHECK_TYPES%3D1%26CLOSURE_PASS%3D1%26MISSING_PROPERTIES%3D1%26PRESERVE_TYPE_ANNOTATIONS%3D1%26PRETTY_PRINT%3D1%26TRANSPILE%3D1">
would have warned.</a>
<br />
<h2>
What about other properties on typedefs?</h2>
<br />
We saw that defining new types on typedefs is not supported.
More generally, you should not define any extra properties on typedefs, even if these properties are not creating new types.
The compiler may not warn, but it will not check these properties correctly.
<br />
<br />
A common mistake people make is to define a typedef of a record type, and then define extra properties on it.
The compiler will silently not typecheck in this case.
<br />
<pre>// Externs
/** @typedef {{prop1: number, prop2: string}} */
var MyType;
/**
* Wrong!
* @type {number}
*/
MyType.prop3;
/**
* Wrong!
* @type {number}
*/
MyType.prototype.prop4;
// Source
/** @param {MyType} x */
function f(x) {
var /** null */ n;
n = x.prop3; // Typed as unknown
n = x.prop4; // Typed as unknown
}
</pre>
The correct way to do this is with @record.
<br />
<pre>/** @record */
function MyType() {}
/** @type {number} */
MyType.prototype.prop1;
/** @type {string} */
MyType.prototype.prop2;
/** @type {number} */
MyType.prototype.prop3;
/** @type {number} */
MyType.prototype.prop4;
</pre>
A related mistake is to define a typedef of a function, and then define extra properties.
Again, some typechecking will silently not happen.
<br />
<pre>// Externs
/** @typedef {function(number):number} */
var MyType;
/**
* Wrong!
* @type {number}
*/
MyType.prop3;
/**
* Wrong!
* @type {number}
*/
MyType.prototype.prop4;
// Source
/** @param {MyType} x */
function f(x) {
var /** null */ n;
n = x.prop3; // Typed as unknown
n = x.prop4; // Typed as unknown
}
</pre>
Closure Compiler does not fully support functions with properties.
They are representable in the type system, but there is no notation to write such types.<br />
<br />
There is a somewhat hacky way to express functions with properties.
Even though it is not entirely correct, it provides some type checking.
We first define a typedef <span style="font-family: "courier new" , "courier" , monospace;">MyType</span> of the function type.
Then, we define a variable or property of type <span style="font-family: "courier new" , "courier" , monospace;">MyType</span>,
and then we define the extra properties on the variable.
<br />
<pre>// Externs
/** @typedef {function(number):number} */
var MyType;
/** @type {MyType} */
var MyType_;
/** @type {number} */
MyType_.prop3;
/** @type {number} */
MyType_.prop4;
</pre>
Defining functions with properties this way has two caveats.
First, even though these properties should only be defined on <span style="font-family: "courier new" , "courier" , monospace;">MyType</span>, they are defined on more functions, so <a href="https://closure-compiler-debugger.appspot.com/#input0%3D%252F**%2520%2540param%2520%257Bfunction(number)%253Astring%257D%2520x%2520*%252F%250Afunction%2520f(x)%2520%257B%250A%2520%2520return%2520x.prop4%253B%2520%252F%252F%2520no%2520warning%250A%257D%26input1%26conformanceConfig%26externs%3D%252F**%2520%2540typedef%2520%257Bfunction(number)%253Anumber%257D%2520*%252F%250Avar%2520MyType%253B%250A%250A%252F**%2520%2540type%2520%257BMyType%257D%2520*%252F%250Avar%2520MyType_%253B%250A%250A%252F**%2520%2540type%2520%257Bnumber%257D%2520*%252F%250AMyType_.prop3%253B%250A%250A%252F**%2520%2540type%2520%257Bnumber%257D%2520*%252F%250AMyType_.prop4%253B%250A%26refasterjs-template%26includeDefaultExterns%3D1%26CHECK_SYMBOLS%3D1%26CHECK_TYPES%3D1%26CLOSURE_PASS%3D1%26MISSING_PROPERTIES%3D1%26PRESERVE_TYPE_ANNOTATIONS%3D1%26PRETTY_PRINT%3D1%26TRANSPILE%3D1">
the compiler misses some inexistent-property warnings.</a>
Second, the old and the new type checker behave differently on such types.
In this <a href="https://closure-compiler-debugger.appspot.com/#input0%3D%252F**%2520%2540param%2520%257Bfunction(string)%253Astring%257D%2520x%2520*%252F%250Afunction%2520f(x)%2520%257B%250A%2520%2520return%2520x.prop4%253B%250A%257D%26input1%26conformanceConfig%26externs%3D%252F**%2520%2540typedef%2520%257Bfunction(number)%253Anumber%257D%2520*%252F%250Avar%2520MyType%253B%250A%250A%252F**%2520%2540type%2520%257BMyType%257D%2520*%252F%250Avar%2520MyType_%253B%250A%250A%252F**%2520%2540type%2520%257Bnumber%257D%2520*%252F%250AMyType_.prop3%253B%250A%250A%252F**%2520%2540type%2520%257Bnumber%257D%2520*%252F%250AMyType_.prop4%253B%250A%26refasterjs-template%26includeDefaultExterns%3D1%26CHECK_SYMBOLS%3D1%26CHECK_TYPES%3D1%26CHECK_TYPES_NEW_INFERENCE%3D1%26CLOSURE_PASS%3D1%26MISSING_PROPERTIES%3D1%26PRESERVE_TYPE_ANNOTATIONS%3D1%26PRETTY_PRINT%3D1%26TRANSPILE%3D1">
example,</a> the new type checker does not warn but the old one does.
Despite these caveats, this is an acceptable workaround to declare types of functions with properties.
<br />
<span class="post-author"><br /></span>
<span class="post-author">Posted by Dimitris Vardoulakis, Software Engineer on the Closure Compiler team</span>
</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2437909874160353836.post-49490655230966863872016-10-20T05:47:00.000-07:002016-10-20T05:47:24.200-07:00Polymer & Closure Compiler in GulpThis is an adjunct article <a href="https://www.youtube.com/watch?v=CplQdSo7lkE">to a talk given at the Polymer Summit London</a> in October 2016. It describes how to add Closure Compiler to the build steps of a Polymer project.<br />
<br />
<div style="text-align: center;">
<iframe allowfullscreen="" frameborder="0" height="270" src="https://www.youtube.com/embed/CplQdSo7lkE?showinfo=0" width="480"></iframe>
</div>
<h4>
<span style="background-color: white; color: #298dbe; font-family: "arial" , "helvetica" , sans-serif; font-size: medium; font-weight: normal; white-space: pre-wrap;">Wait, what?</span></h4>
<a href="https://medium.com/dev-channel/closure-compiler-for-js-fun-and-profit-3b6c99f4fd31">Google’s Closure Compiler</a> is a JavaScript optimizer, typechecker and minifier. It also transpiles modern JS into ES5. It can make you more productive by providing typechecking, static analysis, and a warm fuzzy feeling that a robot has read and validated your code 👍<br />
<br />
<a href="https://www.polymer-project.org/">Polymer</a>, on the other hand, is a library that helps you build modern HTML web experiences with Web Components — specifically, reusable custom elements. There’s also a vast library of elements available already 🎉<br />
<br />
Closure Compiler and Polymer are great together. You can write Polymer that is compiled, giving you almost immediate compile-time feedback—are your types correct? — and reducing your code size. You’ll also be able to use use <a href="http://kangax.github.io/compat-table/es6/">all that modern JS hotness</a> 🔥, regardless of which browser you’re targeting.<br />
<div>
<h4>
<span style="background-color: white; color: #298dbe; font-family: "arial" , "helvetica" , sans-serif; font-size: medium; font-weight: normal; white-space: pre-wrap;">The Final Product</span></h4>
<div>
If you’d like to check out the final product, a working sample app with a single Polymer element- <a href="https://github.com/samthor/polymer-closure">head over to GitHub</a>. But if you’d like to work through the steps, read on! 📕</div>
</div>
<div>
<h4>
<span style="color: #298dbe; font-family: "arial" , "helvetica" , sans-serif; font-size: medium;"><span style="background-color: white; font-weight: normal; white-space: pre-wrap;">Your First Build</span></span></h4>
Let’s assume that you have no build steps. None! Well, maybe you use <a href="https://github.com/Polymer/vulcanize">vulcanize</a>, to bring together your custom elements. Let’s assume you have an index file like this, containing your elements-</div>
<div>
<br /></div>
<div>
<div dir="ltr" style="background-color: white; font-family: Arial, Helvetica, sans-serif; font-size: 12px; line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<pre style="background-color: #f8f8f8; border-radius: 3px; border: 1px solid rgb(204, 204, 204); color: #007000; font-size: 9pt; line-height: 15px; overflow: auto; padding: 4px 8px; word-break: normal; word-wrap: normal;"><span style="font-family: "courier new" , "courier" , monospace; line-height: 22.08px; white-space: pre-wrap;"><link href="elements/my-element.html" rel="import">
<link href="elements/my-other-element.html" rel="import"></span></pre>
</div>
</div>
<div>
<h4>
<span style="color: #298dbe; font-family: "arial" , "helvetica" , sans-serif;"><span style="background-color: white; font-weight: normal; white-space: pre-wrap;">Get the dependencies</span></span></h4>
For this task, we’ll use Gulp, and the JavaScript version of Closure Compiler. Start by installing dependencies-<br />
<br />
<div dir="ltr" style="background-color: white; font-family: Arial, Helvetica, sans-serif; font-size: 12px; line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<pre style="background-color: #f8f8f8; border-radius: 3px; border: 1px solid rgb(204, 204, 204); color: #007000; font-size: 9pt; line-height: 15px; overflow: auto; padding: 4px 8px; word-break: normal; word-wrap: normal;"><span style="font-family: "courier new" , "courier" , monospace; line-height: 22.08px; white-space: pre-wrap;">npm install --save-dev gulp gulp-vulcanize gulp-crisper google-closure-compiler-js</span></pre>
</div>
<h4>
<span style="color: #298dbe; font-family: "arial" , "helvetica" , sans-serif;"><span style="background-color: white; font-weight: normal; white-space: pre-wrap;">#1: Merge and split your code</span></span></h4>
Let’s create or update your <a href="http://gulpjs.com/">Gulp configuration file</a> to merge together your elements (it’s called gulpfile.js). This vulcanizes your code, bringing it all together: it then uses crisper to split just the HTML and JS apart.<br />
<br />
<script src="https://gist.github.com/samthor/3337ed284c1cbb8c7348d3b9e9527612.js"></script>
Note that we don’t include the Polymer source code itself — it’s explicitly excluded. This is because Polymer, at least in the 1.x branch, does not compile well with Closure Compiler. You shouldn’t worry though — the point here is to typecheck <b>your</b> code, not Polymer itself.</div>
<div>
<h4>
<span style="color: #298dbe; font-family: "arial" , "helvetica" , sans-serif;"><span style="background-color: white; font-weight: normal; white-space: pre-wrap;">#2: Compile the JS</span></span></h4>
Now, we just need one more step to compile your elements. At the bottom of your Gulp configuration file, add this compile step. This depends on your previous merge step, and produces a minified output file.<br />
<br />
<script src="https://gist.github.com/samthor/b331861b0e1e043ca9ab4b861db87d53.js"></script>
It has a few nuances. We need to load the Polymer externs manually, as Closure Compiler does not include them by default. You’ll also need to set polymerPass to true, and provide some sensible defaults.<br />
<br />
Now, run gulp compile in a terminal. If your Polymer code is perfect — don’t worry, no-one’s is to begin with — you won’t see any warnings.</div>
<div>
<h4>
<span style="color: #298dbe; font-family: "arial" , "helvetica" , sans-serif;"><span style="background-color: white; font-weight: normal; white-space: pre-wrap;">#3 (Optional): Additional reading</span></span></h4>
If you’d like to speed up your builds, there’s also a <a href="https://github.com/google/closure-compiler">Java version of Closure Compiler</a>. And if you’d like to decrease your code size and increase performance, Closure Compiler also has an <span style="font-family: "courier new" , "courier" , monospace;">ADVANCED</span> mode. However, most Polymer elements won’t compile ⚠️ without changes. To find out more, read <a href="http://closuretools.blogspot.com/2016/06/using-polymer-with-closure-compiler-part-1.html">Using Polymer with Closure Compiler</a>.</div>
<div>
<h4>
<span style="color: #298dbe; font-family: "arial" , "helvetica" , sans-serif;"><span style="background-color: white; font-weight: normal; white-space: pre-wrap;">#4: Use the output</span></span></h4>
You’re almost done! To quickly see your work in an actual browser, you can create a HTML file which includes all four dependencies —the Web Components polyfill, Polymer itself, your vulcanized HTML, <b>and your minified, compiled, transpiled JavaScript</b> 👏<br />
<br />
<pre style="background-color: #f8f8f8; border-radius: 3px; border: 1px solid rgb(204, 204, 204); color: #007000; font-size: 9pt; line-height: 15px; overflow: auto; padding: 4px 8px; word-break: normal; word-wrap: normal;"><span style="font-family: "courier new" , "courier" , monospace; line-height: 22.08px; white-space: pre-wrap;"><head>
<!-- Order is important! -->
<script src="bower_components/webcomponentsjs/webcomponents-lite.min.js"></script>
<link rel="import" href="bower_components/polymer/polymer.html">
<link rel="import" href="dest/elements.html">
<script src="dest/elements.min.js"></script>
</head></span></pre>
<br />
Rather than four dependencies, you could also add an extra Gulp task which merges the JS or HTML together (especially if you don’t want to ship your <span style="font-family: "courier new" , "courier" , monospace;">bower_components</span> directory). Don’t try to compile again at this point — just concatenating the files together works fine.</div>
<div>
<h3>
<span style="color: black; display: inline; float: none; font-family: "times"; font-size: small; font-style: normal; font-weight: normal; letter-spacing: normal; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"></span></h3>
<h4 style="-webkit-text-stroke-width: 0px; color: black; font-family: Times; font-size: medium; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;">
<span style="color: #298dbe; font-family: "arial" , "helvetica" , sans-serif; font-size: medium;"><span style="background-color: white; font-weight: normal; white-space: pre-wrap;">Congratulations!</span></span></h4>
You’ve compiled your elements, and gained an awesome 👑 static compile step. Go reward yourself with a donut! 🍩</div>
<p>
<span class="post-author">Posted by Sam Thorogood, Developer Programs Engineer at Google.</span>
</p>Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-2437909874160353836.post-21710837456590642552016-08-31T19:26:00.001-07:002016-08-31T19:26:57.637-07:00Closure Compiler in JavaScript<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "arial" , "helvetica" , sans-serif;"><i>Cross-posted from the <a href="https://developers.googleblog.com/2016/08/closure-compiler-in-javascript.html">Google Developers Blog</a></i></span></span><br />
<span style="background-color: transparent; color: black; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "arial" , "helvetica" , sans-serif;"><i><br /></i></span></span>
<span style="color: black; font-family: "arial" , "helvetica" , sans-serif; line-height: 1.38; vertical-align: baseline; white-space: pre-wrap;">The Closure Compiler was originally released, in Java, </span><a href="http://googlecode.blogspot.com/2009/11/introducing-closure-tools.html" style="font-family: arial, helvetica, sans-serif; line-height: 1.38; text-decoration: none;"><span style="color: #1155cc; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">back in 2009</span></a><span style="color: black; font-family: "arial" , "helvetica" , sans-serif; line-height: 1.38; vertical-align: baseline; white-space: pre-wrap;">. Today, we're announcing </span><a href="https://github.com/google/closure-compiler-js" style="font-family: arial, helvetica, sans-serif; line-height: 1.38; text-decoration: none;"><span style="color: #1155cc; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">the very same Closure Compiler is now available in pure JavaScript</span></a><span style="color: black; font-family: "arial" , "helvetica" , sans-serif; line-height: 1.38; vertical-align: baseline; white-space: pre-wrap;">, for use without Java. It's designed to run under NodeJS with support for some popular build tools.</span><br />
<span style="color: black; font-family: "arial" , "helvetica" , sans-serif; line-height: 1.38; vertical-align: baseline; white-space: pre-wrap;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif; line-height: 1.38; white-space: pre-wrap;">If you've not heard of the Closure Compiler, it's a JavaScript optimizer, transpiler and typechecker, which compiles your code into a high-performance, minified version. Nearly every web frontend at Google uses it to serve the smallest, fastest code possible.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif; line-height: 1.38; white-space: pre-wrap;"><br /></span>
<span style="color: black; font-family: "arial" , "helvetica" , sans-serif; line-height: 1.38; vertical-align: baseline; white-space: pre-wrap;">It supports new features in ES2015, such as let, const, arrow functions, and provides polyfills for ES2015 methods not supported everywhere. To help you write better, maintainable and scalable code, the compiler also checks syntax, correct use of types, and provides warnings for many JavaScript gotchas. To find out more about the compiler itself, including tutorials, head to </span><a href="https://developers.google.com/closure/compiler/" style="font-family: arial, helvetica, sans-serif; line-height: 1.38; text-decoration: none;"><span style="color: #1155cc; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Google Developers</span></a><span style="color: black; font-family: "arial" , "helvetica" , sans-serif; line-height: 1.38; vertical-align: baseline; white-space: pre-wrap;">.</span></div>
<b style="font-weight: normal;"><span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-align: center;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "arial" , "helvetica" , sans-serif;"><img height="176" src="https://lh5.googleusercontent.com/tKY7Ci0RogFvTqINnX_nhkOocYcO7FaFmMtFhakvwbCwN_UZZuZvK4GrIlutEw49u7l1ZjCMZdGEOWyWqgs5-CcHy_s29vwFPdRiBdP5BI140fD0_Yc-XcxdY1n2tJMupdBLy5Hh" style="border: none; transform: rotate(0rad);" width="176" /></span></span></div>
<b style="font-weight: normal;"><span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span></b>
<br />
<h4 style="line-height: 1.38; margin-bottom: 0pt; margin-top: 10pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="background-color: white; color: #298dbe; font-family: "arial" , "helvetica" , sans-serif; line-height: 1.5em;"><span style="font-size: large;">How does this work?</span></span></span></h4>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: "arial" , "helvetica" , sans-serif; line-height: 1.38; white-space: pre-wrap;"><br /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: "arial" , "helvetica" , sans-serif; line-height: 1.38; white-space: pre-wrap;">This isn't a rewrite of Closure in JavaScript. Instead, we compile the Java source to JS to run under Node, or even inside a plain old browser. Every post or resource you see about Closure Compiler will also apply to this version.</span><br />
<span style="color: black; font-family: "arial" , "helvetica" , sans-serif; line-height: 1.38; vertical-align: baseline; white-space: pre-wrap;"><br /></span>
<span style="color: black; font-family: "arial" , "helvetica" , sans-serif; line-height: 1.38; vertical-align: baseline; white-space: pre-wrap;">To find out more about Closure Compiler's internals, be sure to </span><a href="http://closuretools.blogspot.com/2016/03/high-level-overview-of-compilation-job.html" style="font-family: arial, helvetica, sans-serif; line-height: 1.38; text-decoration: none;"><span style="color: #1155cc; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">check out this post by Dimitris</span></a><span style="color: black; font-family: "arial" , "helvetica" , sans-serif; line-height: 1.38; vertical-align: baseline; white-space: pre-wrap;"> (who works on the Closure team at Google), other posts on the </span><a href="http://closuretools.blogspot.com/" style="font-family: arial, helvetica, sans-serif; line-height: 1.38; text-decoration: none;"><span style="color: #1155cc; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Closure Tools</span></a><span style="color: black; font-family: "arial" , "helvetica" , sans-serif; line-height: 1.38; vertical-align: baseline; white-space: pre-wrap;"> blog, </span><a href="https://medium.com/@samthor/closure-compiler-for-js-fun-and-profit-3b6c99f4fd31" style="font-family: arial, helvetica, sans-serif; line-height: 1.38; text-decoration: none;"><span style="color: #1155cc; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">or read an exploratory post</span></a><span style="color: black; font-family: "arial" , "helvetica" , sans-serif; line-height: 1.38; vertical-align: baseline; white-space: pre-wrap;"> about Closure and how it can help your project in 2016.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif; line-height: 1.38; white-space: pre-wrap;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif; line-height: 1.38; white-space: pre-wrap;">Note that the JS version is experimental. It may not perform in the same way as the native Java version, but we believe it's an interesting new addition to the compiler landscape, and the Closure team will be working to improve and support it over time.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif; line-height: 1.38; white-space: pre-wrap;"><br /></span>
<span style="background-color: white; color: #298dbe; font-family: "arial" , "helvetica" , sans-serif; font-size: large; line-height: 1.5em; white-space: pre-wrap;">How can I use it?</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "arial" , "helvetica" , sans-serif;">To include the JS version of Closure Compiler in your project, you should add it as a dependency of your project via NPM-
</span></span><br />
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;"></span></span><br />
<pre style="background-color: #f8f8f8; border-radius: 3px; border: 1px solid rgb(204, 204, 204); line-height: 15px; overflow: auto; padding: 4px 8px; word-break: normal; word-wrap: normal;"><span style="font-family: "courier new" , "courier" , monospace; line-height: 22.08px; white-space: pre-wrap;">npm install --save-dev google-closure-compiler-js</span></pre>
</div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: "arial" , "helvetica" , sans-serif;"><span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">To then use the compiler with </span><a href="https://github.com/gulpjs/gulp" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-style: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Gulp</span></a><span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, you can add a task like this-</span></span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: "courier new" , "courier" , monospace;"><span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"></span></span><br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<pre style="background-color: #f8f8f8; border-radius: 3px; border: 1px solid rgb(204, 204, 204); line-height: 15px; overflow: auto; padding: 4px 8px; word-break: normal; word-wrap: normal;"><div dir="ltr" style="font-family: Times; line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; white-space: normal;">
<span style="font-family: "courier new" , "courier" , monospace;"><span style="background-color: transparent; color: black; vertical-align: baseline; white-space: pre-wrap;">const compiler = require('google-closure-compiler-js').gulp();</span><span style="background-color: transparent; color: black; vertical-align: baseline; white-space: pre-wrap;">
</span><span style="background-color: transparent; color: black; vertical-align: baseline; white-space: pre-wrap;">gulp.task('script', function() {
</span></span><span style="background-color: transparent; font-family: "courier new" , "courier" , monospace; line-height: 1.38; white-space: pre-wrap;"> // select your JS code here
</span><span style="background-color: transparent; font-family: "courier new" , "courier" , monospace; line-height: 1.38; white-space: pre-wrap;"> return gulp.src('./src/**/*.js', {base: './'})
</span><span style="background-color: transparent; font-family: "courier new" , "courier" , monospace; line-height: 1.38; white-space: pre-wrap;"> .pipe(compiler({
</span><span style="font-family: "courier new" , "courier" , monospace; line-height: 1.38; white-space: pre-wrap;"> jsOutputFile: 'output.min.js', // outputs single file
</span><span style="background-color: transparent; font-family: "courier new" , "courier" , monospace; line-height: 1.38; white-space: pre-wrap;"> compilationLevel: 'SIMPLE',
</span><span style="background-color: transparent; font-family: "courier new" , "courier" , monospace; line-height: 1.38; white-space: pre-wrap;"> warningLevel: 'VERBOSE',
</span><span style="background-color: transparent; font-family: "courier new" , "courier" , monospace; line-height: 1.38; white-space: pre-wrap;"> outputWrapper: '(function(){\n%output%\n}).call(this)',
</span><span style="font-family: "courier new" , "courier" , monospace; line-height: 1.38; white-space: pre-wrap;"> createSourceMap: true
</span><span style="background-color: transparent; font-family: "courier new" , "courier" , monospace; line-height: 1.38; white-space: pre-wrap;"> }))
</span><span style="background-color: transparent; font-family: "courier new" , "courier" , monospace; line-height: 1.38; white-space: pre-wrap;"> .pipe(gulp.dest('./dist'));
</span><span style="background-color: transparent; font-family: "courier new" , "courier" , monospace; line-height: 1.38; white-space: pre-wrap;">});</span></div>
</pre>
<div>
<span style="color: black; font-family: "arial" , "helvetica" , sans-serif; line-height: 1.38; vertical-align: baseline; white-space: pre-wrap;"><br /></span></div>
<div>
<span style="color: black; font-family: "arial" , "helvetica" , sans-serif; line-height: 1.38; vertical-align: baseline; white-space: pre-wrap;">If you'd like to migrate from </span><span style="color: black; line-height: 1.38; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">google-closure-compiler</span></span><span style="color: black; font-family: "arial" , "helvetica" , sans-serif; line-height: 1.38; vertical-align: baseline; white-space: pre-wrap;"> (which requires Java), you'll have to use </span><span style="color: black; line-height: 1.38; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">gulp.src()</span></span><span style="color: black; font-family: "arial" , "helvetica" , sans-serif; line-height: 1.38; vertical-align: baseline; white-space: pre-wrap;"> or equivalents to load your JavaScript before it can be compiled. As this compiler runs in pure JavaScript, the compiler cannot load or save files from your filesystem directly.</span></div>
<div>
<span style="color: black; font-family: "arial" , "helvetica" , sans-serif; line-height: 1.38; vertical-align: baseline; white-space: pre-wrap;"><br /></span></div>
<div>
<span style="color: black; font-family: "arial" , "helvetica" , sans-serif; line-height: 1.38; vertical-align: baseline; white-space: pre-wrap;">For more information, </span><span style="color: #1155cc; font-family: "arial" , "helvetica" , sans-serif; line-height: 1.38; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;"><a href="https://github.com/google/closure-compiler-js#usage" style="font-family: arial, helvetica, sans-serif; line-height: 1.38; text-decoration: none;">check out Usage</a></span><span style="color: black; font-family: "arial" , "helvetica" , sans-serif; line-height: 1.38; vertical-align: baseline; white-space: pre-wrap;">, </span><span style="color: #1155cc; font-family: "arial" , "helvetica" , sans-serif; line-height: 1.38; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;"><a href="https://github.com/google/closure-compiler-js#flags" style="font-family: arial, helvetica, sans-serif; line-height: 1.38; text-decoration: none;">supported Flags</a></span><span style="color: black; font-family: "arial" , "helvetica" , sans-serif; line-height: 1.38; vertical-align: baseline; white-space: pre-wrap;">, or a <a href="https://github.com/google/closure-compiler-js/tree/master/samples">demo project</a>. Not all flags supported in the Java release are currently available in this experimental version. However, the compiler will let you know via exception if you've hit any missing ones.</span></div>
<div>
<span style="color: #666666; font-family: "arial" , "helvetica" , sans-serif; line-height: 1.38; white-space: pre-wrap;"><br /></span></div>
<div>
<span style="color: #666666; font-family: "arial" , "helvetica" , sans-serif; line-height: 1.38; white-space: pre-wrap;">Posted by Sam Thorogood, Developer Programs Engineer</span></div>
</div>
</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2437909874160353836.post-10227323093351428082016-06-22T04:48:00.000-07:002016-06-22T04:48:57.199-07:00Using Polymer with Closure Compiler - Part 3: Renaming in Templates<style>
p, ol, h2 {
line-height: 1.5em;
}
code, pre, #ws, #message {
word-break: normal;
word-wrap: normal;
}
code, pre, #ws, #message {
border-radius: 3px;
background-color: #F8F8F8;
color: inherit;
}
code {
border: 1px solid #EAEAEA;
margin: 0 2px;
padding: 0 5px;
}
pre {
border: 1px solid #CCCCCC;
overflow: auto;
padding: 4px 8px;
}
pre > code {
border: 0;
margin: 0;
padding: 0;
}
code > a {
text-decoration: none;
}
</style>
<p>
<em>This is the last post in a 3-part series about using Polymer with Closure Compiler</em>
</p>
<ul>
<li>
<a href="/2016/06/using-polymer-with-closure-compiler-part-1.html">Part 1: Type Information</a>
</li>
<li>
<a href="/2016/06/using-polymer-with-closure-compiler-part-2.html">Part 2: Maximizing Renaming</a>
</li>
</ul>
<p>With Closure-Compiler in <code>ADVANCED</code> mode, the concept of “whole world”
optimization is used.
Simply stated, the compiler needs to know about <strong>all</strong>
of the JavaScript source used and <strong>all</strong>
the ways it can be consumed by other libraries/event handlers/scripts.
</p>
<p>Polymer templates would logically be thought of as an external use case.
However, symbols referenced externally can't be renamed by the compiler.
So, we need to provide the Polymer templates to Closure-Compiler along with our script
source so that everything can be renamed consistently.
Problem is, Polymer templates are HTML not JavaScript.
</p>
<h2 id="thepolymer-renameproject"></h2>
<p>
<a href="https://github.com/Banno/polymer-rename">Polymer-rename</a>
was created to solve just this problem.
It works by translating the HTML template data-binding expressions to
JavaScript before compilation and then reverses the process afterwards.
</p>
<h2 id="beforecompilations">Before Compilation: Extracting Expressions</h2>
<p>The polymer-rename extract plugin parses the HTML of a Polymer element.
It ignores the content of <code><<span style="color: rgb(99, 163, 92);">script</span>></code>
and <code><<span style="color: rgb(99, 163, 92);">style</span>></code> tags.
It looks for polymer expressions such as:
</p>
<pre><<span style="color: rgb(99, 163, 92);">button</span> <span style="color: rgb(121, 93, 163);">on-tap</span>=<span style="color: rgb(24, 54, 145);">"tapped_"</span>>[[buttonName]]</<span style="color: rgb(99, 163, 92);">button</span>></pre>
<p>From these expressions, it generates matching JavaScript:</p>
<pre>polymerRename.<span style="color: rgb(121, 93, 163);">eventListener</span>(<span style="color: rgb(0, 134, 179);">16</span>, <span style="color: rgb(0, 134, 179);">23</span>, <span style="color: rgb(237, 106, 67);">this</span>.tapped_);
polymerRename.<span style="color: rgb(121, 93, 163);">symbol</span>(<span style="color: rgb(0, 134, 179);">27</span>, <span style="color: rgb(0, 134, 179);">37</span>, <span style="color: rgb(237, 106, 67);">this</span>.buttonName);</pre>
<p>This JavaScript is not designed to ever be executed directly.
You don't package it with your elements.
Instead, Closure-Compiler uses this to consistently rename the symbols.
</p>
<h2 id="compiling">Compiling: Separate the Output
</h2>
<p>To separate your Polymer element script source from the templates and to provide all the source to Closure-Compiler
in the correct order, use the <a href="https://github.com/Polymer/vulcanize">vulcanize tool</a>
to combine all of your elements and inline all of the scripts.
Next, use the <a href="https://github.com/PolymerLabs/crisper">crisper tool</a>
to extract all of your inline scripts into a single external javascript file.
If you want your script inlined after compilation, just use the vulcanize tool again.
</p>
<p>With your polymer-rename generated script and your extracted source from vulcanize and cripser, you can now use
Closure-Compiler.
By default, Closure-Compiler is going to combine all of your JavaScript into a single output file.
But we do <strong>not</strong> want the polymer-rename generated code packaged with the rest of our scripts.
Closure-Compiler has a <a href="http://stackoverflow.com/a/10401030/1211524">powerful
- yet confusing to use - code splitting functionality</a>
which will allow us to direct some JavaScript to a different output file.
The confusing part is that the flag to trigger the code splitting is named “module”.
Don't mistake this with input module formats like ES6, CommonJS or goog.module - it has nothing to do with these.
</p>
<p>Here's an example compile command (using the compiler gulp plugin):
</p>
<pre><span style="color: rgb(167, 29, 93);">const</span> <span style="color: rgb(0, 134, 179);">closureCompiler</span> <span style="color: rgb(167, 29, 93);">=</span> <span style="color: rgb(0, 134, 179);">require</span>(<span style="color: rgb(24, 54, 145);">'google-closure-compiler'</span>);
gulp.<span style="color: rgb(121, 93, 163);">task</span>(<span style="color: rgb(24, 54, 145);">'compile-js'</span>, <span style="color: rgb(167, 29, 93);">function</span>() {
gulp.<span style="color: rgb(121, 93, 163);">src</span>([
<span style="color: rgb(24, 54, 145);">'./src/js/element-source.js'</span>,
<span style="color: rgb(24, 54, 145);">'./build/element-template-expressions.js'</span>])
.<span style="color: rgb(121, 93, 163);">pipe</span>(<span style="color: rgb(121, 93, 163);">closureCompiler</span>({
compilation_level<span style="color: rgb(167, 29, 93);">:</span> <span style="color: rgb(24, 54, 145);">'ADVANCED'</span>,
warning_level<span style="color: rgb(167, 29, 93);">:</span> <span style="color: rgb(24, 54, 145);">'VERBOSE'</span>,
polymer_pass<span style="color: rgb(167, 29, 93);">:</span> <span style="color: rgb(0, 134, 179);">true</span>,
module<span style="color: rgb(167, 29, 93);">:</span> [
<span style="color: rgb(24, 54, 145);">'element-source:1'</span>,
<span style="color: rgb(24, 54, 145);">'element-template-expressions:1:element-source'</span>
],
externs<span style="color: rgb(167, 29, 93);">:</span> [
require.<span style="color: rgb(121, 93, 163);">resolve</span>(
<span style="color: rgb(24, 54, 145);">'google-closure-compiler/contrib/externs/polymer-1.0.js'</span>),
require.<span style="color: rgb(121, 93, 163);">resolve</span>(
<span style="color: rgb(24, 54, 145);">'polymer-rename/polymer-rename-externs.js'</span>)
]
})
.<span style="color: rgb(121, 93, 163);">pipe</span>(gulp.<span style="color: rgb(121, 93, 163);">dest</span>(<span style="color: rgb(24, 54, 145);">'./dist'</span>));
});
</pre>
<p>What's going on here? We provided exactly two javascript files to Closure-Compiler - and the order matters greatly.
The first module definition consumes 1 javascript file (that's the <code>:1</code> part of the flag).
The second module flag also consumes 1 javascript file and logically depends on the first module.
The code-splitting flags are a bit unwieldy as they require you to have an exact count of your input files and to
make sure they are apportioned between your module flags correctly - and in the right order.
</p>
<p>After compilation completes, the “dist” folder should have two javascript files: element-source.js and
element-template-expressions.js.
The element-template-expressions.js file should only contain the template expressions extracted
by the polymer-rename project, but now with all of the symbol references properly renamed.
</p>
<h2 id="aftercompilation">After Compilation: Updating the Templates</h2>
<p>Now it's time to go back and update the original HTML templates with our newly renamed expressions.
There's not a lot to this step - just call the polymer-rename replace plugin and watch it work.
The example Polymer HTML expression from earlier might now look something like:
</p>
<pre><<span style="color: rgb(99, 163, 92);">button</span> <span style="color: rgb(121, 93, 163);">on-tap</span>=<span style="color: rgb(24, 54, 145);">"a"</span>>[[b]]</<span style="color: rgb(99, 163, 92);">button</span>></pre>
<h2 id="custom_type_names">Custom Type Names</h2>
<p>In <a href="/2016/06/using-polymer-with-closure-compiler-part-1.html">part 1 of the series</a>,
I discussed how the Polymer pass of Closure-Compiler generates type names
based off the element tag name:
<code><<span style="color: rgb(99, 163, 92);">foo-bar</span>></code>
by default will have the type name <code>FooBarElement</code>.
However, I also explained that an author can assign the return value
of the <code>Polymer</code> function to specify custom type names.
The polymer-rename plugins will use the same logic to determine type names.
If any of your elements have custom type names you will need to provide those names
to the extract plugin of polymer-rename.
</p>
<p>The extract plugin optionally takes a function which is used to lookup these names.
Here's an example implementation of a custom lookup function:
</p>
<pre>
<span style="color: rgb(150, 152, 150);">/**</span>
<span style="color: rgb(150, 152, 150);"> * Custom element type name lookup</span>
<span style="color: rgb(150, 152, 150);"> * <span style="color: rgb(167, 29, 93);">@param</span> <span style="color: rgb(121, 93, 163);">{string}</span> <span style="color: rgb(51, 51, 51);">tagName</span></span>
<span style="color: rgb(150, 152, 150);"> * <span style="color: rgb(167, 29, 93);">@return</span> {string|undefined}</span>
<span style="color: rgb(150, 152, 150);"> */</span>
<span style="color: rgb(167, 29, 93);">function</span> <span style="color: rgb(121, 93, 163);">lookupTypeByTagName</span>(tagName) {
<span style="color: rgb(167, 29, 93);">if</span> (<span style="color: rgb(24, 54, 145);">/<span style="color: rgb(167, 29, 93);">^</span>foo(-<span style="color: rgb(0, 134, 179);">.</span><span style="color: rgb(167, 29, 93);">*</span>)/</span>.<span style="color: rgb(0, 134, 179);">test</span>(tagName)) {
<span style="color: rgb(167, 29, 93);">return</span> <span style="color: rgb(24, 54, 145);">'myNamespace.Foo'</span> <span style="color: rgb(167, 29, 93);">+</span> tagName.<span style="color: rgb(0, 134, 179);">replace</span>(<span style="color: rgb(24, 54, 145);">/-(<span style="color: rgb(0, 134, 179);">[a-z]</span>)/g</span>,
<span style="color: rgb(167, 29, 93);">function</span>(match, letter) {
<span style="color: rgb(167, 29, 93);">return</span> letter.<span style="color: rgb(0, 134, 179);">toUpperCase</span>();
});
}
<span style="color: rgb(150, 152, 150);">// returning undefined here causes the polymer-rename</span>
<span style="color: rgb(150, 152, 150);">// plugin to fall back to the default</span>
<span style="color: rgb(150, 152, 150);">// behavior for type name lookups.</span>
<span style="color: rgb(167, 29, 93);">return</span> <span style="color: rgb(0, 134, 179);">undefined</span>;
}
</pre>
<p>
In this implementation, any element that starts with <code>foo-</code>
will have a type name that is upper camel case and a
member of the <code>myNamespace</code> object.
</p>
<h2 id="summary">Summary</h2>
<p>In addition to allowing full renaming of Polymer elements by Closure-Compiler,
the polymer-rename plugin also enables a wide range of type checking.
The compiler can now see how Polymer computed property methods are called -
and will properly notify you if the number of arguments or types don't match.
</p>
<p>Closure-Compiler <code>ADVANCED</code> optimizations and Polymer can create a powerful app,
it just takes a little work and an understanding of how they fit together.
</p>
<p>
<span class="post-author">Posted by Chad Killingsworth, JS Engineer for Jack Henry and Associates, Closure Compiler committer</span>
</p>Chad Killingsworthhttp://www.blogger.com/profile/03207660456745179801noreply@blogger.com1tag:blogger.com,1999:blog-2437909874160353836.post-22684900773772476542016-06-20T05:40:00.000-07:002016-06-22T10:43:54.705-07:00Using Polymer with Closure Compiler - Part 2: Maximizing Renaming<style>
p, ol, h2 {
line-height: 1.5em;
}
code, pre, #ws, #message {
word-break: normal;
word-wrap: normal;
}
code, pre, #ws, #message {
border-radius: 3px;
background-color: #F8F8F8;
color: inherit;
}
code {
border: 1px solid #EAEAEA;
margin: 0 2px;
padding: 0 5px;
}
pre {
border: 1px solid #CCCCCC;
overflow: auto;
padding: 4px 8px;
}
pre > code {
border: 0;
margin: 0;
padding: 0;
}
code > a {
text-decoration: none;
}
</style>
<p>
<em>This is the second post in a 3-part series about using Polymer with Closure Compiler</em>
</p>
<ul>
<li>
<a href="/2016/06/using-polymer-with-closure-compiler-part-1.html">Part 1: Type Information</a>
</li>
<li>
<a href="/2016/06/using-polymer-with-closure-compiler-part-3.html">Part 3: Renaming in Templates</a>
</li>
</ul>
<p><strong>UPDATE:</strong> <code>goog.reflect.<span style="color: rgb(121, 93, 163);">objectProperty</span></code> is now
available as part of the 20160619 compiler and library releases.</p>
<hr />
<p>Closure Compiler's <code>ADVANCED</code>
mode property renaming and dead code elimination put it in a class all its own. In <code>ADVANCED</code>
mode, the compiler performs “whole world” optimizations. Polymer apps can take advantage of these optimizations
without losing functionality.
</p>
<h2 id="howclosurecompilerrenamesproperties">How Closure Compiler Renames Properties
</h2>
<p>Closure Compiler property renaming occurs in two primary ways. The first is quite straightforward: all properties
with the same name are renamed in the same way. This is ideal because it doesn't require any type information to
work.
All instances of <code>.foo</code> are renamed <code>.a</code> regardless of on which object they are defined.
However, if any property with the same name is found on <em>any</em>
object in the externs, the compiler cannot rename it with this strategy. The more extern properties included in your
compilation, the fewer properties can be renamed with this method.
</p>
<p>The second method for property renaming was created to address the shortcomings in the first method. Here, the
compiler uses type information to rename properties so that they are unique. This way, the first method can happily
rename them as they no longer share the name of an extern property. This method is called type-based renaming and as
its name suggests, it can only work with proper type information. It will decline to rename a property if it finds
the same property on an object for which it cannot determine type information. The better type information provided,
the better this method works.
</p>
<p>Finally, for property renaming to work at all, properties must be consistently referenced. Properties accessed using
an array style bracket notation (such as <code>foo['bar']</code>) are called quoted properties and they will never
be renamed.
Properties accessed using a dot notation (such as <code>foo.bar</code>) are called dotted properties and <em>may</em>
be renamed. Your code can break if you access the same property using both methods - so make sure you choose one and
are consistent.
</p>
<h2 id="renamingpolymerproperties">Renaming Polymer Properties</h2>
<p>The Polymer library itself is considered an external library. A <a
href="https://github.com/google/closure-compiler/blob/master/contrib/externs/polymer-1.0.js">well maintained
externs file</a>
for Polymer is hosted within the compiler repository (and distributed in the npm version).
Lifecycle methods (such as <code>created</code>
, <code>ready</code>
, <code>attached</code>
, etc) are externally defined and therefore not renameable. Also, as mentioned in <a
href="/2016/06/using-polymer-with-closure-compiler-part-1.html">part 1 of this series</a>
, declared properties defined as part of Polymer's <code>properties</code>
object can never be renamed.
</p>
<p>That leaves non-lifecycle standard properties as eligible for renaming - as long as they are not quoted. However,
since Polymer's listeners and observers are specified as strings, that breaks the consistent access rule for
properties and forces you to quote those properties. There are, however, other options.
</p>
<h2 id="observersandlisteners">Observers and Listeners</h2>
<p>A Polymer element declares a property observer like:
</p>
<pre><span style="color: rgb(121, 93, 163);">Polymer</span>({
is<span style="color: rgb(167, 29, 93);">:</span> <span style="color: rgb(24, 54, 145);">'foo-bar'</span>,
properties<span style="color: rgb(167, 29, 93);">:</span> {
foo<span style="color: rgb(167, 29, 93);">:</span> {
type<span style="color: rgb(167, 29, 93);">:</span><span style="color: rgb(0, 134, 179);">String</span>,
observer<span style="color: rgb(167, 29, 93);">:</span> <span style="color: rgb(24, 54, 145);">'fooChanged_'</span>
}
}
<span style="color: rgb(150, 152, 150);">/** <span style="box-sizing: border-box; color: rgb(167, 29, 93);">@private</span> */</span>
<span style="color: rgb(24, 54, 145);">'fooChanged_'</span><span style="color: rgb(167, 29, 93);">:</span> <span style="color: rgb(167, 29, 93);">function</span>(oldValue, newValue) {}
});</pre>
<p>In this case, our <code>fooChanged_</code> method is a private implementation detail.
Renaming it would be ideal. However for that to be possible, we would
need to have access to the renamed name of <code>fooChanged_</code>
as a string.
Closure Library has a primitive that Closure Compiler understands to help in just this case:
<a href="https://google.github.io/closure-library/api/namespace_goog_reflect.html#object">goog.reflect.object</a>.
</p>
<p>By using <code>goog.reflect.<span style="color: rgb(121, 93, 163);">object</span></code>
we can rename the keys of an object literal in the same way that our Polymer element is renamed. After renaming, we
can use <a href="https://google.github.io/closure-library/api/namespace_goog_object.html#transpose">goog.object.transpose</a>
to swap the object keys and values enabling us to easily lookup the name of our now renamed property.
</p>
<pre><span style="color: rgb(167, 29, 93);">var</span> FooBarElement <span style="box-sizing: border-box; color: rgb(167, 29, 93);">=</span> <span style="color: rgb(121, 93, 163);">Polymer</span>({
is<span style="color: rgb(167, 29, 93);">:</span> <span style="color: rgb(24, 54, 145);">'foo-bar'</span>,
properties<span style="color: rgb(167, 29, 93);">:</span> {
foo<span style="color: rgb(167, 29, 93);">:</span> {
type<span style="color: rgb(167, 29, 93);">:</span> <span style="color: rgb(0, 134, 179);">String</span>,
observer<span style="color: rgb(167, 29, 93);">:</span> FooBarRenamedProperties[<span style="color: rgb(24, 54, 145);">'fooChanged_'</span>]
}
}
<span style="color: rgb(150, 152, 150);">/** <span style="box-sizing: border-box; color: rgb(167, 29, 93);">@private</span> */</span>
<span style="color: rgb(121, 93, 163);">fooChanged_</span><span style="color: rgb(167, 29, 93);">:</span> <span style="color: rgb(167, 29, 93);">function</span>(oldValue, newValue) {}
});
<span style="color: rgb(167, 29, 93);">var</span> FooBarRenamedProperties <span style="box-sizing: border-box; color: rgb(167, 29, 93);">=</span> goog.<span style="color: rgb(0, 134, 179);">object</span>.<span style="color: rgb(121, 93, 163);">transpose</span>(
goog.reflect.<span style="color: rgb(0, 134, 179);">object</span>(FooBarElement, {
fooChanged_<span style="color: rgb(167, 29, 93);">:</span> <span style="color: rgb(24, 54, 145);">'fooChanged_'</span>
})
);</pre>
<p>We can use the same technique to rename listener methods:</p>
<pre><span style="color: rgb(167, 29, 93);">var</span> FooBarElement <span style="box-sizing: border-box; color: rgb(167, 29, 93);">=</span> <span style="color: rgb(121, 93, 163);">Polymer</span>({
is<span style="color: rgb(167, 29, 93);">:</span> <span style="color: rgb(24, 54, 145);">'foo-bar'</span>,
listeners<span style="color: rgb(167, 29, 93);">:</span> {
<span style="color: rgb(24, 54, 145);">'tap'</span><span style="color: rgb(167, 29, 93);">:</span> FooBarRenamedProperties[<span style="color: rgb(24, 54, 145);">'tapped_'</span>]
}
<span style="color: rgb(150, 152, 150);">/** <span style="box-sizing: border-box; color: rgb(167, 29, 93);">@param</span> {!Event} evt */</span>
<span style="color: rgb(121, 93, 163);">tapped_</span><span style="color: rgb(167, 29, 93);">:</span> <span style="color: rgb(167, 29, 93);">function</span>(evt) {}
});
<span style="color: rgb(167, 29, 93);">var</span> FooBarRenamedProperties <span style="box-sizing: border-box; color: rgb(167, 29, 93);">=</span> goog.<span style="color: rgb(0, 134, 179);">object</span>.<span style="color: rgb(121, 93, 163);">transpose</span>(
goog.reflect.<span style="color: rgb(0, 134, 179);">object</span>(FooBarElement, {
tapped_<span style="color: rgb(167, 29, 93);">:</span> <span style="color: rgb(24, 54, 145);">'tapped_'</span>
})
);</pre>
<h2 id="triggering_property_change">Triggering Property Change Events</h2>
<p>Polymer provides three different methods to indicate that a property has changed and data-binding expressions should
be re-evaluated: <code><a href="https://www.polymer-project.org/1.0/docs/api/Polymer.Base#method-set">set</a></code>,
<code><a href="https://www.polymer-project.org/1.0/docs/devguide/data-binding#set-path">notifyPath</a></code>
and <code><a
href="https://www.polymer-project.org/1.0/docs/devguide/data-binding#array-mutation">notifySplices</a></code>.
All three have one unfortunate thing in common: they require us to specify the property name as a string. This
would also break the consistent access rule for properties and once again we need access to the renamed property as
a string. While the <code>goog.object.<span style="color: rgb(121, 93, 163);">transpose</span>(goog.reflect.<span style="color: rgb(121, 93, 163);">object</span>(typeName, {}))</code>
technique would also work for this case, it requires us to know the globally accessible type name of the object. In
this case, Closure Library has another primitive to help: <a
href="https://github.com/google/closure-library/blob/master/closure/goog/reflect/reflect.js#L40-L58">goog.reflect.objectProperty</a>
. This method is very new. <em>As of this writing, <code>goog.reflect.<span style="color: rgb(121, 93, 163);">objectProperty</span></code>
has yet to be released in either Closure Compiler or Closure Library (though it should be soon).</em>
<code>goog.reflect.<span style="color: rgb(121, 93, 163);">objectProperty</span></code>
allows us to call the notification methods with a renamed string.
</p>
<pre><span style="color: rgb(121, 93, 163);">Polymer</span>({
is<span style="color: rgb(167, 29, 93);">:</span> <span style="color: rgb(24, 54, 145);">'foo-bar'</span>,
baz<span style="color: rgb(167, 29, 93);">:</span><span style="color: rgb(24, 54, 145);">'Original Value'</span>,
<span style="color: rgb(121, 93, 163);">attached</span><span style="color: rgb(167, 29, 93);">:</span> <span style="color: rgb(167, 29, 93);">function</span>() {
<span style="color: rgb(0, 134, 179);">setTimeout</span>((<span style="color: rgb(167, 29, 93);">function</span>() {
<span style="color: rgb(237, 106, 67);">this</span>.baz <span style="color: rgb(167, 29, 93);">=</span> <span style="color: rgb(24, 54, 145);">'New Value'</span>;
<span style="color: rgb(237, 106, 67);">this</span>.<span style="color: rgb(121, 93, 163);">notifyPath</span>(
goog.reflect.<span style="color: rgb(121, 93, 163);">objectProperty</span>(<span style="color: rgb(24, 54, 145);">'baz'</span>, <span style="color: rgb(237, 106, 67);">this</span>), <span style="color: rgb(237, 106, 67);">this</span>.baz);
}).<span style="color: rgb(121, 93, 163);">bind</span>(<span style="color: rgb(237, 106, 67);">this</span>), <span style="color: rgb(0, 134, 179);">1000</span>);
}
});</pre>
<p>
<code>goog.reflect.<span style="color: rgb(121, 93, 163);">objectProperty</span></code>
simply returns the string name (first argument) in uncompiled mode. Its use comes solely as a Closure Compiler
primitive where the compiler replaces the entire call with simply a string of the renamed property.
</p>
<h2 id="summary">Summary</h2>
<p>By reserving Polymer's declared properties for cases where the special functionality offered is actually needed,
quite a bit of renaming can be obtained on an element. In addition, use of <code>goog.reflect.<span style="color: rgb(121, 93, 163);">object</span></code>
and <code>goog.reflect.<span style="color: rgb(121, 93, 163);">objectProperty</span></code>
allows us to rename properties which are required to be used with strings.
</p>
<p>However now we find ourselves in a case where all this renaming has broken references in our template data-binding
expressions. Time for <a href="/2016/06/using-polymer-with-closure-compiler-part-3.html">Part 3: Renaming in Polymer Templates</a>.
</p>
<p>
<span class="post-author">Posted by Chad Killingsworth, JS Engineer for Jack Henry and Associates, Closure Compiler committer</span>
</p>
Chad Killingsworthhttp://www.blogger.com/profile/03207660456745179801noreply@blogger.com5tag:blogger.com,1999:blog-2437909874160353836.post-69467468242631349052016-06-15T13:01:00.001-07:002016-06-22T04:52:07.282-07:00Using Polymer with Closure Compiler - Part 1: Type Information<style>
p, ol, h2 {
line-height: 1.5em;
}
code, pre, #ws, #message {
word-break: normal;
word-wrap: normal;
}
code, pre, #ws, #message {
border-radius: 3px;
background-color: #F8F8F8;
color: inherit;
}
code {
border: 1px solid #EAEAEA;
margin: 0 2px;
padding: 0 5px;
}
pre {
border: 1px solid #CCCCCC;
overflow: auto;
padding: 4px 8px;
}
pre > code {
border: 0;
margin: 0;
padding: 0;
}
code > a {
text-decoration: none;
}
</style>
<p><em>This is the first post in a 3-part series about using Polymer with Closure Compiler</em></p>
<ul>
<li>
<a href="/2016/06/using-polymer-with-closure-compiler-part-2.html">Part 2: Maximizing Renaming</a>
</li>
<li>
<a href="/2016/06/using-polymer-with-closure-compiler-part-3.html">Part 3: Renaming in Templates</a>
</li>
</ul>
<h2 id="introduction">
Introduction</h2>
<p>Closure Compiler has long been practically the only JavaScript compiler to be able to rename properties (using the
<code>ADVANCED</code>
optimization level). In addition, it offers an impressive amount of static analysis and type checking while still
writing in native
ECMAScript. However, with the adoption of frameworks with data-bound templates such as Angular, the power of Closure
Compiler
has been significantly reduced because the template references are external to the compiler.</p>
<p>
With Polymer, it is possible to maintain a high degree of property renaming and type checking while still utilizing
the power of data-bound HTML templates. Finding information on how to use the two together has been difficult thus
far.</p>
<p>
This post explains how type information in the compiler is created from Polymer element definitions and how to
utilize them.
<a href="/2016/06/using-polymer-with-closure-compiler-part-2.html">Part 2</a> concentrates on how to obtain optimal renaming of Polymer elements and <a href="/2016/06/using-polymer-with-closure-compiler-part-3.html">part 3</a> will detail how to rename
data-binding
references in the HTML templates consistently with the element properties.</p>
<h2 id="thepolymerpass">The Polymer Pass</h2>
<p>Closure Compiler has a pass specifically written to process Polymer element definitions and produce the correct type
information.
The pass is enabled by specifying the <code>--polymer_pass</code> command line flag. The pass allows the rest of the
compiler to
properly understand Polymer types.</p>
<p>
Polymer element definitions contain both standard properties and can also declare properties on a special <code>properties</code>
object. It can be confusing to understand the difference. Both will end up as properties on the created class’
prototype. However,
if you have a property which does not need the extra abilities of the <code>properties</code> object, where does it
go? The official
guidance has been if the property is part of the public API for an element, it should be defined on the <code>properties</code>
object. However, with Closure Compiler, it’s not quite so cut-and-dry.</p>
<p>
<h2 id="declaredproperties">
Declared Properties - Children of the <code>properties</code> Object</h2>
<p><a href="https://www.polymer-project.org/1.0/docs/devguide/properties">Declared properties</a>
biggest advantage is how they work behind the scenes. Polymer attaches them using getters and setters so that any
change to the property automatically updates data-bound expressions. However, because these elements can also be
serialized as attributes, referenced from CSS and are generally considered external interfaces, the compiler will
<strong>never</strong>
rename them. The Polymer pass of the compiler creates an external interface and marks the Polymer element as
implementing that interface. This blocks renaming without incurring the loss of type checking that happens with
properties which are quoted.</p>
<h2 id="standardproperties">
Standard Properties</h2>
<p>Standard properties on the other hand are potentially renamable (the compiler will use its standard strategies to
determine whether it is safe to rename the property or not). In fact, one method to prevent template references from
being broken by renaming is to quote all standard properties used in data-binding expressions. This is less than
ideal and <a href="/2016/06/using-polymer-with-closure-compiler-part-3.html">part 3
of the series</a> will describe how to avoid this. Standard properties are still accessible from outside of the
component and can also be considered part of the public API of an element, but they retain the ability to be
renamed. However, because they are not defined with Polymer’s getters and setters, you must either use the Polymer
<code><a href="https://www.polymer-project.org/1.0/docs/api/Polymer.Base#method-set">set</a></code> method to make
changes to the property or use either <code><a
href="https://www.polymer-project.org/1.0/docs/devguide/data-binding#set-path">notifyPath</a></code>
or <code><a
href="https://www.polymer-project.org/1.0/docs/devguide/data-binding#array-mutation">notifySplices</a></code>
to inform Polymer that a change has already occurred. The next post in the series talks about how to use these
methods with renamed properties.</p>
<h2 id="behaviors">
Behaviors</h2>
<p><a href="https://www.polymer-project.org/1.0/docs/devguide/behaviors">Polymer behaviors</a>
are essentially a mixin. Since the compiler needs explicit knowledge of behavior implementation, type definitions
are copied onto the element. The Polymer pass of Closure Compiler automatically creates sub entries for each
behavior method. There are a some not-so-obvious implementation details however:</p>
<ol>
<li>Behaviors must be defined as object literals - just like a Polymer element definition.</li>
<li>Behaviors must be annotated with the special <code>@polymerBehavior</code>
annotation.
</li>
<li>Methods of a behavior should be annotated with <code>@this {!PolymerElement}</code>
so that the compiler knows the correct type of the <code>this</code>
keyword.
</li>
<li>Behaviors must be defined as a global type name - and cannot be aliased.</li>
</ol>
<h2 id="elementtypenames">
Element Type Names</h2>
<p>Most Polymer examples call the <code>Polymer</code>
function without using the return value. In these cases, the Polymer pass will automatically create a type name for
the element from the tag name. The tag name is converted from a hyphenated name to an upper camel case name and the
word <code>Element</code>
is appended. For instance, the compiler sees the <code>foo-bar</code>
element definition and creates a global <code>FooBarElement</code>
type. This allows references in other elements to type cast the value.</p>
<p>
<pre><span style="box-sizing: border-box; color: rgb(167 , 29 , 93);">var</span> fooBarElement <span
style="box-sizing: border-box; color: rgb(167 , 29 , 93);">=</span>
<span style="box-sizing: border-box; color: rgb(150 , 152 , 150);">/** <span class="pl-k"
style="box-sizing: border-box; color: rgb(167 , 29 , 93);">@type</span> {FooBarElement} */</span>(<span
style="box-sizing: border-box; color: rgb(237 , 106 , 67);">this</span>.<span
style="box-sizing: border-box; color: rgb(121 , 93 , 163);">$$</span>(<span
style="box-sizing: border-box; color: rgb(24 , 54 , 145);"><span style="box-sizing: border-box;">'</span>foo-bar<span
style="box-sizing: border-box;">'</span></span>));</pre>
Authors may also choose to assign their own type name. To do that, simply use the return value of the
<code>Polymer</code>
function.</p>
<p>
<pre><span style="box-sizing: border-box;">myNamespace</span>.<span class="pl-smi" style="box-sizing: border-box;">FooBar</span> <span
style="box-sizing: border-box; color: rgb(167 , 29 , 93);">=</span> <span class="pl-en"
style="box-sizing: border-box; color: rgb(121 , 93 , 163);">Polymer</span>({is<span
style="box-sizing: border-box; color: rgb(167 , 29 , 93);">:</span><span
style="box-sizing: border-box; color: rgb(24 , 54 , 145);"><span class="pl-pds" style="box-sizing: border-box;">'</span>foo-bar<span
style="box-sizing: border-box;">'</span></span>});</pre>
The assigned name will now be the type name:</p>
<p>
<pre><span style="box-sizing: border-box; color: rgb(167 , 29 , 93);">var</span> fooBarElement <span
style="box-sizing: border-box; color: rgb(167 , 29 , 93);">=</span>
<span style="box-sizing: border-box; color: rgb(150 , 152 , 150);">/** <span class="pl-k"
style="box-sizing: border-box; color: rgb(167 , 29 , 93);">@type</span> {myNamespace.FooBar} */</span>(<span
style="box-sizing: border-box; color: rgb(237 , 106 , 67);">this</span>.<span
style="box-sizing: border-box; color: rgb(121 , 93 , 163);">$$</span>(<span
style="box-sizing: border-box; color: rgb(24 , 54 , 145);"><span style="box-sizing: border-box;">'</span>foo-bar<span
style="box-sizing: border-box;">'</span></span>));</pre>
Because type names must be globally accessible, the Polymer pass will only recognize this assignment in the global scope
or
if the name is a qualified namespace assignment.</p>
<h2 id="summary">
Summary</h2>
<p>This post describes how Closure Compiler processes Polymer element definitions. In many cases, the compiler will
automatically
process and infer type information. However, Polymer elements must still be written in a way which is compatible
with the restrictions imposed by Closure Compiler. Don’t assume that any element you find will automatically be
compatible. If you find one that isn’t, may I suggest a pull request?</p>
<p>
<span class="post-author">Posted by Chad Killingsworth, JS Engineer for Jack Henry and Associates, Closure Compiler committer</span>
</p>Chad Killingsworthhttp://www.blogger.com/profile/03207660456745179801noreply@blogger.com0tag:blogger.com,1999:blog-2437909874160353836.post-48164069673648625692016-03-03T21:31:00.000-08:002016-03-03T21:34:29.217-08:00High-level overview of a compilation job<div dir="ltr" style="text-align: left;" trbidi="on">
This post gives a short overview of Closure Compiler's code, and the main classes that are involved in a compilation. It is intended for people who are getting started with the compiler, and want to make changes to it and understand how it works.<br />
<br />
For each compilation, an instance of <a href="https://github.com/google/closure-compiler/blob/master/src/com/google/javascript/jscomp/Compiler.java">Compiler</a> is created. The compiler class contains several <span style="font-family: "courier new" , "courier" , monospace;">compile</span> methods, and they all end up calling <span style="font-family: "courier new" , "courier" , monospace;"><a href="https://github.com/google/closure-compiler/search?utf8=%E2%9C%93&q=%22private+void+compileInternal%28%29%22">compileInternal</a></span>.<br />
<br />
The <a href="https://github.com/google/closure-compiler/blob/master/src/com/google/javascript/jscomp/CommandLineRunner.java">CommandLineRunner</a> takes the command-line arguments and creates an instance of <a href="https://github.com/google/closure-compiler/blob/master/src/com/google/javascript/jscomp/CompilerOptions.java">CompilerOptions</a>. The compiler uses the options object to determine which passes will be run (some checks and some optimizations). This happens in <a href="https://github.com/google/closure-compiler/blob/master/src/com/google/javascript/jscomp/DefaultPassConfig.java">DefaultPassConfig</a>. The two important methods in this class are <span style="font-family: "courier new" , "courier" , monospace;">getChecks</span> and <span style="font-family: "courier new" , "courier" , monospace;">getOptimizations</span>.<br />
<br />
Before running the checks, the compiler parses the code and creates an abstract-syntax tree (AST). The structure of the AST is described in <a href="https://github.com/google/closure-compiler/blob/master/src/com/google/javascript/rhino/Node.java">Node</a>, <a href="https://github.com/google/closure-compiler/blob/master/src/com/google/javascript/rhino/IR.java">IR</a> and <a href="https://github.com/google/closure-compiler/blob/master/src/com/google/javascript/rhino/Token.java">Token</a>. <a href="https://github.com/google/closure-compiler/blob/master/src/com/google/javascript/jscomp/NodeUtil.java">NodeUtil</a> contains many static utility functions for manipulating the AST.<br />
<br />
<a href="https://github.com/google/closure-compiler/blob/master/src/com/google/javascript/jscomp/PhaseOptimizer.java">PhaseOptimizer</a> takes the list of passes created in the pass config and runs them. Running the checks is simple, we just go through the list of checks and run each check once. Some optimization passes run once, and others run in a loop until they can no longer make changes. During an optimization loop, the compiler tries to avoid running passes that are no longer making changes. If you are experimenting with the compiler and want to see the code after each pass, use the command-line flag <span style="font-family: "courier new" , "courier" , monospace;">--print_source_after_each_pass</span>. If you want to see how long each pass takes, and how each pass changes code size, use the flag <span style="font-family: "courier new" , "courier" , monospace;">--tracer_mode=ALL</span>.<br />
<br />
After all checks and optimizations are finished, the AST is converted back to JavaScript source. See <a href="https://github.com/google/closure-compiler/blob/master/src/com/google/javascript/jscomp/CodeGenerator.java">CodeGenerator</a> and <a href="https://github.com/google/closure-compiler/blob/master/src/com/google/javascript/jscomp/CodePrinter.java">CodePrinter</a>.<br />
<br />
This is basically it. Below, we briefly describe some of the common compiler passes.<br />
<br />
<a href="https://github.com/google/closure-compiler/blob/master/src/com/google/javascript/jscomp/NodeTraversal.java">NodeTraversal</a> has utility methods to traverse the AST. All compiler passes use a traversal to go through the code, rather than hand-written recursion.<br />
<br />
The type-checking code lives in <a href="https://github.com/google/closure-compiler/blob/master/src/com/google/javascript/jscomp/TypedScopeCreator.java">TypedScopeCreator</a>, <a href="https://github.com/google/closure-compiler/blob/master/src/com/google/javascript/jscomp/TypeInference.java">TypeInference</a> and <a href="https://github.com/google/closure-compiler/blob/master/src/com/google/javascript/jscomp/TypeCheck.java">TypeCheck</a>. The code for the new type checker (still under development) lives in <a href="https://github.com/google/closure-compiler/blob/master/src/com/google/javascript/jscomp/GlobalTypeInfo.java">GlobalTypeInfo</a> and <a href="https://github.com/google/closure-compiler/blob/master/src/com/google/javascript/jscomp/NewTypeInference.java">NewTypeInference</a>.<br />
<br />
To see some of the optimizations, start at <a href="https://github.com/google/closure-compiler/search?utf8=%E2%9C%93&q=%22getMainOptimizationLoop%22&type=Code">getMainOptimizationLoop</a> and look at the passes used there.<br />
<br />
Also, the <a href="http://closure-compiler-debugger.appspot.com/">debugger</a> is really useful. You can paste some JS, turn individual passes on and off, and see the AST, the generated code, and the compiler warnings.<br />
<br />
Posted by Dimitris Vardoulakis, Software Engineer</div>
Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-2437909874160353836.post-22108210894813578502014-06-11T11:14:00.002-07:002014-06-11T11:14:51.417-07:00Call of the Octocat: From Google Code to GitHubEarlier this spring, Closure engineers proposed migrating our source repositories from Google Code to GitHub. We asked the open-source community whether hosting the repositories on GitHub would improve their workflow, and whether it would justify the (small) cost of migration. <br />
<br />
The <a href="https://groups.google.com/d/msg/closure-library-discuss/WEgaBsn-08U/sbn_bACDjDUJ">response</a> was univocal. Closure users preferred GitHub issue tracking, documentation, and pull request systems to their Google Code equivalents. Enthusiastic users outside Google had even set up unofficial GitHub mirrors of the Closure projects to better fit into their development process. <br />
<br />
Today, we are pleased to announce that three of the four top-level Closure projects have migrated to GitHub:<br />
<ul>
<li><a href="https://github.com/google/closure-compiler">Closure Compiler</a></li>
<li><a href="https://github.com/google/closure-library">Closure Library</a></li>
<li><a href="https://github.com/google/closure-stylesheets">Closure Stylesheets</a></li>
</ul>
(The fourth project, <a href="https://code.google.com/p/closure-linter/">Closure Linter</a>, still needs some work to ensure a smooth migration. It will stay at Google Code for now.) If your own Git repositories currently use the Google Code repositories as a remote, use <a href="http://stackoverflow.com/questions/2432764/change-the-uri-url-for-a-remote-git-repository">these instructions</a> to update.<br />
<br />
We hope this change will make it easier for developers to learn about, use, discuss, and contribute to the Closure Tools. Let us know what you think on the project-specific groups (<a href="https://groups.google.com/forum/#!forum/closure-compiler-discuss">Compiler</a>, <a href="https://groups.google.com/forum/#!forum/closure-library-discuss">Library</a>, <a href="https://groups.google.com/forum/#!forum/closure-stylesheets-discuss">Stylesheets</a>).<br />
<br />
<span class="post-author">Posted by Brendan Linn, Software Engineer</span>Unknownnoreply@blogger.com3tag:blogger.com,1999:blog-2437909874160353836.post-33235412956242549672012-09-26T07:28:00.001-07:002012-09-26T07:29:53.634-07:00Which Compilation Level is Right for Me?<i>Cross-posted from the <a href="http://blogs.missouristate.edu/web/2012/09/26/closure-compiler-which-compilation-level-is-right-for-me/">Missouri State Web and New Media Blog</a></i>
<p>When first starting with Closure Compiler, it is easy to see the names for the <a href="https://developers.google.com/closure/compiler/docs/compilation_levels">compilation levels</a> and assume that advanced is better than simple. While it is true that advanced optimization generally <a href="https://developers.google.com/closure/compiler/docs/api-tutorial3#better">produces a smaller file</a>, that does not mean it is the best fit for all projects.</p>
<h2>What is really the difference?</h2>
<p>There are quite a few differences, but the most significant is dead-code elimination. With advanced optimizations the compiler removes any code that it knows you are not using. Perfect! Who would not want that? Turns out a lot of people because the compiler can only correctly eliminate code when you specifically tell it about ALL of the other code used in your project AND ALL of the ways that your code is used by other scripts. Everything should be compiled together at the same time. That is a pretty big gotcha.</p>
<p>Here is a classic example:</p>
<pre><html>
<head>
<title>Advanced Optimization Gotchas</title>
<!-- an external library -->
<script src="jquery-1.7.2.js"></script>
<script>
//This section is compiled
function ChangeBackground() {
$('body').css('background-color', 'pink');
}
//Export for external use
window['ChangeBackground'] = ChangeBackground;
</script>
</head>
<body>
<!-- external use of compiled code -->
<a onclick="ChangeBackground()">Pinkify</a>
</body>
</html></pre>
<p>In this case we have to explicitly tell the compiler about jQuery during compilation with an <a href="https://developers.google.com/closure/compiler/docs/api-tutorial3#comptoex">extern file</a> and we have to tell it that our <span style="font-family: Courier New, serif;">ChangeBackground</span> function is called from external code. While this is a contrived example, it illustrates a case where it probably was not worth the time to ensure compatibility with the advanced optimization level.</p>
<h2>General decision factors</h2>
<p>So how do you actually decide which optimization level is right for your project? Below are some of the most common factors in that decision:</p>
<p><table border="1px solid black">
<tbody>
<tr>
<th scope="col">Simple Optimizations</th>
<th scope="col">Advanced Optimizations</th>
</tr>
<tr>
<td>Looking for a replacement JavaScript compressor</td>
<td>Looking for every last byte of savings in delivered code size or in execution time</td>
</tr>
<tr>
<td>Compiling a library where the vast majority of functions are part of the publicly exposed API</td>
<td>Authoring a very large application with multiple modules</td>
</tr>
<tr>
<td>Unwilling to make substantial changes to code style</td>
<td>Starting a new project or are willing to make substantial changes to coding style and patterns</td>
</tr>
<tr>
<td>Using external libraries that do not have existing extern files and are not compatible with advanced optimizations</td>
<td>Wanting the best possible obfuscation of your code to protect intellectual property</td>
</tr>
<tr>
<td>On a tight timeline that does not allow for troubleshooting obscure errors after compilation</td>
<td>Authoring a large library but want to support users who only use a small subset of the code</td>
</tr>
</tbody>
</table></p>
<h2>Coding style factors</h2>
<p>Most of us are proud of our JavaScript. In fact we may have some slick coding patterns that make our code elegant to read and maintain, however, not all JavaScript coding patterns compile equally with Closure Compiler advanced optimizations. If your code contains any of the following (and you are unwilling to change this) then simple optimizations would probably be the best choice for you:</p>
<ul style="margin-top: 1em;">
<li><strong>Mixed property access methods</strong><br />
Closure Compiler treats properties accessed with dotted notation (obj.prop) differently than when accessed via brackets or quoted notation (obj[‘prop’]). In fact it sees them as <a href="https://developers.google.com/closure/compiler/docs/api-tutorial3#propnames">completely different properties</a>. This item is first on the list for a reason: it is almost always the biggest hurdle. Because of this, the following patterns are all places which can cause problems with advanced optimizations:</p>
<ol style="margin-top: 1em;">
<li><strong>Building method names with strings</strong>
<pre>var name = 'replace';
obj[name] = function() {};
obj[name + 'With'] = function() {};
Obj.replaceWith(); //Mixed access problem</pre>
</li>
<li><strong>Testing for property existence with strings</strong>
<pre>obj.prop = 'exists';
if ('prop' in obj) … //Mixed access problem</pre>
</li>
<li><strong>Using a property name in a loop</strong>
<pre>obj.prop = function() {};
for (var propName in obj) {
if(propName == 'prop') { //Mixed access problem
}
}</pre>
</li>
</ol>
</li>
<li><strong>Using the “this” keyword outside of constructors or prototype methods</strong>
<pre>var obj = {};
//Static method using “this”
obj.prop = function() { this.newprop = 'exists' };
obj.prop();
alert(obj.newprop);
...</pre>
<p>In advanced optimizations, Closure Compiler can move and refactor code in unexpected ways. Some of them include functions which are inlined and properties which are collapsed to variables. In many of these cases, it changes <a href="http://closuretools.blogspot.com/2010/10/this-this-is-your-this.html">which object the “this” keyword references</a>. These cases have workarounds, but without special attention your code will likely not execute as intended. To illustrate, under advanced optimizations the compiler might change the above code to:</p>
<pre>var obj = {};
var a = function() { this.newprop = 'exists' };
a();
//Property does not exist - it is defined on the window object
alert(obj.newprop);</pre>
</li>
</ul>
<h2>Choose wisely</h2>
<p>Regardless of the choice between simple or advanced optimizations, you can still use the many compile time code checks and warnings for your code. From a missing semicolon to a misspelled property, the compiler can assist in identifying problems with your code before your users do it for you.</p>
<p>So to recap, advanced is not always better than simple. Modifying an existing code base to be compatible with Closure Compiler advanced optimizations can be a daunting challenge, and it definitely is not the best choice for every project.</p>
<p><span class="post-author">Posted by Chad Killingsworth, Closure Compiler committer</span></p>A Googlerhttp://www.blogger.com/profile/07002962734146179522noreply@blogger.com0tag:blogger.com,1999:blog-2437909874160353836.post-54027357106913707012012-06-01T14:12:00.000-07:002012-06-01T14:12:51.416-07:00Subtyping Functions Without Poking Your Eyes OutPop quiz: suppose you see two Closure Compiler type annotations.<br />
<br />
A) <code>{function(Object)}</code><br />
B) <code>{function(Array)}</code><br />
<br />
Which one is the subtype?<br />
<br />
Telling you that the right answer is (A) feels a lot like driving on the wrong side of the road. Try reading it out loud.<br />
<br />
Right Answer: "A function taking an Object IS A function taking an Array"<br />
Wrong Answer: "A function taking an Array IS A function taking an Object"<br />
<br />
Saying the right answer feels so wrong! Saying the wrong answer feels so right! We often have to do multiple rounds of whiteboarding the problem to try to explain it to other JS engineers.<br />
<br />
This is not a unique problem to JavaScript. Most object oriented languages have the same issue. But JavaScript engineers are used to living without types. With Closure, suddenly you have types. And you have lots of complex function types that real OO languages don't have, and that you're probably unfamiliar with if you haven't used a functional language.<br />
<br />
The problem, I think, goes back to a lot of "Intro to Objects and Classes" books that teach the "<a href="http://en.wikipedia.org/wiki/Is-a">is-a</a>" relationship. An apple IS A fruit. A blog IS A website. A werewolf IS A man but also IS A wolf.<br />
<br />
The "is-a" wording is an oversimplification that breaks down if you're not careful. <a href="http://en.wikipedia.org/wiki/Covariance_and_contravariance_%28computer_science%29#Need_for_covariant_argument_types.3F">This wikipedia page</a> gives a good counterexample, obtusely explained. Suppose you define "A Doctor" as a person that can treat all patients, and a Pediatrician as a person that can only treat children. If we need a Doctor that can treat all patients, then a Pediatrician is not an acceptable substitude. So, counterintuitively, a Pediatrician is not a subclass a Doctor.<br />
<br />
Oddly, a Pediatrician is a <em>superclass</em> of this "Doctor." If you need a pediatrician, a doctor that can treat all patients is an acceptable substitute.<br />
<br />
What you really want is to define a Doctor as "a person that can treat at least one patient." You might call this the Empty Doctor or (for the calculus nerds) the Epsilon Doctor. This doctor can treat some patient, somewhere. But if you go to see the Epsilon Doctor, it's likely that they won't know how to treat you. A pediatrician is a subclass of the Epsilon Doctor, because a pediatrician can treat some patients.<br />
<br />
Conversely, when you have a <code>{function(Object)}</code>, this does not mean "a function that can take some object". It means "a function that knows how to handle all objects." A <code>{function(Object)}</code> is substitutable any place you need a <code>{function(Array)}</code>.<br />
<br />
<span class="post-author">Posted by Nick Santos, Software Engineer</span>A Googlerhttp://www.blogger.com/profile/07002962734146179522noreply@blogger.com3tag:blogger.com,1999:blog-2437909874160353836.post-13644193158737695422012-02-24T09:02:00.004-08:002012-02-25T11:48:58.625-08:00Type-checking TipsClosure Compiler’s <a href="https://developers.google.com/closure/compiler/docs/js-for-compiler#types" style="font-weight: normal; ">type language</a> is a bit complicated. It has unions (“variable x can be A or B”), structural functions (“variable x is a function that returns a number”), and record types (“variable x is any object with properties foo and bar”).<br /><br />A lot of people have told us that that’s still not expressive enough. There are many ways that you can write JavaScript that do not fit cleanly into our type system. People have suggested that we should add <a href="http://en.wikipedia.org/wiki/Mixin" style="font-weight: normal; ">mixins</a>, <a href="http://traitsjs.org/" style="font-weight: normal; ">traits</a>, and <a href="http://groups.google.com/group/closure-compiler-discuss/browse_thread/thread/8f0b3a9330a9e0b2" style="font-weight: normal; ">post-hoc naming of anonymous objects</a>.<br /><br />This was not particularly surprising to us. The rules of objects in JavaScript are a little bit like the rules of <a href="http://calvinandhobbes.wikia.com/wiki/Calvinball">Calvinball</a>. You can change anything, and make up new rules as you go along. A lot of people think that a good type system gives you a powerful way to describe how your program is structured. But it also gives you a set of rules. The type system ensures that everyone agrees on what a “class” is, and what an “interface” is, and what “is” means. When you’re trying to add type annotations to untyped JS, you’re inevitably going to run into issues where the rules in my head don’t quite match the rules in your head. That’s OK.<br /><br />But we were surprised that when we gave people this type system, they often found multiple ways to express the same thing. Some ways worked better than others. I thought I’d write this to describe some of the things that people tried, and how they worked out.<br /><br /><b>Function vs. function()</b><br /><br />There are two ways to describe a function. One is to use the {Function} type, which the compiler literally interprets as “any object x where ‘x instanceof Function’ is true”. A {Function} is deliberately mushy. It can accept any arguments, and return anything. You can even use ‘new’ on it. The compiler will let you call it however you want without emitting warnings.<br /><br />A structural function is much more specific, and gives you fine-grained control over what the function can do. A {function()} takes no arguments, but we don’t care what it returns. A {function(?): number} returns a number and takes exactly one argument, but we don’t care about the type of that argument. A {function(new:Array)} creates an Array when you call it with “new”. Our <a href="http://code.google.com/closure/compiler/docs/js-for-compiler.html#types">type documentation</a> and <a href="http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml?showone=JavaScript_Types#JavaScript_Types">JavaScript style guide</a> have more examples of how to use structural functions.<br /><br />A lot of people have asked us if {Function} is discouraged, because it’s less specific. Actually, it’s very useful. For example, consider the definition of <a href="https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind">Function.prototype.bind</a>. It lets you curry functions: you can give it a function and a list of arguments, and it will give you back a new function with those arguments “pre-filled in”. It’s impossible for our type system to express that the returned function type is a transformation of the type of the first argument. So the JSDoc on Function.prototype.bind says that it returns a {Function}, and the compiler has to have hand-coded logic to figure out the real type.<br /><br />There are also many cases where you want to pass a callback function to collect results, but the results are context-specific.<br /><pre><br />rpc.get(‘MyObject’, function(x) {<br /> // process MyObject<br />});<br /></pre><br />The “rpc.get” method is a lot more clumsy if the callback argument you pass has to type-cast anything it gets. So it’s often easier just to give the parameter a {Function} type, and trust that the caller type isn’t worth type-checking.<br /><br /><b>Object vs. Anonymous Objects</b><br /><br />Many JS libraries define a single global object with lots of methods. What type annotation should that object have?<br /><pre><br />var bucket = {};<br />/** @param {number} stuff */ bucket.fill = function(stuff) {};<br /></pre><br />If you come from Java, you may be tempted to just give it type {Object}.<br /><pre><br />/** @type {Object} */ var bucket = {};<br />/** @param {number} stuff */ bucket.fill = function(stuff) {};<br /></pre><br />That’s usually not what you want. If you add a “@type {Object}” annotation, you’re not just telling the compiler “bucket is an Object.” You’re telling it “bucket is allowed to be any Object.” So the compiler has to assume that anybody can assign any object to “bucket”, and the program would still be type-safe.<br /><br />Instead, you’re often better off using @const.<br /><pre><br />/** @const */ var bucket = {};<br />/** @param {number} stuff */ bucket.fill = function(stuff) {};<br /></pre><br />Now we know that bucket can’t be assigned to any other object, and the compiler’s type inference engine can make much stronger checks on bucket and its methods.<br /><br /><b>Can Everything Just Be a Record Type?</b><br /><br />JavaScript’s type system isn’t that complicated. It has 8 types with special syntax: null, undefined, boolean, number, string, Object, Array, and Function. Some people have noticed that record types let you define “an object with properties x, y, and z”, and that typedefs let you give a name to any type expression. So between the two, you should be able to define any user-defined type with record types and typedefs. Is that all we need?<br /><br />Record types are great when you need a function to accept a large number of optional parameters. So if you have this function:<br /><pre><br />/**<br /> * @param {boolean=} withKetchup<br /> * @param {boolean=} withLettuce<br /> * @param {boolean=} withOnions<br /> */<br />function makeBurger(withKetchup, withLettuce, withOnions) {}<br /></pre><br />you can make it a bit easier to invoke like this:<br /><pre><br />/**<br /> * @param {{withKetchup: (boolean|undefined),<br /> withLettuce: (boolean|undefined),<br /> withOnions: (boolean|undefined)}=} options<br /> */<br />function makeBurger(options) {}<br /></pre><br />This works well. But when you use the same record type in many places across a program, things can get a bit hairy. Suppose you create a type for makeBurger’s parameter:<br /><pre><br />/** @typedef {{withKetchup: (boolean|undefined),<br /> withLettuce: (boolean|undefined),<br /> withOnions: (boolean|undefined)}=} */<br />var BurgerToppings;<br /><br />/** @const */<br />var bobsBurgerToppings = {withKetchup: true};<br /><br />function makeBurgerForBob() {<br /> return makeBurger(bobsBurgerToppings);<br />}<br /></pre><br />Later, Alice builds a restaurant app on top of Bob’s library. In a separate file, she tries to add onions, but screws up the API.<br /><pre><br />bobsBurgerToppings.withOnions = 3;<br /></pre><br />Closure Compiler will notice that bobsBurgerToppings no longer matches the BurgerToppings record type. But it won’t complain about Alice’s code. It will complain that Bob’s code is making the type error. For non-trivial programs, it might be very hard for Bob to figure out why the types don’t match anymore.<br /><br />A good type system doesn’t just express contracts about types. It also gives us a good way to assign blame when code breaks the contract. Because a class is usually defined in one place, the compiler can figure out who’s responsible for breaking the definition of the class. But when you have an anonymous object that’s passed to many different functions, and has properties set from many disparate places, it’s much harder--for both humans and compilers--to figure out who’s breaking the type contracts.<br /><br />Posted by Nick Santos, Software Engineer<span style="font-weight: normal; "><span></span></span><span class="post-author" style="font-family: Georgia, serif; "></span>A Googlerhttp://www.blogger.com/profile/07002962734146179522noreply@blogger.com4tag:blogger.com,1999:blog-2437909874160353836.post-59915769931859420242011-11-12T14:58:00.000-08:002011-11-12T15:04:51.103-08:00Introducing Closure Stylesheets<div>(CSS is for programming, not for pasting)</div><br /><div>When the <a target="blank" href="http://googlecode.blogspot.com/2009/11/introducing-closure-tools.html">Closure Tools</a> were first released a little over two years ago, they gave web developers the ability to organize and optimize their JavaScript and HTML in a new way. But there was something missing, namely, a tool to help manage <a target="blank" href="http://www.w3.org/Style/CSS/Overview.en.html">CSS</a>.</div><div><br /></div><div>You see, the nature of CSS runs contrary to the <a target="blank" href="http://en.wikipedia.org/wiki/Don%27t_repeat_yourself">DRY principle</a> that is exhibited in good software engineering. For example, if there is a color that should be used for multiple classes in a stylesheet, a developer has no choice but to copy-and-paste it everywhere because CSS has no concept of <a target="blank" href="http://code.google.com/p/closure-stylesheets/#Variables">variables</a>. Similarly, if there is a value in a stylesheet that is derived from other values, there is no way to express that because CSS also lacks <a target="blank" href="http://code.google.com/p/closure-stylesheets/#Functions">functions</a>. Common patterns of style blocks are duplicated over and over because CSS has no macros. All of these properties of CSS conspire to make stylesheets extremely difficult to maintain.</div><div><br /></div><div>To this end, we are excited to introduce the missing piece in the Closure Tools suite: <a target="blank" href="http://code.google.com/p/closure-stylesheets/">Closure Stylesheets</a>. Closure Stylesheets is an an extension to CSS that adds variables, functions, <a target="blank" href="http://code.google.com/p/closure-stylesheets/#Conditionals">conditionals</a>, and <a target="blank" href="http://code.google.com/p/closure-stylesheets/#Mixins">mixins</a> to standard CSS. The tool also supports <a target="blank" href="http://code.google.com/p/closure-stylesheets/#Minification">minification</a>, <a target="blank" href="http://code.google.com/p/closure-stylesheets/#Linting">linting</a>, <a target="blank" href="http://code.google.com/p/closure-stylesheets/#RTL_Flipping">RTL flipping</a>, and CSS class <a target="blank" href="http://code.google.com/p/closure-stylesheets/#Renaming">renaming</a>. As the existing Closure Tools have done for JavaScript and HTML, Closure Stylesheets will help you write CSS in a maintainable way, while also empowering you to deliver optimized code to your users. We hope you enjoy it! Please let us know what you think in the <a target="blank" href="https://groups.google.com/group/closure-stylesheets-discuss/?pli=1">discussion forum</a>.</div><br /><div><i>By Michael Bolin, Open Source Engineer</i></div><br /><div><i>Cross posted from the <a href="http://google-opensource.blogspot.com/2011/11/introducing-closure-stylesheets.html">Google Open Source Blog</a>.</i></div>A Googlerhttp://www.blogger.com/profile/07002962734146179522noreply@blogger.com8tag:blogger.com,1999:blog-2437909874160353836.post-88935082052893827612011-01-25T14:15:00.000-08:002011-01-25T14:37:56.308-08:00A Property By Any Other Name, Part 3This is the last in a series of blog posts on how Closure Compiler decides what properties. <a href="http://closuretools.blogspot.com/2011/01/property-by-any-other-name-part-1.html">Part 1</a> was about the <code>--compilation_level=ADVANCED_OPTIMIZATIONS</code> flag and <a href="http://closuretools.blogspot.com/2011/01/property-by-any-other-name-part-2.html">part 2</a> was about renaming policies that didn't work. This blog post will be a bit of a grab bag of newer tools for better property renaming.<br /><br /><h3>Using Type Checking to Fill in Missing Externs</h3><br />Your <a href="http://code.google.com/closure/compiler/docs/api-tutorial3.html#externs">externs file</a> should declare all the properties that are defined outside of your program. If you haven't done this before, then finding all those properties can be a pain. Fortunately, Closure Compiler can point us in the right direction by checking for missing properties.<br /><br />There are a few ways to turn on the missing properties check. For example, you can specify the flags:<br /><code>--warning_level=VERBOSE --jscomp_warning=missingProperties</code><br />or<br /><code>--jscomp_warning=checkTypes</code><br />The compiler will try to find places where you've used dot access (<code>foo.bar</code>) to read a property that can't possibly be defined on that object, perhaps because you've forgotten to declare it in your externs.<br /><br />Notice that this check is subtly different than compiler checks in more static languages, like Java. The Java compiler uses a "must-define" approach: the property <code>bar</code> must be declared on all possible values of <code>foo</code> (except <code>null</code>), or it will be a compiler error. Closure Compiler uses a "may-define" approach. It only requires that some possible value of <code>foo</code> has a property <code>bar</code>. For example, if you have:<br /><br /><pre>function f(x) {<br /> return x.apartment;<br />}</pre><br /><br />Closure Compiler will emit a warning if the <code>apartment</code> property is not assigned anywhere in the program. Similarly, if you have:<br /><br /><pre>/** @param {Element} x */<br />function f(x) {<br /> return x.apartment;<br />}</pre><br /><br />the compiler will emit a warning if the <code>apartment</code> property is not assigned on any object that could possibly be an <code>Element</code>. It will <em>not</em> emit a warning if <code>apartment</code> is assigned on some specific subtype of <code>Element</code>, like <code>HTMLTextAreaElement</code>.<br /><br />As you can see, you don't need complete type annotations to use this check, but more type annotations will get better results.<br /><br /><h3>Using Type Analysis for Better Renaming</h3><br />If a property is listed in the externs file under the "All Unquoted" naming policy, that property will not be renamed anywhere in the program. This is a bummer. We went through a lot of trouble to make the Closure Library events API consistent with the native browser events API. But because we gave the methods the same name as extern methods, those methods can't be renamed. Could we use type information to differentiate between method calls on user-defined objects from method calls on browser-defined objects?<br /><br />We can. Closure Compiler's Java API has two options: <code>disambiguateProperties</code> and <code>ambiguateProperties</code>.<br /><br />Disambiguation means that Closure Compiler will look at all accesses to a property<br /><code>x</code> in the program. If two types have a property <code>xx</code>// externs file<br />/** @constructor */ function Element() {}<br />Element.prototype.id;<br /><br />// user code<br />/** @constructor */<br />function MyWidget() {<br /> this.id = 3;<br />}<br /><br />Disambiguate properties will rename this to something like:<br /><br /><pre>/** @constructor */<br />function MyWidget() {<br /> this.MyWidget$id = 3;<br />}</pre><br /><br />By design, disambiguate properties gives things very verbose names, on the assumption that they will be given shorter names by the "All Unquoted" naming policy. This makes it easier to debug, because you can turn off this optimization independently of "all unquoted" property renaming.<br /><br />Disambiguate properties allows us to rename some properties that are in the externs file, but it creates a new problem: there are more unique properties, which makes the gzipped code bigger. To solve this problem, we use <code>ambiguateProperties</code> to minify the number of unique properties. Ambiguate properties will look at two property names on different objects such that there's no chance those objects will appear in the same variable. Then it will give those properties the same name.<br /><br />Disambiguate and ambiguate properties are very conservative. They will only rename things if they are reasonably sure that it's safe to do so. (They can never be absolutely sure, because you could always pass in external objects that violate the declared types.) These optimizations only make sense when used in conjunction with "All Unquoted" renaming.<br /><br /><h3>Short Names Aren't Necessarily Better</h3><br />So far in this series, we've been assuming that short names make your binary smaller, and will always be better than long names.<br /><br />That makes sense if you're sending your entire JS file across the network. But what if your visitors had old versions of your JS in their cache? You might want to figure out what version they have, and send them only the parts that had changed.<br /><br />This is called <a href="http://en.wikipedia.org/wiki/Delta_encoding">delta encoding</a>. If the compiler is choosing the shortest possible names for your properties, then small changes to your JS may change every compiled property in the output. The delta between two versions may be as large as the original files.<br /><br />What we really want is a way to tell the compiler, "give these properties the shortest possible names, unless you've seen them before, and in that case give them the same name you gave them last time." The compiler has 4 flags for this:<br /><br /><pre>--variable_map_input_file<br />--variable_map_output_file<br />--property_map_input_file<br />--property_map_output_file</pre><br /><br />The output maps from one compilation can be used as the input map for the next compilation. Although the compiler cannot guarantee that a property will be renamed the same way in both binaries, it will make a best-effort attempt to do so.<br /><br />That covers most of our major property renaming policies. If you have ideas for more, let us know at the <a href="http://groups.google.com/group/closure-compiler-discuss">Closure Compiler discussion group</a>.<br /><br /><span class="post-author">Posted by Nick Santos, Software Engineer</span>A Googlerhttp://www.blogger.com/profile/07002962734146179522noreply@blogger.com2tag:blogger.com,1999:blog-2437909874160353836.post-9555570839009456302011-01-21T13:52:00.001-08:002011-01-21T13:59:29.701-08:00A Property By Any Other Name, Part 2This is the second in a series of blog posts on how Closure Compiler decides what properties to rename with the <code>--compilation_level=ADVANCED_OPTIMIZATIONS</code> flag. <a href="http://closuretools.blogspot.com/2011/01/property-by-any-other-name-part-1.html">Part 1</a> talks about the current algorithm. This blog post will focus on property renaming policies that we tried that didn't work so well.<br /><br />In the beginning, we tried to use coding conventions to decide when to rename things. Uppercase property names (<code>foo.MyMethod</code>) were renamed, and lowercase property names were not renamed. This didn't work well. One man's internal code is another man's external library. Sometimes you really didn't want uppercase property names to be renamed. Changing your code to use this convention meant breaking your API.<br /><br />Later, we tried to move towards "smarter" algorithms, ones that did not require the programmer to be aware of renaming policies. These were called the "heuristic" property renaming policies. These algorithms looked at the entire input to the compiler, and tried to find all writes and reads to a specific property. If it saw at least one write to the property, and was reasonably sure that all the reads of that property came from those writes, then it renamed them all.<br /><br />In small apps, heuristic renaming policies worked well. They were not very powerful, but they were easy to migrate to. Even when you didn't declare all the properties on external objects in the externs file, you'd usually still be ok. There would be no property writes to that property name, so the compiler wouldn't try to rename it.<br /><br />But for medium to large apps, these advantages were a curse. Consider the following code:<br /><br /><pre>/** @param {Object} json Some external JSON.<br />function f(json) {<br />return json.estate;<br />}<br />window['__receive_json'] = f;<br /><br />// ...<br /><br />// in some other code base<br />Foo.prototype.estate = 3;<br />f(new Foo());</pre><br /><br />If these were the only two appearances of the property <code>estate</code> in your binary, the compiler would rename it. The compiler can't tell that you're calling <code>f</code> from external code, and that you expect <code>estate</code> to be preserved.<br /><br />You could have this piece of code that worked for years and years. Then, somebody who you never met could add Foo.prototype.estate in a different part of the codebase. It would break your code for no obvious reason, and the breaking change would be difficult to track down. When we have common JavaScript libraries, this becomes orders of magnitude more problematic. Adding Foo.prototype.estate could break any of the 25 products that depend on your library in subtle and difficult-to-debug ways.<br /><br />Even if you did find the problem, how would you work around it? If this is shared code, then changing <code>json.estate</code> to something like <code>json['estate']</code> might break other projects that depend on it, because their binaries do expect <code>estate</code> to get renamed.<br /><br />Because of these problems, most projects that use Closure Compiler do not use heuristic renaming algorithms. But heuristic renaming wasn't a total failure. We learned some useful lessons:<br /><ul><br /><li>If the compiler looks at your whole program to determine whether a property should be renamed, then that means a change in one part of the program can change property renaming in an unrelated part of the program.<br /></li><li>If your code is shared across projects, then you probably want the property to be renamed in all projects or none of them.<br /></li><li>When renaming properties, it's better to be transparent and 90% accurate than to be cryptic and 99% accurate.<br /></li></ul><br /><br />Could we use these lessons to develop a better renaming algorithm? We'll talk about this more in Part 3.<br /><br /><span class="post-author">Posted by Nick Santos, Software Engineer</span>A Googlerhttp://www.blogger.com/profile/07002962734146179522noreply@blogger.com3tag:blogger.com,1999:blog-2437909874160353836.post-43242031889142249342011-01-18T13:47:00.000-08:002011-01-18T14:36:56.782-08:00A Property By Any Other Name, Part 1When you use Closure Compiler's <code>--compilation_level=ADVANCED_OPTIMIZATIONS</code> flag, the compiler will try to rename properties on your objects. For example, it may rename <code>x.longPropertyName</code> to <code>x.a</code>.<br /><br />Because property renaming is a complex topic, we're going to split this discussion up into three blog posts. Part 1 is about the property renaming that you get with <code>ADVANCED_OPTIMIZATIONS</code>. Part 2 will be about other property renaming algorithms we've tried that didn't work so well. Part 3 will be about property renaming algorithms that we're currently experimenting on and are available from the Java API.<br /><br />If you're using Closure Compiler's Java API, you have more fine-grained control over what renaming the compiler does. The API treats variable renaming (<code>foo.bar</code> -> <code>a.bar</code>) and property renaming (<code>foo.bar</code> -> <code>foo.a</code>) as completely independent optimizations. You can choose a variable renaming policy and a property renaming policy. The best property renaming policy, "All Unquoted," is what you get when you use <code>ADVANCED_OPTIMIZATIONS</code>. Most large Google projects use it. It significantly changes how we write JavaScript.<br /><br />In the general case, a compiler can't rename properties at compile-time. You simply don't have enough information to try. There will always be objects that come from external sources that the compiler can't see (like JSON responses from the server), and property names that are undecidable. (Consider the expression <code>foo[undecidableFunction()] = function(){};</code>.) So property renaming can never be perfect. There will always be rules and gotchas.<br /><br />Before we talk about the best property renamer, "All Unquoted," we have to define what we mean by "best." Usually, we use three criteria.<br /><br /><ol><li>Power: How much smaller does it make your code?<br /><br /></li><li>Failure Cases: If it renames properties incorrectly, how easy is it to figure out what went wrong? How easy is it to fix the issue? If you make a change, how confident can you be that it won't break renaming?<br /><br /></li><li>Migration: How easy is it to update a legacy codebase so that it can take advantage of property renaming?<br /></li></ol><br /><br />"All Unquoted" renaming was designed to optimize for #2: making the failure cases easy to debug and correct. By design, the algorithm is transparent and simple.<br /><br /><ol><li>If a property is in the externs file, don't rename it.<br /><br /></li><li>If the property appears in quotes, don't rename it.<br /><br /></li><li>Otherwise, rename it.<br /></li></ol><br /><br />For example, if you write the code:<br /><br /><pre>var obj = {<br />alice: true,<br />'bob': true<br />};<br />obj.claire = true;<br />obj.document = true;<br />window['obj'] = obj;<br /></pre><br /><br />then you will get something that looks like this:<br /><br /><pre>var a = {<br />a: true, // alice was not in quotes or in the externs file<br />bob: true // bob was in quotes<br />};<br />a.b = true; // claire was not in quotes or in the externs file<br />a.document = true; // document was in the externs file<br />window.obj = a; // obj was in quotes<br /></pre><br /><br />If you use the <code>--debug</code> flag, the same properties still get renamed, but now it will be much easier to see what the original names were:<br /><br /><pre>var $obj$$ = {<br />$alice$: true,<br />'bob': true<br />};<br />$obj$$.$claire$ = true;<br />$obj$$.document = true;<br />window['obj'] = $obj$$;<br /></pre><br /><br />This has some nice features that help debugging and development. It's straightforward for the average programmer to look at the compiled output and figure out why the compiler is renaming something, and what the name should be. If we decide that we don't want the property "claire" to be renamed, then we can change <code>obj.claire</code> to <code>obj['claire']</code>.<br /><br />Furthermore, this convention makes it easier to read and refactor code written by a large team of JavaScript developers. If Bob is using "All Unquoted," and he has a method defined as <code>Foo.prototype.methodA = fn</code>, then Alice can easily search for all calls to <code>methodA</code> in the codebase. She doesn't have to worry about opaque accesses to the method, like <code>obj['method' + 'A']</code>, because she knows that the compiler will break those accesses anyway.<br /><br />Another way to look at it is that we use the dotted access (<code>obj.alice</code>) for compile-time property lookups, and array access (<code>obj['alice']</code>) for run-time property lookups.<br /><br />But there are some big downsides to "All Unquoted." As you saw above, any property in the externs file cannot be renamed anywhere in the program. When your methods have the same names as native browser methods, they won't be renamed. It's not as powerful as it could be.<br /><br />Even worse, it is difficult to safely convert a legacy codebase to use this renaming policy. Because you never had to declare your "external" properties, you probably didn't, and it's a bear to find them all.<br /><br />Could we do better? Maybe there's additional information we could leverage to get fewer false positives and false negatives? Perhaps we could look at the type annotations, or at other property assignments in the program? We'll get to those questions in the next two posts.<br /><br /><span class="post-author">Posted by Nick Santos, Software Engineer</span>A Googlerhttp://www.blogger.com/profile/07002962734146179522noreply@blogger.com1tag:blogger.com,1999:blog-2437909874160353836.post-2259602601539015212010-10-12T14:04:00.000-07:002010-10-12T14:15:40.288-07:00This “this” is Your ThisIn <a href="http://closuretools.blogspot.com/2010/08/this-var-is-my-var.html">a past blog post</a>, we talked about how Closure Compiler makes it easier to share common JavaScript by ensuring that everybody declares what variables they own.<br /><br />Global variable uniqueness is something that we added checks for fairly early on. Some restrictions are less obvious. In this blog post we’ll talk about the <code>this</code> keyword.<br /><br />Suppose Nathan wants to outsource hot dog eating contests, so that we don’t need an instance of Nathan to run one. To do so, he takes <code>runHotDogContest</code> and <code>unpackHotDogs</code> off the prototype, and makes them into static methods. The code now looks like this:<br /><br /><pre>Nathan.runHotDogContest = function(player, boxes) {<br /> for (var i = 0; i < boxes.length; i++) {<br /> player.eatHotDogs(this.unpackHotDogs(boxes[i]));<br /> }<br />};</pre><br /><br />I want to run 2 hot dog contests, so naturally, I write:<br /><br /><pre>var run = Nathan.runHotDogContest;<br />run(joey, crateA);<br />run(kobayashi, crateB);</pre><br /><br />The code fails with an error that <code>unpackHotDogs</code> is not defined on <code>this</code>. The reason is subtle. To the person writing <code>Nathan.runHotDogContest</code>, <code>this</code> and <code>Nathan</code> seem like interchangeable variables. And as long as you’re testing them by invoking them as:<br /><br /><pre>Nathan.runHotDogContest(joey, crateA);<br />Nathan.runHotDogContest(kobayashi, crateB);</pre><br /><br />then they will be interchangeable.<br /><br />In fact, <code>this</code> is a secret argument to the function. It’s much like any other function argument, except that it appears on the left side of the function call instead of on the right side. So <code>Nathan.runHotDogContest(...)</code> passes <code>Nathan</code> as the <code>this</code> argument, and <code>run(...)</code> passes <code>null</code> as the <code>this</code> argument (which JavaScript helpfully coerces to window).<br /><br />To make Closure Library usable, the library authors and the library users need to agree on what the arguments to a function mean. This includes <code>secret</code> arguments like <code>this</code>. So we’ve agreed that only constructors and prototype methods may use <code>this</code>, and the <code>this</code> argument must be an instanceof the relevant constructor. Closure Compiler enforces this in <code>--warning_level VERBOSE</code>, and will often emit a warning if it sees <code>this</code> used in a dangerous place.<br /><br />If you’re writing a function that expects an unusual <code>this</code> context, you can explicitly document it with <a href="http://www.google.com/url?q=http%3A%2F%2Fgoogle-styleguide.googlecode.com%2Fsvn%2Ftrunk%2Fjavascriptguide.xml%3Fshowall%3Dy%23tag-this">the <code>@this</code> annotation</a>, and the warning will go away.<br /><br />Good luck with all of this!<br /><br /><span class="post-author">Posted by Nick Santos, Software Engineer</span>A Googlerhttp://www.blogger.com/profile/07002962734146179522noreply@blogger.com2tag:blogger.com,1999:blog-2437909874160353836.post-55437219885777995942010-08-31T15:45:00.000-07:002010-08-31T16:55:09.170-07:00Introducing Closure LinterWhen 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 <a href="http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml">Google JavaScript Style Guide</a>. <br /><br />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.<br /><br />Take for example, this code:<br /><br /><pre>var x = 10<br />var y=20;<br /><br />for(var i = 0;i < 10; i++ ) {<br /> x += i;<br /> y -= i;<br />}<br /><br />var z = [10, 20,];<br /><br />x = y + z[0]<br /> + 10;</pre><br />When we run <code>gjslint --strict fixme.js</code> we get<br /><pre>Line 1, E:0010: (New error) Missing semicolon at end of line<br />Line 2, E:0002: Missing space before "="<br />Line 2, E:0002: Missing space after "="<br />Line 4, E:0002: Missing space before "("<br />Line 4, E:0002: Missing space after ";" in for statement<br />Line 4, E:0001: Extra space before ")"<br />Line 6, E:0006: (New error) Wrong indentation: expected any of {2} but got 3<br />Line 9, E:0121: Illegal comma at end of array literal<br />Line 12, E:0120: Binary operator should go on previous line "+"<br />Found 9 errors, including 2 new errors, in 1 files (0 files OK).</pre><br />Even better, if we run <code>fixjsstyle --strict fixme.js</code>, 7 of the 9 errors are automatically fixed for us!<br /><br />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 <a href="http://code.google.com/closure/utilities/docs/linter_howto.html">How to Use Closure Linter</a> page.<br /><br />We welcome comments and questions in <a href="http://groups.google.com/group/closure-linter-discuss">the discussion forum</a>.<br /><br /><span class="post-author">Posted by Robby Walker and Andy Perelson, Software Engineers</span>A Googlerhttp://www.blogger.com/profile/07002962734146179522noreply@blogger.com20tag:blogger.com,1999:blog-2437909874160353836.post-10220654789720771882010-08-30T13:34:00.000-07:002010-08-30T13:50:11.203-07:00This Var is My VarThe 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 <code>--warning_level VERBOSE</code> flag.<br /><br />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, <a href="http://blogs.msdn.com/b/ie/archive/2010/04/26/feedback-on-the-ie9-platform-preview.aspx">fixes for IE9</a> 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.<br /><br />Suppose Joey writes some library code:<br /><br /><pre>Joey.prototype.eatHotDogs = function(hotDogs) {<br /> for (i = 0; i < hotDogs.length; i++) {<br /> this.eat(hotDogs[i]);<br /> }<br />};</pre><br />Next summer, Nathan writes an application to feed Joey HotDogs by the boxful:<br /><br /><pre>Nathan.prototype.runHotDogContest = function(player, boxes) {<br /> for (i = 0; i < boxes.length; i++) {<br /> player.eatHotDogs(this.unpackHotDogs(boxes[i]));<br /> }<br />};</pre><br />Surprisingly, when Nathan runs his code in a browser, it tries to feed Joey an infinite number of hot dogs and crashes the browser.<br /><br />The problem, of course, is that JavaScript "helpfully" declares variables for you if you forgot. No one declared <code>i</code>, so a variable <code>i</code> 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 <code>eatHotDogs()</code> was "resetting" the <code>i</code> in his loop every time he called it.<br /><br />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 <code>var</code> 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.<br /><br />In <code>VERBOSE</code> mode, Closure Compiler enforces that all variables must be declared with the <code>var</code> or <code>function</code> or <code>catch</code> keywords. Global variables may only be declared once. The Google JS style guide has <a href="http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml#Naming">naming conventions</a> to make these collisions even less likely.<br /><br />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 <a href="http://code.google.com/closure/compiler/docs/api-tutorial3.html#externs">externs files</a>, 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 <code>Node</code> because it will conflict with <a href="http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-1950641247">DOM Nodes</a>.<br /><br />Try running Closure Compiler with <code>--warning_level=VERBOSE</code> mode and see what you find in your code!<br /><br /><span class="post-author">Posted by Nick Santos, Software Engineer</span>A Googlerhttp://www.blogger.com/profile/07002962734146179522noreply@blogger.com4tag:blogger.com,1999:blog-2437909874160353836.post-40923591975881693262010-07-14T11:05:00.000-07:002010-07-14T11:24:33.972-07:00Introducing the Closure Library EditorOne of the <a href="http://closure-library.googlecode.com/svn/trunk/closure/goog/ui/">many UI widgets</a> included in the Closure Library is a full-featured rich text editor.<br /> <br />All modern browsers have rich text editing functionality built in — unfortunately this functionality is at best inconsistent and, at worst, broken. Closure Library’s editor is a sub-project within Closure. It provides a common, powerful, and extensible interface that abstracts the cross-browser inconsistencies and shortcomings of rich text editing.<br /> <br />We use the Closure editor in Gmail, Google Sites, Google Groups, and many other Google products. We’re very happy to be able to share this editor with you as part of the Closure Library.<br /> <br /><h4>Using the editor in your project</h4><br />A <a href="http://code.google.com/p/closure-library/source/browse/trunk/closure/goog/demos/editor/editor.html">demo of the basic editor functionality</a> is included in the source distribution, and can be tried <a href="http://closure-library.googlecode.com/svn/trunk/closure/goog/demos/editor/editor.html">here</a>.<br /> <br />The most important code is as follows. First, we create an editable field and attach it to an element with the id <code>editMe</code>.<br /> <br /><pre>// Create an editable field.<br />var myField = new goog.editor.Field('editMe');</pre> <br />Next, we register editing <em>plugins</em>. The rich text editor uses a plugin-based architecture in order to support many products with different feature sets. For example, in Gmail, the tab key moves the cursor to the send button, while in Google Sites it either adds 4 spaces or indents the current bulleted list. Plugins allow us to create modular features for the Editor and let each application pick and choose which ones they need or want. This ensures each application only brings in the code it needs, helping to minimize code size and latency.<br /> <br /><pre>// Create and register all of the editing plugins you want to use.<br />myField.registerPlugin(new goog.editor.plugins.BasicTextFormatter());<br />myField.registerPlugin(new goog.editor.plugins.RemoveFormatting());<br />myField.registerPlugin(new goog.editor.plugins.UndoRedo());<br />myField.registerPlugin(new goog.editor.plugins.ListTabHandler());<br />myField.registerPlugin(new goog.editor.plugins.SpacesTabHandler());<br />myField.registerPlugin(new goog.editor.plugins.EnterHandler());<br />myField.registerPlugin(new goog.editor.plugins.HeaderFormatter());<br />myField.registerPlugin(<br /> new goog.editor.plugins.LoremIpsum('Click here to edit'));<br />myField.registerPlugin(<br /> new goog.editor.plugins.LinkDialogPlugin());</pre><br />In a future post, we’ll discuss how you can use the plugin system to add your own custom functionality to your editor.<br /> <br />Next we set up our toolbar:<br /> <br /><pre>// Specify the buttons to add to the toolbar, using built in default buttons.<br />var buttons = [<br /> goog.editor.Command.BOLD,<br /> goog.editor.Command.ITALIC,<br /> goog.editor.Command.UNDERLINE,<br /> goog.editor.Command.FONT_COLOR,<br /> goog.editor.Command.BACKGROUND_COLOR,<br /> goog.editor.Command.FONT_FACE,<br /> goog.editor.Command.FONT_SIZE,<br /> goog.editor.Command.LINK,<br /> goog.editor.Command.UNDO,<br /> goog.editor.Command.REDO,<br /> goog.editor.Command.UNORDERED_LIST,<br /> goog.editor.Command.ORDERED_LIST,<br /> goog.editor.Command.INDENT,<br /> goog.editor.Command.OUTDENT,<br /> goog.editor.Command.JUSTIFY_LEFT,<br /> goog.editor.Command.JUSTIFY_CENTER,<br /> goog.editor.Command.JUSTIFY_RIGHT,<br /> goog.editor.Command.SUBSCRIPT,<br /> goog.editor.Command.SUPERSCRIPT,<br /> goog.editor.Command.STRIKE_THROUGH,<br /> goog.editor.Command.REMOVE_FORMAT<br />];<br />var myToolbar = goog.ui.editor.DefaultToolbar.makeToolbar(buttons,<br /> goog.dom.getElement('toolbar'));<br /> <br />// Hook the toolbar into the field.<br />var myToolbarController =<br /> new goog.ui.editor.ToolbarController(myField, myToolbar);</pre><br />And finally, we turn on editing:<br /> <br /><pre>myField.makeEditable();</pre><br />When we open the file in the browser, we get an HTML editor:<br /> <br /><a href="http://4.bp.blogspot.com/_QD-u0j65A7k/TD39-wlNSJI/AAAAAAAAACA/efLsJ8MesHE/editor.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 500px; height: 295px;" src="http://4.bp.blogspot.com/_QD-u0j65A7k/TD39-wlNSJI/AAAAAAAAACA/efLsJ8MesHE/s500/editor.png" /></a><br /> <br />Let us know in the comments if you’ve used or plan to use the Closure Library rich text editor in your project. If you have questions, please post them to the <a href="https://groups.google.com/group/closure-library-discuss">discussion group</a>.<br /><br /><span class="post-author">Posted by Robby Walker, Software Engineer</span>Nathan Nazehttp://www.blogger.com/profile/08280236711469825420noreply@blogger.com21tag:blogger.com,1999:blog-2437909874160353836.post-44152513725443516032010-07-01T18:06:00.000-07:002010-07-01T18:21:36.771-07:00Closure Compiler at O'Reilly Velocity Conference 2010I would like to thank everyone who stuck around the booth area for my whiteboard presentation on Closure Compiler last week. It was fun meeting all the developers who share the same passion for making fast and awesome web applications! I hope everyone would continue to find Closure Compiler useful in speeding up your applications.<br /><br />For those who did not get a chance to attend the conference, I wanted to share the slides with you:<br /><br /><iframe src="http://docs.google.com/present/embed?id=dgsp8w6z_80ffttw8c7&size=m" frameborder="0" width="555" height="451"></iframe><br /><br />Thanks again, and if you have questions, please drop us a note on the <a href="https://groups.google.com/group/closure-compiler-discuss/topics">Closure Compiler discussion list</a>.<br /><br /><span class="post-author">Alan Leung, Software Engineer, Closure Compiler team</span>Nathan Nazehttp://www.blogger.com/profile/08280236711469825420noreply@blogger.com1tag:blogger.com,1999:blog-2437909874160353836.post-20269528094277019212010-06-08T18:22:00.000-07:002010-06-08T18:34:23.336-07:00Closure Library Tech Talk at Google I/O, now on YouTubeThe video of our talk at Google I/O, <a href="http://code.google.com/events/io/2010/sessions/closure-library.html"><em>Opening Up Closure Library</em></a>, has been posted.<br /><br /><object width="540" height="385"><param name="movie" value="http://www.youtube.com/v/yp_9q3tgDnQ&hl=en_US&fs=1&"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/yp_9q3tgDnQ&hl=en_US&fs=1&" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="540" height="385"></embed></object><br /><br />The <a href="http://dl.google.com/googleio/2010/tech-talks-closure-library.pdf">session slides</a> are also available as a PDF.<br /><br /><span class="post-author">Posted by Nathan Naze, Closure Tools Team</span>Nathan Nazehttp://www.blogger.com/profile/08280236711469825420noreply@blogger.com0tag:blogger.com,1999:blog-2437909874160353836.post-81853998901167651212010-06-04T08:51:00.001-07:002010-06-04T09:07:30.840-07:00Closure Tools: Open for BusinessWhen we <a href="http://googlecode.blogspot.com/2009/11/introducing-closure-tools.html">open sourced the Closure Tools</a>, we were ecstatic to be getting such great and useful code out to the world. And since then, we’ve seen people do great stuff with Closure Tools. And then we got a little nervous. You see, the more cool stuff you do with Closure Tools, the more work we figured we should put into their open sourcing. Today, we’d like to describe our latest work making the Closure Tools even more open.<br /><br />I’m a member of the <a href="http://google-opensource.blogspot.com/">Open Source Programs Office</a> at Google, which means I help teams that are open sourcing Google code do it better and more easily. I’ve built a toolkit to help these teams called “Make Open Easy” (shameless plug: I’ll be presenting my work in more detail at <a href="http://www.oscon.com/oscon2010/public/schedule/detail/13833">OSCON</a> this year). It automates the processes of maintaining an open source codebase of Google code: publishing updates, merging patches made in subversion back into our internal source control, and keeping track of who’s done what. We’ve now “MOEified” <a href="http://code.google.com/p/closure-compiler">Closure Compiler</a> and <a href="http://code.google.com/p/closure-library">Library</a>. What does this mean for you?<br /><br />First, we’re going to push updates more often, regularly, and with descriptions of the changes. Updating the public version with the changes made at Google now takes minutes. For now, we’re not setting a schedule, but we expect that we shouldn’t go more than two weeks without updating the codebase in public Subversion. We hope you’ll appreciate getting code that’s fresh off the press.<br /><br />Second, we now want your patches! Since MOE has made merging patches written against the public codebase so easy, we want public contrubtions to the compiler and library. If there are bugs you’d like to fix or features you’d like to implement, feel free to send us a patch. We’re still going to hold patches to a high level of quality, design, and style, so consider talking to us first on our “discuss” lists (<a href="https://groups.google.com/group/closure-library-discuss">closure-library-discuss</a> and <a href="https://groups.google.com/group/closure-compiler-discuss">closure-compiler-discuss</a>). And, as before, if you have ideas but not code, we still welcome your thoughts. We’d like to work with you to shape Closure Tools.)<br /><br />The Closure Tools team is committed to being more transparent and collaborative but sometimes there still might be issues with releasing or accepting code. Please be patient as we work out kinks in the process.<br /><br />So, what’s the next feature for Closure Tools? Now’s your chance to show us!<br /><br /><span class="post-author">Posted by Dan Bentley, Open Source Programs Office</span>Nathan Nazehttp://www.blogger.com/profile/08280236711469825420noreply@blogger.com0tag:blogger.com,1999:blog-2437909874160353836.post-46700466620743723282010-05-19T10:45:00.000-07:002010-05-18T21:41:11.938-07:00Welcome to the Closure Tools blog<div><div>Last November, we <a href="http://googlecode.blogspot.com/2009/11/introducing-closure-tools.html">released Closure Tools</a> as open source software. These web development tools encompass three major components: a <a href="http://code.google.com/closure/compiler/">compiler</a>, a <a href="http://code.google.com/closure/library/">library</a>, and a <a href="http://code.google.com/closure/templates/">templating</a> system. Google engineers use these three tools to put together some of our largest web applications: Gmail, Google Docs, Google Sites, and many others. </div><div><br /></div><div>The response has been heartening. A number of projects have adopted Closure Compiler, both for its excellent performance as a minifier, but also for its compile-time optimizations and type checking. Many folks have picked up Closure Library and Closure Templates as the basis for their new web projects. Traffic on the <a href="https://groups.google.com/group/closure-compiler-discuss">three</a> <a href="https://groups.google.com/group/closure-library-discuss">discussion</a> <a href="https://groups.google.com/group/closure-templates-discuss">lists</a> has been growing.</div><div><br /></div><div>In conjunction with our events for the <a href="http://googlecode.blogspot.com/2009/11/introducing-closure-tools.html">library</a> and <a href="http://code.google.com/events/io/2010/officehours.html">compiler</a> at <a href="http://code.google.com/events/io/2010/">Google I/O</a>, we’re taking a few steps to help encourage that nascent community. The first to mention is this blog, on which we plan to publish notes, tips, and helpful articles from engineers working on Closure Tools. We’ve also started a <a href="http://twitter.com/closuretools">Twitter account</a> that you can follow. And, as of today, Closure Library joins Closure Compiler as a project that can take external patches from developers outside of Google.</div><div><br /></div><div>So add this blog to your feed reader (perhaps Google Reader, built with Closure Tools), follow us on Twitter, and, just maybe, submit a patch. Thanks!</div></div><div><br /></div><span class="post-author">Posted by Nathan Naze, Closure Tools Team</span>Nathan Nazehttp://www.blogger.com/profile/08280236711469825420noreply@blogger.com1