|  | = Gerrit Code Review - PolyGerrit Plugin Development | 
|  |  | 
|  | CAUTION: Work in progress. Hard hat area. Please | 
|  | link:https://bugs.chromium.org/p/gerrit/issues/entry?template=PolyGerrit%20plugins[send | 
|  | feedback] if something's not right. | 
|  |  | 
|  | [[migration]] | 
|  | == Incremental migration of existing GWT UI plugins | 
|  |  | 
|  | link:pg-plugin-dev.html[PolyGerrit plugin API] is based on different concepts and | 
|  | provides a different type of API compared to the one available to GWT | 
|  | plugins. Depending on the plugin, it might require significant modifications to | 
|  | existing UI scripts to fully take advantage of the benefits provided by the PolyGerrit API. | 
|  |  | 
|  | To make migration easier, PolyGerrit recommends an incremental migration | 
|  | strategy. Starting with a .js file that works for GWT UI, plugin author can | 
|  | incrementally migrate deprecated APIs to the new plugin API. | 
|  |  | 
|  | The goal for this guide is to provide a migration path from .js-based UI script to | 
|  | a html based implementation | 
|  |  | 
|  | NOTE: Web UI plugins distributed as a single .js file are not covered in this | 
|  | guide. | 
|  |  | 
|  | Let's start with a basic plugin that has an UI module. Commonly, file tree | 
|  | should look like this: | 
|  |  | 
|  | ├── BUILD | 
|  | ├── LICENSE | 
|  | └── src | 
|  | └── main | 
|  | ├── java | 
|  | │   └── com | 
|  | │       └── foo | 
|  | │           └── SamplePluginModule.java | 
|  | └── resources | 
|  | └── static | 
|  | └── sampleplugin.js | 
|  |  | 
|  | For simplicity's sake, let's assume SamplePluginModule.java has following | 
|  | content: | 
|  |  | 
|  | ``` java | 
|  | public class SamplePluginModule extends AbstractModule { | 
|  |  | 
|  | @Override | 
|  | protected void configure() { | 
|  | DynamicSet.bind(binder(), WebUiPlugin.class) | 
|  | .toInstance(new JavaScriptPlugin("sampleplugin.js")); | 
|  | } | 
|  | } | 
|  | ``` | 
|  |  | 
|  | === Step 1: Create `sampleplugin.html` | 
|  |  | 
|  | As a first step, create `sampleplugin.html` and include the UI script in the | 
|  | module file. | 
|  |  | 
|  | NOTE: GWT UI ignores html files which it doesn't support. | 
|  |  | 
|  | ``` java | 
|  | @Override | 
|  | protected void configure() { | 
|  | DynamicSet.bind(binder(), WebUiPlugin.class) | 
|  | .toInstance(new JavaScriptPlugin("sampleplugin.js")); | 
|  | DynamicSet.bind(binder(), WebUiPlugin.class) | 
|  | .toInstance(new JavaScriptPlugin("sampleplugin.html")); | 
|  | } | 
|  | ``` | 
|  |  | 
|  | Here's recommended starter code for `sampleplugin.html`: | 
|  |  | 
|  | NOTE: By specification, the `id` attribute of `dom-module` *must* contain a dash | 
|  | (-). | 
|  |  | 
|  | ``` html | 
|  | <dom-module id="sample-plugin"> | 
|  | <script> | 
|  | Gerrit.install(plugin => { | 
|  | // Setup block, is executed before sampleplugin.js | 
|  |  | 
|  | // Install deprecated JS APIs (onAction, popup, etc) | 
|  | plugin.deprecated.install(); | 
|  | }); | 
|  | </script> | 
|  |  | 
|  | <script src="./sampleplugin.js"></script> | 
|  |  | 
|  | <script> | 
|  | Gerrit.install(plugin => { | 
|  | // Cleanup block, is executed after sampleplugin.js | 
|  | }); | 
|  | </script> | 
|  | </dom-module> | 
|  | ``` | 
|  |  | 
|  | Here's how this works: | 
|  |  | 
|  | - PolyGerrit detects migration scenario because UI scripts have same filename | 
|  | and different extensions | 
|  | * PolyGerrit will load `sampleplugin.html` and skip `sampleplugin.js` | 
|  | * PolyGerrit will reuse `plugin` (aka `self`) instance for `Gerrit.install()` | 
|  | callbacks | 
|  | - `sampleplugin.js` is loaded since it's referenced in `sampleplugin.html` | 
|  | - setup script tag code is executed before `sampleplugin.js` | 
|  | - cleanup script tag code is executed after `sampleplugin.js` | 
|  | - `plugin.deprecated.install()` enables deprecated APIs (onAction(), popup(), | 
|  | etc) before `sampleplugin.js` is loaded | 
|  |  | 
|  | This means the plugin instance is shared between .html-based and .js-based | 
|  | code. This allows to gradually and incrementally transfer code to the new API. | 
|  |  | 
|  | === Step 2: Create cut-off marker in `sampleplugin.js` | 
|  |  | 
|  | Commonly, window.Polymer is being used to detect in GWT UI script if it's being | 
|  | executed inside PolyGerrit. This could be used to separate code that was already | 
|  | migrated to new APIs from old not yet migrated code. | 
|  |  | 
|  | During incremental migration, some of the UI code will be reimplemented using | 
|  | the PolyGerrit plugin API. However, old code still could be required for the plugin | 
|  | to work in GWT UI. | 
|  |  | 
|  | To handle this case, add the following code at the end of the installation | 
|  | callback in `sampleplugin.js` | 
|  |  | 
|  | ``` js | 
|  | Gerrit.install(function(self) { | 
|  |  | 
|  | // Existing code here, not modified. | 
|  |  | 
|  | if (window.Polymer) { return; } // Cut-off marker | 
|  |  | 
|  | // Everything below was migrated to PolyGerrit plugin API. | 
|  | // Code below is still needed for the plugin to work in GWT UI. | 
|  | }); | 
|  | ``` | 
|  |  | 
|  | === Step 3: Migrate! | 
|  |  | 
|  | The code that uses deprecated APIs should be eventually rewritten using | 
|  | non-deprecated counterparts. Duplicated pieces could be kept under cut-off | 
|  | marker to work in GWT UI. | 
|  |  | 
|  | If some data or functions needs to be shared between code in .html and .js, it | 
|  | could be stored in the `plugin` (aka `self`) object that's shared between both | 
|  |  | 
|  | === Step 4: Cleanup | 
|  |  | 
|  | Once deprecated APIs are migrated, `sampleplugin.js` will only contain | 
|  | duplicated code that's required for GWT UI to work. As soon as GWT support is removed from Gerrit | 
|  | that file can be simply deleted, along with the script tag loading it. | 
|  |  |