| # Using the Chrome Devtools JavaScript preprocessing feature | 
 |  | 
 | The Chrome Devtools JavaScript preprocessor intercepts JavaScript just before it | 
 | enters V8, the Chrome JS system, allowing the JS to be transcoded before | 
 | compilation.  In combination with page injected JavaScript, the preprocessor | 
 | allows a complete synthetic runtime to be constructed in JavaScript. Combined | 
 | with other functions in the `chrome.devtools` extension API, the preprocessor | 
 | allows new more sophisticated  JavaScript-related developer tools to be created. | 
 |  | 
 | ## API | 
 |  | 
 | To use the script preprocessor, write a | 
 | [chrome devtools extension](http://developer.chrome.com/extensions/devtools.inspectedWindow.html#method-reload) | 
 | that reloads the Web page with the preprocessor installed: | 
 |  | 
 | ```javascript | 
 | chrome.devtools.inspectedWindow.reload({ | 
 |     ignoreCache: true, | 
 |     injectedScript: runThisFirst, | 
 |     preprocessorScript: preprocessor | 
 | }); | 
 | ``` | 
 |  | 
 | where `preprocessorScript` is source code (string) for a JavaScript function | 
 | taking three string arguments, the source to preprocess, the URL of the source, | 
 | and a function name if the source is an DOM event handler. The | 
 | `preprocessorerScript` function should return a string to be compiled by Chrome | 
 | in place of the input source. In the case that the source is a DOM event | 
 | handler, the returned source must compile to a single JS function. | 
 |  | 
 | The | 
 | [Chrome Preprocessor Example](http://developer.chrome.com/extensions/samples.html) | 
 | illustrates the API call in a simple chrome devtools extension. Download and | 
 | unpack the .zip file, use `chrome://extensions` in Developer Mode and load the | 
 | unpacked extension. Then open or reopen devtools. The Preprocessor panel has a | 
 | **reload** button that triggers a simple preprocessor. | 
 |  | 
 | The preprocessor runs in an isolated world similar to the environment of Chrome | 
 | content scripts. A `window` object is available but it shares no properties with | 
 | the Web page `window` object.  DOM calls in the preprocessor environment will | 
 | operate on the Web page, but developers should be cautious about operating on | 
 | the DOM in the preprocessor. We do not test such operations though we expect the | 
 | result to resemble calls from the outer function of `<script>` tags. | 
 |  | 
 | In some applications the developer may coordinate runtime initialization using | 
 | the `injectedScript` property in the object passed to the `reload()` call. This | 
 | is also JavaScript source code; it is compiled into the page ahead of any Web | 
 | page scripts and thus before any JavaScript is preprocessed. | 
 |  | 
 | The preprocessor is compiled once just before the first JavaScript appears. It | 
 | remains active until the page is reloaded or otherwise navigated. Navigating the | 
 | Web page back and then forward will result in no preprocessing. Closing devtools | 
 | will leave the preprocessor in place. | 
 |  | 
 | ## Use Cases | 
 |  | 
 | The script preprocessor supports transcoding input source to JavaScript. Use cases include: | 
 |  | 
 | *   Adding write barriers for Querypoint debugging, | 
 | *   Supporting feature-specific debugging of next generation EcmaScript using eg Traceur, | 
 | *   Integration of development tools like coverage analysis. | 
 | *   Analysis of call sequences for performance tuning. | 
 |  | 
 | Several JavaScript compilers support transcoding, including | 
 | [Traceur](https://github.com/google/traceur-compiler#readme) and | 
 | [Esprima](http://esprima.org/). | 
 |  | 
 | ## Implementation | 
 |  | 
 | The implementation relies on the Devtools front-end hosting an extension | 
 | supplying the preprocessor script; the front end communicates with the browser | 
 | backend over eg web sockets. | 
 |  | 
 | The devtools extension function call issues a postMessage() event from the | 
 | devtools extension iframe to the devtools main frame. The event is handled in | 
 | `ExtensionServer.js` which forwards it over the | 
 | [devtools remote debug protocol](https://developers.google.com/chrome-developer-tools/docs/protocol/1.0/page#command-reload). | 
 | (See [Bug 229971](https://crbug.com/229971) for this part of the implementation | 
 | and its status). | 
 |  | 
 | When the preprocessor script arrives in the back end, | 
 | `InspectorPageAgent::reload` stores the preprocessor script in | 
 | `m_pendingScriptPreprocessor`. After the browser begins the reload operation, it | 
 | calls `PageDebuggerAgent::didClearWindowObjectInWorld` which moves the processor | 
 | source into the `scriptDebugServer()`. | 
 |  | 
 | Next the browser prepares the page environment and calls | 
 | `PageDebuggerAgent::didClearWindowObjectInWorld`. This function clears the | 
 | preprocessor object pointer and if it is not recreated during the page load, no | 
 | scripts will be preprocessed. At this point we only store the preprocessor | 
 | source, delaying the compilation of the preprocessor until just before its first | 
 | use. This helps ensure that the JS environment we use is fully initialized. | 
 |  | 
 | Source to be preprocessed comes from three different places: | 
 |  | 
 | 1.  Web page `<script>` tags, | 
 | 1.  DOM event-listener attributes, eg `onload`, | 
 | 1.  JS `eval()` or `new Function()` calls. | 
 |  | 
 | When the browser encounters either a `<script>` tag | 
 | (`ScriptController::executeScriptInMainWorld`) or an  element attribute script | 
 | (`V8LazyEventListener::prepareListenerObject`) we call a corresponding function | 
 | in InspectorInstrumentation. This function has a fast inlined return path in the | 
 | case that the debugger is not attached. | 
 |  | 
 | If the debugger is attached, InspectorInstrumentation will call the matching | 
 | function in PageDebuggerAgent (see core/inspector/InspectorInstrumentation.idl). | 
 | It checks to see if the preprocessor is installed. If not, it returns. | 
 |  | 
 | The preprocessor source is stored in PageScriptDebugServer. | 
 | If the preprocessor is installed, we check to see if it is compiled. If not, we | 
 | create a new `ScriptPreprocessor` object.  The constructor uses | 
 | `ScriptController::executeScriptInIsolatedWorld` to compile the preprocessor in | 
 | a new isolated world associated with the Web page's main world.  If the | 
 | compilation and outer script execution succeed and if the result is a JavaScript | 
 | function, we store the resulting function as a `ScopedPersistent<v8::Function>` | 
 | member of the preprocessor. | 
 |  | 
 | If the `PageScriptDebugServer::preprocess()` has a value for the preprocessor | 
 | function, it applies the function to the web page source using | 
 | `V8ScriptRunner::callAsFunction()`. This calls the compiled JS function in the | 
 | ScriptPreprocessor's isolated world and retrieves the resulting string. | 
 |  | 
 | When the preprocessed JavaScript source runs it may call `eval()` or | 
 | `new Function()`.  These calls cause the V8 runtime to compile source. | 
 | Immediately before compiling, V8 issues a beforeCompile event which triggers | 
 | `ScriptDebugServer::handleV8DebugEvent()`. This code is only called if the | 
 | debugger is active. In the handler we call `ScriptDebugServer::preprocessEval()` | 
 | to examine the ScriptCompilationTypeInfo, a marker set by V8, to see if we are | 
 | compiling dynamic code. Only dynamic code is preprocessed in this function and | 
 | only if we are not executing the preprocessor itself. | 
 |  | 
 | During the browser operation, API generation code, debugger console | 
 | initialization code, injected page script code, debugger information extraction | 
 | code, and regular web page code enter this function.  There is currently no way | 
 | to distinguish internal or system code from the web page code. However the | 
 | internal code is all static. By limiting our preprocessing to dynamic code in | 
 | the beforeCompile handler, we know we are only operating on Web page code. The | 
 | static Web page code is preprocessed as described above. | 
 |  | 
 | ## Limitations | 
 |  | 
 | We currently do not support preprocessing of WebWorker source code. |