-
Notifications
You must be signed in to change notification settings - Fork 10
Cross framework UI Component
Tester Lit-Element avec ReactJS, VueJS et Angular2+
Pour utiliser Lit-Element, il faut installer :
- Lit-Element
- Un polyfill webcomponent
Dans le package.json du module, ajouter :
"lit-element": "^2.2.0",
"@webcomponents/webcomponentsjs": "^2.2.10"Modifier le fichier tsconfig.json et ajouter dans les options du compiler la configuration suivante :
"experimentalDecorators": trueModifier le fichier webpack.config.js:
loaders: [
{
test: /\.(ts|js)$/,
loader: 'ts-loader'
}
]Modifier le fichier gulpfile.js afin d'ajouter la copie du polyfill :
gulp.task('copy-polyfill', ['rev'], () => {
gulp.src('./node_modules/@webcomponents/webcomponentsjs/custom-elements-es5-adapter.js')
.pipe(gulp.dest('./src/main/resources/public/dist'));
});
gulp.task('build', ['copy-polyfill'], () => {
var refs = gulp.src("./src/main/resources/view-src/**/*.html")
.pipe(revReplace({manifest: gulp.src("./rev-manifest.json") }))
.pipe(gulp.dest("./src/main/resources/view"));
var copyBehaviours = gulp.src('./src/main/resources/public/dist/behaviours.js')
.pipe(gulp.dest('./src/main/resources/public/js'));
return merge[refs, copyBehaviours];
});Modifier la vue de l'application pour ajouter le polyfill webcomponent :
<title>{{#i18n}}mediacentre.title{{/i18n}}</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script src="/mediacentre/public/dist/custom-elements-es5-adapter.js" type="text/javascript"></script>
<script src="/mediacentre/public/dist/entcore/ng-app.js" type="text/javascript" id="context"></script>
<script src="/mediacentre/public/dist/application.js" type="text/javascript"></script>Créer un composant dans un dossier elements dans src/main/resources/public/ts :
import {css, html, LitElement} from "lit-element";
class ResourceCard extends LitElement {
static get styles() {
return css`
:host {
background-color: #FFF;
border-radius: 10px;
box-shadow: 0px 5px 5px rgba(0, 0, 0, .2);
}
`
};
render(): any {
return html`<div class="card">
<slot></slot>
</div>`
}
}
export const element = {
name: 'resource-card',
element: ResourceCard
};Ajouter un fichier index.ts dans le dossier elements:
export * from './ResourceCard';Dans le fichier app.ts importer et injecter les Web components :
import * as elements from './elements';
for (let customElement in elements) {
let {name, element} = elements[customElement];
customElements.define(name, element)
}Lors de l'expérimentation, un problème de compatibilité entre AngularJS et lit-element est rapidement arrivé. En effet, le data binding d'Angular rentre en conflit avec le converter de Lit-Element (élément qui transforme les propriétés des webcomponents en fonction du paramètre cf. documentation). Ainsi, à chaque modification par le binding Angular, on retrouve cette erreur :
VM1408:1 Uncaught SyntaxError: Unexpected token g in JSON at position 1
Le problème intervient dans la fonction d'update au niveau du data binding, plus précisément : https://github.com/Polymer/lit-element/blob/master/src/lib/updating-element.ts#L155
Lors d'une modification de la donnée, les propriétés du composant de type Object et Array sont soumis à un JSON.parse.Cependant, lors du repaint par Angular, l'updater de Lit Element semble intercepter la valeur décrite dans l'HTML et tente donc de parser [[myValue]] générant l'erreur précédente.
La solution trouvée est d'utiliser une bibliothèque d'aide trouvée sur internet (et surement non maintenue) : https://github.com/oriweingart/ng-lit
Il suffirait ainsi de modifier les composants créés et d'y ajouter un appel à NgLit :
import {css, html, LitElement} from "lit-element";
import {NgLit} from "ng-lid"
class ResourceCard extends NgLit(LitElement) {
static get styles() {
return css`
:host {
background-color: #FFF;
border-radius: 10px;
box-shadow: 0px 5px 5px rgba(0, 0, 0, .2);
}
`
};
render(): any {
return html`<div class="card">
<slot></slot>
</div>`
}
}
export const element = {
name: 'resource-card',
element: ResourceCard
};Pour rendre cross framework et rétro-compatible (pour les applications AngularJS) l'infra front, il faudrait forker la librairie ngLit et la modifier pour que la surcharge de LitElement ne s'effectue que lorsque l'application utilisée est une application AngularJS.