| :linkattrs: |
| = 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,role=external,window=_blank] 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. |
| |