Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(90)

Side by Side Diff: docs/closure_compilation.md

Issue 1942133002: Closure compilation: rewrite doc now that there's try bots (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Closure Compilation 1 # Closure Compilation
2 2
3 ## I just need to fix the compile! 3 ## What is type safety?
4 4
5 ### Pre-requisites 5 [Strongly-typed languages](https://en.wikipedia.org/wiki/Strong_and_weak_typing)
groby-ooo-7-16 2016/05/03 05:51:15 Completely unnecessary nitpick of the week: Strict
Dan Beam 2016/05/03 21:24:06 Acknowledged.
6 like C++ and Java have the notion of variable types.
6 7
7 You'll need Java 7 (preferably the OpenJDK version). To install on Ubuntu: 8 This is typically baked into how you declare variables:
8 9
9 ```shell 10 ```c++
10 sudo apt-get install openjdk-7-jre 11 const int32 kUniversalAnswer = 42; // type = 32-bit integer
11 ``` 12 ```
12 13
13 On Mac or Windows, visit: 14 or as [templates](https://en.wikipedia.org/wiki/Template_metaprogramming) for
14 [http://www.oracle.com/technetwork/java/javase/downloads/index.html](http://www. oracle.com/technetwork/java/javase/downloads/index.html) 15 containers or generics:
15 16
16 ### Using ninja to compile the code 17 ```c++
17 18 std::vector<int64> fibonacci_numbers; // a vector of 64-bit integers
18 To compile the JavaScript, run this script:
19
20 ```shell
21 third_party/closure_compiler/run_compiler
22 ``` 19 ```
23 20
24 The output should look something like this: 21 When differently-typed variables interact with eachother, the compiler can warn
groby-ooo-7-16 2016/05/03 05:51:15 nit:each[space]other
Dan Beam 2016/05/03 21:24:05 Done.
22 you if there's no sane default action to take.
25 23
26 ```shell 24 Typing can also be manually annotated via mechanisms like `dynamic_cast` and
27 ninja: Entering directory `out/Default/' 25 `static_cast` or older C-style casts (i.e. `(Type)`).
28 [30/106] ACTION Compiling chrome/browser/resources/md_history/constants.js 26
27 Using stongly-typed languages provide _some_ level of protection against
28 accidentally using variables in the wrong context.
29
30 JavaScript is loosely-typed and doesn't offer this safety by default. This makes
groby-ooo-7-16 2016/05/03 05:51:15 weakly-typed? Since that's what you start of with?
Dan Beam 2016/05/03 21:24:06 Done.
31 writing JavaScript more error prone, and various type errors have resulted in
32 real bugs seen by many users.
33
34 ## Chrome's solution to typechecking JavaScript
35
36 Enter [Closure Compiler](https://developers.google.com/closure/compiler/), a
37 tool for analyzing JavaScript and checking for syntax errors, variable
38 references, and other common JavaScript pitfalls.
39
40 To get the fullest type safety possible, it's often required to annotate your
41 JavaScript explicitly with [Closure-flavored @jsdoc
42 tags](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").
47 * @return {!Array<number>} Numbers corresponing to |version| (i.e. [50, 0, 2661 , 94]).
48 */
49 function versionSplit(version) {
50 return version.split('.').map(Number);
51 }
29 ``` 52 ```
30 53
31 To compile only a specific target, add an argument after the script name:
32
33 ```shell
34 third_party/closure_compiler/run_compiler people_page
35 ```
36
37 ## Background
38
39 In C++ and Java, compiling the code gives you _some_ level of protection against
40 misusing variables based on their type information. JavaScript is loosely typed
41 and therefore doesn't offer this safety. This makes writing JavaScript more
42 error prone as it's _one more thing_ to mess up.
43
44 Because having this safety is handy, Chrome now has a way to optionally
45 typecheck your JavaScript and produce compiled output with
46 [Closure Compiler](https://developers.google.com/closure/compiler/).
47 The type information is
48 [annotated in comment tags](https://developers.google.com/closure/compiler/docs/ js-for-compiler)
49 that are briefly described below.
50
51 See also: 54 See also:
52 [the design doc](https://docs.google.com/a/chromium.org/document/d/1Ee9ggmp6U-lM -w9WmxN5cSLkK9B5YAq14939Woo-JY0/edit). 55 [the design doc](https://docs.google.com/a/chromium.org/document/d/1Ee9ggmp6U-lM -w9WmxN5cSLkK9B5YAq14939Woo-JY0/edit).
53 56
54 ## Assumptions
55
56 A working Chrome checkout. See here:
57 https://www.chromium.org/developers/how-tos/get-the-code
58
59 ## Typechecking Your Javascript 57 ## Typechecking Your Javascript
60 58
61 So you'd like to compile your JavaScript! 59 Given an example file structure of:
62 60
63 Maybe you're working on a page that looks like this: 61 + lib/does_the_hard_stuff.js
62 + ui/makes_things_pretty.js
64 63
65 ```html 64 `lib/does_the_hard_stuff.js`:
66 <script src="other_file.js"></script>
67 <script src="my_product/my_file.js"></script>
68 ```
69
70 Where `other_file.js` contains:
71 65
72 ```javascript 66 ```javascript
73 var wit = 100; 67 var wit = 100;
74 68
75 // ... later on, sneakily ... 69 // ... later on, sneakily ...
76 70
77 wit += ' IQ'; // '100 IQ' 71 wit += ' IQ'; // '100 IQ'
78 ``` 72 ```
79 73
80 and `src/my_product/my_file.js` contains: 74 `ui/makes_things_pretty.js`:
81 75
82 ```javascript 76 ```javascript
83 /** @type {number} */ var mensa = wit + 50; 77 /** @type {number} */ var mensa = wit + 50;
78
84 alert(mensa); // '100 IQ50' instead of 150 79 alert(mensa); // '100 IQ50' instead of 150
85 ``` 80 ```
86 81
87 In order to check that our code acts as we'd expect, we can create a 82 Closure compiler can notify us if we're using `string`s and `number`s in
83 dangerous ways.
88 84
89 my_project/compiled_resources2.gyp 85 To do this, we can create:
90 86
91 with the contents: 87 + ui/compiled_resources2.gyp
88
89 With these contents:
92 90
93 ``` 91 ```
94 # Copyright 2016 The Chromium Authors. All rights reserved. 92 # Copyright 2016 The Chromium Authors. All rights reserved.
95 # Use of this source code is governed by a BSD-style license that can be 93 # Use of this source code is governed by a BSD-style license that can be
96 # found in the LICENSE file. 94 # found in the LICENSE file.
97 { 95 {
98 'targets': [ 96 'targets': [
99 { 97 {
100 'target_name': 'my_file', # file name without ".js" 98 # Target names is typically just without ".js"
101 'dependencies': [ # No need to specify empty lists. 99 'target_name': 'makes_things_pretty',
102 '../compiled_resources2.gyp:other_file', 100
103 '<(EXTERNS_GYP):any_needed_externs' # e.g. chrome.send(), chrome.app.wi ndow, etc. 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'
104 ], 107 ],
105 'includes': ['../third_party/closure_compiler/compile_js2.gypi'], 108
109 'includes': ['../path/to/third_party/closure_compiler/compile_js2.gypi'],
106 }, 110 },
107 ], 111 ],
108 } 112 }
109 ``` 113 ```
110 114
111 You should get results like: 115 ## Running Closure compiler locally
116
117 You 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
119 [Chrome checkout](http://www.chromium.org/developers/how-tos/get-the-code) (i.e.
120 python, depot_tools). Note: on Ubuntu, you can probably just run `sudo apt-get
121 install openjdk-7-jre`.
122
123 Now you should be able to run:
124
125 ```shell
126 third_party/closure_compiler/run_compiler
127 ```
128
129 and should see output like this:
130
131 ```shell
132 ninja: Entering directory `out/Default/'
133 [0/1] ACTION Compiling ui/makes_things_pretty.js
134 ```
135
136 To compile only a specific target, add an argument after the script name:
137
138 ```shell
139 third_party/closure_compiler/run_compiler makes_things_pretty
140 ```
141
142 In our example code, this error should appear:
112 143
113 ``` 144 ```
114 (ERROR) Error in: my_project/my_file.js 145 (ERROR) Error in: ui/makes_things_pretty.js
115 ## /my/home/chromium/src/my_project/my_file.js:1: ERROR - initializing variable 146 ## /my/home/chromium/src/ui/makes_things_pretty.js:1: ERROR - initializing varia ble
116 ## found : string 147 ## found : string
117 ## required: number 148 ## required: number
118 ## /** @type {number} */ var mensa = wit + 50; 149 ## /** @type {number} */ var mensa = wit + 50;
119 ## ^ 150 ## ^
120 ``` 151 ```
121 152
122 Yay! We can easily find our unexpected type errors and write less error-prone 153 Hooray! We can catch type errors in JavaScript!
123 code!
124 154
125 ## Continuous Checking 155 ## Integrating with the continuous build
126 156
127 To compile your code on every commit, add a line to 157 To compile your code on every commit, add your file to the `'dependencies'` list
128 /third_party/closure_compiler/compiled_resources.gyp 158 in `src/third_party/closure_compiler/compiled_resources2.gyp`:
129 like this:
130 159
131 ``` 160 ```
132 { 161 {
133 'targets': [ 162 'targets': [
134 { 163 {
135 'target_name': 'compile_all_resources', 164 'target_name': 'compile_all_resources',
136 'dependencies': [ 165 'dependencies': [
137 # ... other projects ... 166 # ... other projects ...
138 ++ '../my_project/compiled_resources2.gyp:*', 167 ++ '../my_project/compiled_resources2.gyp:*',
139 ], 168 ],
140 } 169 }
141 ] 170 ]
142 } 171 }
143 ``` 172 ```
144 173
145 and the 174 this file is used by the
groby-ooo-7-16 2016/05/03 05:51:15 [T]his...
Dan Beam 2016/05/03 21:24:06 Done.
146 [Closure compiler bot](http://build.chromium.org/p/chromium.fyi/builders/Closure %20Compilation%20Linux) 175 [Closure compiler bot](http://build.chromium.org/p/chromium.fyi/builders/Closure %20Compilation%20Linux)
147 will [re-]compile your code whenever relevant .js files change. 176 will automatically compile your code on every commit.
groby-ooo-7-16 2016/05/03 05:51:15 And will automatically... or It will automatically
Dan Beam 2016/05/03 21:24:06 Done. (changed to "used by the closure compiler bo
148 177
149 ## Using Compiled JavaScript 178 ## Trying your change
150 179
151 Compiled JavaScript is output in 180 Closure compilation also has [try
152 `src/out/<Debug|Release>/gen/closure/my_project/my_file.js` along with a source 181 bots](https://build.chromium.org/p/tryserver.chromium.linux/builders/closure_com pilation)
153 map for use in debugging. In order to use the compiled JavaScript, we can create 182 which can check whether you could *would* break the build if it was committed.
154 a
155 183
156 my_project/my_project_resources.gyp 184 From the command line, you can issue a try job with your current diff by:
groby-ooo-7-16 2016/05/03 05:51:15 s/diff/changes
Dan Beam 2016/05/03 21:24:06 Done. (From the command line, you try your change
157 185
158 with the contents: 186 ```shell
187 git cl try -b closure_compilation
188 ```
189
190 To automatically check that your code typechecks cleanly before submitting, you
191 can add this line to your CL description:
159 192
160 ``` 193 ```
161 # Copyright 2015 The Chromium Authors. All rights reserved. 194 CQ_INCLUDE_TRYBOTS=tryserver.chromium.linux:closure_compilation
162 # Use of this source code is governed by a BSD-style license that can be
163 # found in the LICENSE file.
164
165 {
166 'targets': [
167 {
168 # GN version: //my_project/resources
169 'target_name': 'my_project_resources',
170 'type': 'none',
171 'variables': {
172 'grit_out_dir': '<(SHARED_INTERMEDIATE_DIR)/my_project',
173 'my_file_gen_js': '<(SHARED_INTERMEDIATE_DIR)/closure/my_project/my_file .js',
174 },
175 'actions': [
176 {
177 # GN version: //my_project/resources:my_project_resources
178 'action_name': 'generate_my_project_resources',
179 'variables': {
180 'grit_grd_file': 'resources/my_project_resources.grd',
181 'grit_additional_defines': [
182 '-E', 'my_file_gen_js=<(my_file_gen_js)',
183 ],
184 },
185 'includes': [ '../build/grit_action.gypi' ],
186 },
187 ],
188 'includes': [ '../build/grit_target.gypi' ],
189 },
190 ],
191 }
192 ``` 195 ```
193 196
194 The variables can also be defined in an existing .gyp file if appropriate. The 197 Working in common resource directories in Chrome automatically add this line for
groby-ooo-7-16 2016/05/03 05:51:15 add[s]
Dan Beam 2016/05/03 21:24:06 Done.
195 variables can then be used in to create a 198 you.
196
197 my_project/my_project_resources.grd
198
199 with the contents:
200
201 ```
202 <?xml version="1.0" encoding="utf-8"?>
203 <grit-part>
204 <include name="IDR_MY_FILE_GEN_JS" file="${my_file_gen_js}" use_base_dir="fals e" type="BINDATA" />
205 </grit-part>
206 ```
207
208 In your C++, the resource can be retrieved like this:
209
210 ```
211 base::string16 my_script =
212 base::UTF8ToUTF16(
213 ResourceBundle::GetSharedInstance()
214 .GetRawDataResource(IDR_MY_FILE_GEN_JS)
215 .as_string());
216 ```
217
218 ## Debugging Compiled JavaScript
219
220 Along with the compiled JavaScript, a source map is created:
221 `src/out/<Debug|Release>/gen/closure/my_project/my_file.js.map`
222
223 Chrome DevTools has built in support for working with source maps:
224 https://developer.chrome.com/devtools/docs/javascript-debugging#source-maps
225
226 In order to use the source map, you must first manually edit the path to the
227 'sources' in the .js.map file that was generated. For example, if the source map
228 looks like this:
229
230 ```
231 {
232 "version":3,
233 "file":"/tmp/gen/test_script.js",
234 "lineCount":1,
235 "mappings":"A,aAAA,IAAIA,OAASA,QAAQ,EAAG,CACtBC,KAAA,CAAM,OAAN,CADsB;",
236 "sources":["/tmp/tmp70_QUi"],
237 "names":["fooBar","alert"]
238 }
239 ```
240
241 sources should be changed to:
242
243 ```
244 ...
245 "sources":["/tmp/test_script.js"],
246 ...
247 ```
248
249 In your browser, the source map can be loaded through the Chrome DevTools
250 context menu that appears when you right click in the compiled JavaScript source
251 body. A dialog will pop up prompting you for the path to the source map file.
252 Once the source map is loaded, the uncompiled version of the JavaScript will
253 appear in the Sources panel on the left. You can set break points in the
254 uncompiled version to help debug; behind the scenes Chrome will still be running
255 the compiled version of the JavaScript.
256
257 ## Additional Arguments
258
259 `compile_js.gypi` accepts an optional `script_args` variable, which passes
260 additional arguments to `compile.py`, as well as an optional `closure_args`
261 variable, which passes additional arguments to the closure compiler. You may
262 also override the `disabled_closure_args` for more strict compilation.
263
264 For example, if you would like to specify multiple sources, strict compilation,
265 and an output wrapper, you would create a
266
267 ```
268 my_project/compiled_resources.gyp
269 ```
270
271 with contents similar to this:
272
273 ```
274 # Copyright 2015 The Chromium Authors. All rights reserved.
275 # Use of this source code is governed by a BSD-style license that can be
276 # found in the LICENSE file.
277 {
278 'targets' :[
279 {
280 'target_name': 'my_file',
281 'variables': {
282 'source_files': [
283 'my_file.js',
284 'my_file2.js',
285 ],
286 'script_args': ['--no-single-file'], # required to process multiple file s at once
287 'closure_args': [
288 'output_wrapper=\'(function(){%output%})();\'',
289 'jscomp_error=reportUnknownTypes', # the following three provide m ore strict compilation
290 'jscomp_error=duplicate',
291 'jscomp_error=misplacedTypeAnnotation',
292 ],
293 'disabled_closure_args': [], # remove the disabled closure args for more strict compilation
294 },
295 'includes': ['../third_party/closure_compiler/compile_js.gypi'],
296 },
297 ],
298 }
299 ```
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698