summaryrefslogtreecommitdiffstats
path: root/Documentation/pg-plugin-migration.txt
blob: 3ddceedb0e9decbc96aa701487c2691eedc955de (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
= 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.