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

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: change order of try and continous integration systems 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)
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 each other, the compiler can warn
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 weakly-typed and doesn't offer this safety by default. This makes
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 ## Trying your change
126 156
127 To compile your code on every commit, add a line to 157 Closure compilation also has [try
128 /third_party/closure_compiler/compiled_resources.gyp 158 bots](https://build.chromium.org/p/tryserver.chromium.linux/builders/closure_com pilation)
129 like this: 159 which can check whether you could *would* break the build if it was committed.
160
161 From the command line, you try your change with:
162
163 ```shell
164 git cl try -b closure_compilation
165 ```
166
167 To automatically check that your code typechecks cleanly before submitting, you
168 can add this line to your CL description:
169
170 ```
171 CQ_INCLUDE_TRYBOTS=tryserver.chromium.linux:closure_compilation
172 ```
173
174 Working in common resource directories in Chrome automatically adds this line
175 for you.
176
177 ## Integrating with the continuous build
178
179 To compile your code on every commit, add your file to the `'dependencies'` list
180 in `src/third_party/closure_compiler/compiled_resources2.gyp`:
130 181
131 ``` 182 ```
132 { 183 {
133 'targets': [ 184 'targets': [
134 { 185 {
135 'target_name': 'compile_all_resources', 186 'target_name': 'compile_all_resources',
136 'dependencies': [ 187 'dependencies': [
137 # ... other projects ... 188 # ... other projects ...
138 ++ '../my_project/compiled_resources2.gyp:*', 189 ++ '../my_project/compiled_resources2.gyp:*',
139 ], 190 ],
140 } 191 }
141 ] 192 ]
142 } 193 }
143 ``` 194 ```
144 195
145 and the 196 This file is used by the
146 [Closure compiler bot](http://build.chromium.org/p/chromium.fyi/builders/Closure %20Compilation%20Linux) 197 [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. 198 to automatically compile your code on every commit.
148
149 ## Using Compiled JavaScript
150
151 Compiled JavaScript is output in
152 `src/out/<Debug|Release>/gen/closure/my_project/my_file.js` along with a source
153 map for use in debugging. In order to use the compiled JavaScript, we can create
154 a
155
156 my_project/my_project_resources.gyp
157
158 with the contents:
159
160 ```
161 # Copyright 2015 The Chromium Authors. All rights reserved.
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 ```
193
194 The variables can also be defined in an existing .gyp file if appropriate. The
195 variables can then be used in to create a
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