Tutoriel pour apprendre à utiliser des Web Components avec GWT : application à Google Polymer

Zakaria Amine

Quand GWT a été créé, il y avait seulement quelques frameworks JavaScript, et donc l'intérêt d'avoir une interopérabilité bidirectionnelle n'avait pas beaucoup de sens à l'époque. GWT a offert une façon d'écrire du JavaScript à l'intérieur des classes Java en utilisant du JSNI. Mais maintenant, avec l'évolution de l'écosystème JavaScript, les développeurs GWT ont besoin de quelque chose de plus élaboré que JSNI.

Ce tutoriel se propose de présenter JsInterop dans une première partie, puis de présenter la spécification liée aux Web Components et l'implémentation Polymer proposée par Google et enfin de voir comment utiliser facilement Polymer avec GWT via JsInterop.

Pour réagir au contenu de ce compte-rendu, un espace de dialogue vous est proposé sur le forum : Commentez .

- Titre : Tutoriel pour apprendre à utiliser des Web Components avec GWT : application à Google Polymer

- Auteur : Zakaria Amine

- Parution : 13 juillet 2016

- Mise à jour : 24 février 2020

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 2016 Zakaria Amine. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. JsInterop

- II. Web Components et Polymer

- II-A. Le point de rencontre entre JsInterop et les Web Components

- II-B. Faire sa première application

- III. Conclusion et remerciements

I - JsInterop

À partir de la version 2.7 de GWT, JsInterop a été présenté comme une fonctionnalité expérimentale pour remplacer le JSNI. Comme son nom l'indique, JsInterop est une façon d'interopérer Java (GWT) avec JavaScript. Il offre un meilleur mode de communication entre les deux en utilisant des annotations, au lieu d'avoir à écrire du JavaScript dans vos classes. JSInterop est défini par les interfaces suivantes : @JsType, @JsProperty, @JSMethod, @JSConstructor, @JSFunction, @JsExport.

La première utilité de JsInterop est de pouvoir exposer vos classes Java afin de pouvoir les utiliser à partir d'un script JavaScript. Par exemple :

1. package com.jsinterop;

3. @JsType

4. public class myClasse {

6. public String name;

8. public myClass(String name){

9. this.name = name;

10. }

13. public void sayHello() {

14. return 'Hello' + this.name;

15. }

16. }

On pourra utiliser notre classe depuis un script comme ceci :

1. // le Nom du package est important car il sert comme namespace

2. var aClass = new com.jsinterop.myClasse('developpez.com');

4. console.log(aClass.sayHello());

6. // resultat: 'Hello developpez.com'

La deuxième utilité de JsInterop est la possibilité d'importer les bibliothèques JavaScript existantes et de pouvoir les utiliser dans GWT sans avoir à réécrire une ligne de JavaScript. C'est ici où les choses deviennent intéressantes. Imaginez que vous pouvez faire usage de tous les grands frameworks qui existent dans l'écosystème JavaScript (Angular, Polymer, React …) à partir de votre code Java. Il suffit donc d'importer la bibliothèque JavaScript dans la page principale (Entry Point). Il faudra aussi identifier les méthodes et champs à importer dans votre projet GWT.

Par exemple, supposons que nous voulions utiliser Leaflet, qui est une bibliothèque JavaScript qui permet de manipuler des cartes, depuis notre code Java. Tout ce que nous devons faire est d'envelopper les méthodes dont nous avons besoin à l'aide de JsInterop :

1. @JsType(isNative=true, namespace=JsPackage.GLOBAL)

2. public class L {

4. public static native Map map(String id);

5. }

7. @JsType(isNative=true)

8. public class Map {

11. @JsMethod

12. public native L setView(double[] center, int zoom);

13. }

Veuillez noter qu'on a utilisé les mêmes noms de variables que ceux du code source de la bibliothèque Leaflet. Les noms de classes, dans notre exemple L et Map, et les noms des méthodes sont très importants dans JsInterop car du moment où on spécifie isNative=true, GWT va automatiquement chercher dans l'environnement du navigateur les noms des variables similaires et va les associer à ceux définis à l'aide de JsInterop.

