blob: 81a002be57dd7dcb3ce49b298b2309e281b1f8c1 [file] [log] [blame] [view]
andybons6eaa0c0d2015-08-26 20:12:521# Closure Compilation
2
dbeamb0b12672016-05-03 21:33:133## What is type safety?
andybons3322f762015-08-24 21:37:094
dbeamb0b12672016-05-03 21:33:135[Strongly-typed languages](https://en.wikipedia.org/wiki/Strong_and_weak_typing)
6like C++ and Java have the notion of variable types.
andybons3322f762015-08-24 21:37:097
dbeamb0b12672016-05-03 21:33:138This is typically baked into how you declare variables:
dbeam707cf272016-03-10 04:12:139
dbeamb0b12672016-05-03 21:33:1310```c++
11const int32 kUniversalAnswer = 42; // type = 32-bit integer
dbeame3d03b7c2016-02-06 03:08:2412```
13
dbeamb0b12672016-05-03 21:33:1314or as [templates](https://en.wikipedia.org/wiki/Template_metaprogramming) for
15containers or generics:
dbeame3d03b7c2016-02-06 03:08:2416
dbeamb0b12672016-05-03 21:33:1317```c++
18std::vector<int64> fibonacci_numbers; // a vector of 64-bit integers
dbeam43f31dd2016-03-09 22:05:5919```
20
dbeamb0b12672016-05-03 21:33:1321When differently-typed variables interact with each other, the compiler can warn
22you if there's no sane default action to take.
dbeam707cf272016-03-10 04:12:1323
dbeamb0b12672016-05-03 21:33:1324Typing can also be manually annotated via mechanisms like `dynamic_cast` and
25`static_cast` or older C-style casts (i.e. `(Type)`).
26
27Using stongly-typed languages provide _some_ level of protection against
28accidentally using variables in the wrong context.
29
30JavaScript is weakly-typed and doesn't offer this safety by default. This makes
31writing JavaScript more error prone, and various type errors have resulted in
32real bugs seen by many users.
33
34## Chrome's solution to typechecking JavaScript
35
36Enter [Closure Compiler](https://developers.google.com/closure/compiler/), a
37tool for analyzing JavaScript and checking for syntax errors, variable
38references, and other common JavaScript pitfalls.
39
40To get the fullest type safety possible, it's often required to annotate your
41JavaScript explicitly with [Closure-flavored @jsdoc
42tags](https://developers.google.com/closure/compiler/docs/js-for-compiler)
43
44```js
45/**
46 * @param {string} version A software version number (i.e. "50.0.2661.94").
qyearsleyc0dc6f42016-12-02 22:13:3947 * @return {!Array<number>} Numbers corresponding to |version| (i.e. [50, 0, 2661, 94]).
dbeamb0b12672016-05-03 21:33:1348 */
49function versionSplit(version) {
50 return version.split('.').map(Number);
51}
dbeam43f31dd2016-03-09 22:05:5952```
53
andybons6eaa0c0d2015-08-26 20:12:5254See also:
55[the design doc](https://docs.google.com/a/chromium.org/document/d/1Ee9ggmp6U-lM-w9WmxN5cSLkK9B5YAq14939Woo-JY0/edit).
andybons3322f762015-08-24 21:37:0956
andybons6eaa0c0d2015-08-26 20:12:5257## Typechecking Your Javascript
andybons3322f762015-08-24 21:37:0958
dbeamb0b12672016-05-03 21:33:1359Given an example file structure of:
andybons3322f762015-08-24 21:37:0960
dbeamb0b12672016-05-03 21:33:1361 + lib/does_the_hard_stuff.js
62 + ui/makes_things_pretty.js
andybons3322f762015-08-24 21:37:0963
dbeamb0b12672016-05-03 21:33:1364`lib/does_the_hard_stuff.js`:
andybons3322f762015-08-24 21:37:0965
andybons6eaa0c0d2015-08-26 20:12:5266```javascript
andybons3322f762015-08-24 21:37:0967var wit = 100;
68
69// ... later on, sneakily ...
70
71wit += ' IQ'; // '100 IQ'
72```
73
dbeamb0b12672016-05-03 21:33:1374`ui/makes_things_pretty.js`:
andybons3322f762015-08-24 21:37:0975
andybons6eaa0c0d2015-08-26 20:12:5276```javascript
andybons3322f762015-08-24 21:37:0977/** @type {number} */ var mensa = wit + 50;
dbeamb0b12672016-05-03 21:33:1378
andybons3322f762015-08-24 21:37:0979alert(mensa); // '100 IQ50' instead of 150
80```
81
dbeamb0b12672016-05-03 21:33:1382Closure compiler can notify us if we're using `string`s and `number`s in
83dangerous ways.
andybons3322f762015-08-24 21:37:0984
dbeamb0b12672016-05-03 21:33:1385To do this, we can create:
andybons3322f762015-08-24 21:37:0986
dbeamb0b12672016-05-03 21:33:1387 + ui/compiled_resources2.gyp
88
89With these contents:
andybons3322f762015-08-24 21:37:0990
91```
dbeam1ff34582016-03-10 18:30:3692# Copyright 2016 The Chromium Authors. All rights reserved.
andybons3322f762015-08-24 21:37:0993# Use of this source code is governed by a BSD-style license that can be
94# found in the LICENSE file.
95{
96 'targets': [
97 {
dbeamb0b12672016-05-03 21:33:1398 # Target names is typically just without ".js"
99 'target_name': 'makes_things_pretty',
100
101 'dependencies': [
102 '../lib/compiled_resources2.gyp:does_the_hard_stuff',
103
104 # Teaches closure about non-standard environments/APIs, e.g.
105 # chrome.send(), chrome.app.window, etc.
106 '<(EXTERNS_GYP):extern_name_goes_here'
dbeam1ff34582016-03-10 18:30:36107 ],
dbeamb0b12672016-05-03 21:33:13108
109 'includes': ['../path/to/third_party/closure_compiler/compile_js2.gypi'],
andybons3322f762015-08-24 21:37:09110 },
111 ],
112}
113```
114
dbeamb0b12672016-05-03 21:33:13115## Running Closure compiler locally
116
117You can locally test that your code compiles on Linux or Mac. This requires
118[Java](http://www.oracle.com/technetwork/java/javase/downloads/index.html) and a
xiaoyin.l1003c0b2016-12-06 02:51:17119[Chrome checkout](https://www.chromium.org/developers/how-tos/get-the-code) (i.e.
dbeamb0b12672016-05-03 21:33:13120python, depot_tools). Note: on Ubuntu, you can probably just run `sudo apt-get
121install openjdk-7-jre`.
122
123Now you should be able to run:
124
125```shell
126third_party/closure_compiler/run_compiler
127```
128
129and should see output like this:
130
131```shell
132ninja: Entering directory `out/Default/'
133[0/1] ACTION Compiling ui/makes_things_pretty.js
134```
135
136To compile only a specific target, add an argument after the script name:
137
138```shell
139third_party/closure_compiler/run_compiler makes_things_pretty
140```
141
142In our example code, this error should appear:
andybons3322f762015-08-24 21:37:09143
144```
dbeamb0b12672016-05-03 21:33:13145(ERROR) Error in: ui/makes_things_pretty.js
146## /my/home/chromium/src/ui/makes_things_pretty.js:1: ERROR - initializing variable
andybons3322f762015-08-24 21:37:09147## found : string
148## required: number
149## /** @type {number} */ var mensa = wit + 50;
150## ^
151```
152
dbeamb0b12672016-05-03 21:33:13153Hooray! We can catch type errors in JavaScript!
andybons3322f762015-08-24 21:37:09154
dbeamb0b12672016-05-03 21:33:13155## Trying your change
andybons3322f762015-08-24 21:37:09156
dbeamb0b12672016-05-03 21:33:13157Closure compilation also has [try
158bots](https://build.chromium.org/p/tryserver.chromium.linux/builders/closure_compilation)
159which can check whether you could *would* break the build if it was committed.
160
161From the command line, you try your change with:
162
163```shell
164git cl try -b closure_compilation
165```
166
167To automatically check that your code typechecks cleanly before submitting, you
168can add this line to your CL description:
169
170```
171CQ_INCLUDE_TRYBOTS=tryserver.chromium.linux:closure_compilation
172```
173
174Working in common resource directories in Chrome automatically adds this line
175for you.
176
177## Integrating with the continuous build
178
179To compile your code on every commit, add your file to the `'dependencies'` list
180in `src/third_party/closure_compiler/compiled_resources2.gyp`:
andybons3322f762015-08-24 21:37:09181
182```
183{
184 'targets': [
185 {
186 'target_name': 'compile_all_resources',
187 'dependencies': [
188 # ... other projects ...
dbeam1ff34582016-03-10 18:30:36189++ '../my_project/compiled_resources2.gyp:*',
andybons3322f762015-08-24 21:37:09190 ],
191 }
192 ]
193}
194```
195
dbeamb0b12672016-05-03 21:33:13196This file is used by the
xiaoyin.l1003c0b2016-12-06 02:51:17197[Closure compiler bot](https://build.chromium.org/p/chromium.fyi/builders/Closure%20Compilation%20Linux)
dbeamb0b12672016-05-03 21:33:13198to automatically compile your code on every commit.
michaelpgc1e2d1e2017-05-01 23:40:59199
200## Externs
201
202[Externs files](https://github.com/google/closure-compiler/wiki/FAQ#how-do-i-write-an-externs-file)
203define APIs external to your JavaScript. They provide the compiler with the type
204information needed to check usage of these APIs in your JavaScript, much like
205forward declarations do in C++.
206
207Third-party libraries like Polymer often provide externs. Chrome must also
208provide externs for its extension APIs. Whenever an extension API's `idl` or
209`json` schema is updated in Chrome, the corresponding externs file must be
210regenerated:
211
212```shell
213./tools/json_schema_compiler/compiler.py -g externs \
214 extensions/common/api/your_api_here.idl \
215 > third_party/closure_compiler/externs/your_api_here.js
216```