On pourra maintenant initialiser une carte Leafet dans notre application GWT sans manipuler du code JavaScript :

1. public class Leafletwrapper implements EntryPoint {

3. double[] positions = {51.505, -0.09};

5. public void onModuleLoad() {

7. // ça marche !!!

8. L.map("map").setView(positions, 13);

9. }

10. }

Le code complet de cet exemple est disponible à : https://github.com/zak905/jsinterop-leaflet

Pour le moment, il n'y a pas de méthode automatisée pour faire l'import d'une bibliothèque JavaScript dans GWT. En attendant un outil qui permette de le faire (du style gwt-api-generator qui est utilisé uniquement pour les éléments Polymer), le développeur doit connaître le fonctionnement de la bibliothèque JavaScript (les méthodes, les arguments, les champs, les namespaces…), et faire le mapping manuellement. Bien sûr, le mapping manuel n'est pas à l'abri de l'erreur, mais c'est le seul moyen qui existe pour le moment. Un autre inconvénient du mapping manuel est lors de l'évolution d'une bibliothèque/framework JavaScript. Encore une fois, le développeur doit incorporer les changements manuellement pour la continuité de l'interopérabilité.

Voici un autre exemple intéressant qui peut aider à comprendre JsIntrop et dans lequel AngularJs est utilisé depuis GWT : https://github.com/bitwerk/AngularGwtExample

II - Web Components et Polymer

Avec l'émergence du nouveau web et des applications riches et interactives, les développeurs web se sont retrouvés à faire des manipulations complexes de HTML, CSS et JavaScript. Travailler avec les trois à la fois n'est pas toujours évident et donc les développeurs et la communauté web en général ont ressenti le besoin d'avoir quelque chose de plus standard afin de pouvoir mieux gérer les bouts de HTML, CSS et JS.

L'idée des Web Components est née de ce besoin. Le but derrière la création des Web Components est la réutilisabilité. La réutilisabilité a été parmi les objectifs principaux des langages orientés objet tels que Java, mais n'a pas été mise en évidence pour la partie client (Frontend). Il y a évidemment beaucoup de patterns qui se répètent d'une application à une autre et donc la question qui se pose est pourquoi ne pas pouvoir les porter et les réutiliser. Imaginez que vous ayez créé une barre de menu pour une application, et vous ayez passé beaucoup de temps sur des choses telles que le HTML, le style, les animations, les événements-…

En développant une nouvelle application, vous réalisez que vous avez besoin du même menu, alors vous retournez à votre projet précédent et commencez à ramasser et recoller les bouts de HTML, JS, CSS et à les adapter à votre nouvelle application ; cela devient fastidieux au fil du temps et propice aux erreurs. Les Web Components fournissent une solution pragmatique à ce problème. Les Web Components fournissent un excellent moyen de portage et de réutilisation de bouts de HTML, CSS et JS, le tout encapsulé dans un tag HTML. Les Web Components sont définis par quatre spécifications qui ont été ajoutées par le W3C aux spécifications HTML :

- custom elements : ce qui permet de créer vos propres composants <mon-element></mon-element> ;

- HTML imports : pouvoir importer ces éléments dans n'importe quel DOM ;

- templates : pouvoir définir des templates de HTML qui sont manipulables par JavaScript;

- shadow Dom : permet de cacher la complexité de certains éléments HTML en cachant le HTML sous-jacent.

Les Web Components sont des spécifications brutes, mais il y a aussi plusieurs frameworks qui sont construits à partir de ces spécifications et qui permettent de tirer avantage de toutes leurs fonctionnalités. Polymer est parmi ces frameworks. Polymer est un projet construit et maintenu par Google. C'est un framework basé sur les Web Components et qui permet de construire des applications optimisées, soignées au niveau esthétique et qui peut marcher sur n'importe quel dispositif. Polymer offre également la possibilité d'étendre ses fonctionnalités et de créer vos propres composants réutilisables.

Pour illustrer l'utilisation des Web Components, nous allons créer un élément Polymer simple avec un look personnalisé qui affiche une pop-up à chaque clic. Nous allons appeler cet élément cool-div. Pour faire cela, nous allons créer une définition de l'élément dans un fichier appelé cool-div.html :

1. <dom-module id="cool-div">

2. <template>

3. <style>

4. :host {

5. display: block;

6. }

7. #mydiv{

8. background-color: orange;

9. max-width: 100px;

10. color: white;

11. }

13. </style>

14. <div id="mydiv">

15. <content></content>

16. </div>

17. </template>

19. <script>

20. Polymer({

22. is: 'cool-div',

24. properties: {

25. prop1: {

26. type: String,

27. value: 'cool-div',

28. },

29. },

31. listeners :{

32. click:'divClicked'

33. },

35. divClicked: function(){

36. alert('cool div clicked');

37. }

39. });

40. </script>

41. </dom-module>

On pourra maintenant utiliser cet élément en important simplement la définition dans la section head de la page HTML :

1. <link rel="import" href="cool-div.html">

et puis :

1. <cool-div>mon premier web component</cool-div>

Le code complet de cet exemple est disponible à : https://github.com/zak905/cool-div

II-A - Le point de rencontre entre JsInterop et les Web Components

L'équipe Vaadin a fait des choses intéressantes avec GWT. L'une d'elles a été l'adaptation des éléments Polymer à GWT. La bibliothèque vaadin-gwt-polymer-elements apporte non seulement beaucoup de potentiel pour GWT, mais peut aussi être un remplacement pour les widgets dont le retrait est prévu pour la version 3.0 de GWT. Afin d'adapter les éléments Polymer à GWT, Vaadin a choisi l'approche JsInterop au lieu de tout réécrire from scratch. De cette façon, l'adaptation au contexte GWT a été faite d'une manière très lisse et sans erreur ni conflit. Vaadin a créé un générateur nommé gwt-api-generator qui permet d'envelopper automatiquement les éléments Polymer sous la forme d'une API. Le générateur peut également être utilisé pour générer des API Java pour vos propres éléments Polymer.

II-B - Faire sa première application

Ce n'est pas compliqué de créer une application Polymer dans GWT. Tout ce dont vous avez besoin est d'importer vaadin-gwt-polymer-elements et d'utiliser le flag -generateJsInteropExports lors de la compilation ou en mode dev. Un minimum de connaissance des éléments Polymer et de leur utilisation est nécessaire, mais cela peut se faire très rapidement. Il y a une superbe série de podcasts nommés Polycasts conçus par l'équipe Polymer sur YouTube et qui donnent des leçons sur les bases des éléments Polymer. La documentation des éléments Polymer est aussi bien élaborée et donne toutes les informations nécessaires. Il y a aussi quelques projets dans Github qui peuvent vous aider à obtenir un peu d'inspiration et à surmonter le syndrome de la page blanche :

- https://github.com/manolo/gwt-polymer-todo-list

- https://github.com/gwidgets/gwt-polymer-starter-kit

- https://github.com/cdigiano/polymergwt

Note : pour le moment la version 2.8 bêta pose quelques problèmes pour JsIntrop, il est conseillé d'utiliser la version 2.8-SNAPSHOT.

III - Conclusion et remerciements

JsInterop apporte beaucoup de nouvelles possibilités à GWT. L'utilisation de JsInterop peut également aider à surmonter la confusion qui pourrait survenir avec le système de typage de JavaScript. Avec JsInterop, vous pouvez vérifier au moment de la compilation s'il y a des erreurs de typage. JsInterop ouvre un nouveau monde aux utilisateurs GWT et il est seulement en phase expérimentale. Nous devrons attendre que la version stable de GWT 2.8 soit lancée pour pouvoir utiliser JsInterop en production.

Nous tenons à remercier genthial pour la relecture orthographique attentive de cet article et Mickael Baron pour la mise au gabarit.