Comment concevoir un thème personnalisé et léger sous Liferay ?

Cet article survient suite à la réalisation, par notre équipe Plateformes d’intégration et Intelligence Artificielle, d’un site informationnel pour l’un de nos clients, une grande entreprise canadienne de télécommunication et de médias, en utilisant Liferay 7 (la dernière version du portail Liferay).

Alexis, développeur front-end, vous partage son expérience sur ce projet afin de vous expliquer comment il est possible de créer un thème léger et rapide à charger avec Liferay.

En 2015, nous avons découvert le site de Bugaboo, réalisé sous Liferay 6.2. Une chose nous a surpris : l’absence des librairies front-end du thème Liferay.
Depuis l’idée a fait son chemin et un mandat similaire est arrivé à Savoir-faire Linux : Réaliser le site web informationnel d’une grande entreprise canadienne de télécommunications et média, avec Liferay.

Avant toute chose, nous devons nous accorder sur un point, la vitesse de chargement d’un site web est un élément déterminant de la rétention des utilisateurs : après 3 secondes [de chargement], jusqu’à 40% d’entre eux vont quitter le site » (Gomez Inc., 2010, en anglais). Pour plus d’informations, voir Lara Callender Hogan (en anglais).

Liferay n’est pas en soi une solution technique qui peut répondre à tous les besoins. Il est tout à fait possible de faire des sites web avec, mais malheureusement la méthode « recommandée », c’est-à-dire étendre le thème Liferay par défaut, aurait été un échec technique pour le site informationnel de notre client à cause d’un allongement considérable du temps de chargement. C’est alors que, basé sur nos expériences avec nos précédents projets, il a été choisi d’adapter en profondeur le thème Liferay afin de pouvoir répondre aux besoins précis de notre client. Dans ce qui va suivre, nous partageons avec vous notre retour et nos résultats.

Le portail Liferay, un outil puissant qui a besoin d’accompagnement

Liferay est un gestionnaire de contenu (CMS) et un portail écrit en Java fournissant de nombreuses fonctionnalités spécifiques aux développeurs comme une gestion avancée des utilisateurs, des droits d’accès, des documents, etc. Dans notre cas, en tant que société de services, nous avons la possibilité de l’adapter autant que nous le voulons aux besoins de nos clients. Par contre, étant pensé pour être un portail modulaire, il y a quelques défauts liés aux thèmes et aux performances à considérer avant de concevoir un site web avec. En voici la liste :

  • Le thème de base de Liferay charge par défaut toutes les librairies front-end ainsi que l’ensemble des styles que Liferay et ses portlets ont besoin. Cependant, une grande partie du code et des dépendances s’avère inutile pour un visiteur non-connecté (soit la majorité de nos utilisateurs dans le cadre de ce projet). De nombreux problèmes de performance apparaissent donc à cause de cette surcharge inutile de code.
  • Liferay impose la présence de son Design Language, Lexicon (ou plutôt, sa seule implémentation: Clay). Cela provoque également plusieurs problèmes :
    • Manque de correspondance entre le Design Language et les besoins visuels requis pour ce projet, limitant grandement les designs réalisables et ou en compliquant grandement la personnalisation,
    • Conflits au sein des règles CSS, augmentant le temps de développement,
    • Les mises à jour et corrections du thème de base de Liferay peuvent briser les styles développés provoquant alors une augmentation significative du temps de maintenance,
    • L’administration des contenus étant à même les pages, les styles développés peuvent briser le comportement des styles d’administration participant aussi à l’augmentation du temps de développement et de maintenance.

Comment alors réaliser un thème léger sous Liferay ?

La solution pour bénéficier de la puissance de Liferay tout en gardant le contrôle de la vitesse de chargement des pages est de créer un thème léger ne contenant aucune des librairies Liferay front-end comme senna.js, AlloyUi, Lexicon/Clay, etc.

Cependant, dans Liferay 7, ce n’est pas aussi facile que cela n’y paraît, notamment dû à l’impossibilité d’avoir une vue d’administration (indépendante) pour le site. Pour échapper à cela, nos fantastiques développeurs back-end de l’équipe ont développé un module, le « Theme Switcher », qui permet de forcer l’affichage d’un thème en fonction du rôle d’un utilisateur. Dans notre cas, cela nous permet d’afficher un thème classique Liferay uniquement aux administrateurs du site. Voici le lien vers le GitHub du « Theme Switcher » : savoirfairelinux/liferay-theme-switcher

5 étapes pour la mise en place d’un thème léger sous Liferay

Un exemple de thème léger pour Liferay disponible sur notre GitHub : savoirfairelinux/lightweight-liferay-theme. Ce thème utilise une architecture Maven, mais libre à vous de le modifier.

Étape 1 – Nettoyage du thème

Retirez les inclusions du fichier portal_normal.ftl, principalement: <@liferay_util["include"] page=top_head_include />. Mais aussi <@liferay_util["include"] page=body_top_include /> et j’en passe…

Étape 2 – Réparation du thème

Malheureusement la variable top_head_include ne contient pas que les librairies CSS et javascript de Liferay, mais aussi beaucoup d’autres choses. Il est donc nécessaire de ré-inclure les balises du head qui nous intéressent.

Par exemple,

  • Les meta-tags que l’utilisateur peut définir dans chaque pages (keywords, description, etc…):

<@liferay_theme["meta-tags"] />

  • La définition des urls canoniques:
<#if !is_signed_in && layout.isPublicLayout() > 
  <#assign completeURL = portalUtil.getCurrentCompleteURL(request) > 
  <#assign canonicalURL = portalUtil.getCanonicalURL(completeURL, themeDisplay, layout) > 

  <link href="${htmlUtil.escapeAttribute(canonicalURL)}" rel="canonical" /> 

  <#assign availableLocales = languageUtil.getAvailableLocales(themeDisplay.getSiteGroupId()) > 

  <#if availableLocales?size gt 1 > 
    <#list availableLocales as availableLocale> 
      <#if availableLocale == localeUtil.getDefault() > 
        <link href="${htmlUtil.escapeAttribute(canonicalURL) }" hreflang="x-default" rel="alternate" /> 
      </#if> 
      <link href="${htmlUtil.escapeAttribute(portalUtil.getAlternateURL(canonicalURL, themeDisplay, availableLocale, layout)) }" hreflang="${localeUtil.toW3cLanguageId(availableLocale)}" rel="alternate" /> 
  </#list> 
  </#if> 
</#if> 

Pour savoir quoi aller chercher, et comment, basez-vous sur la jsp qui est utilisée pour générer la variable top_head_include : https://github.com/liferay/liferay-portal/blob/7.0.x/portal-web/docroot/html/common/themes/top_head.jsp

Étape 3 – Organisation

Un des problèmes, et vous l’aurez peut-être deviné : les tâches liferay-theme-tasks fonctionneront difficilement.

Cependant, bonne nouvelle : Vous pouvez organiser votre futur thème de la manière dont vous le souhaiter et selon les standards de développement de votre équipe (sass, less, es6, etc.). Dans le cas de notre client, nous avons utilisé et agrémenté le gulpfile habituel pour nos projets web. Le tout chapeauté par Maven et des modules front-end.

Étape 4 – Automatisation du déploiement du thème léger

Cette partie a été la plus longue, je vous avoue, mais elle vous est maintenant disponible clé en main, dans la tâche gulp ‘deployLocal:syncTheme’ du thème d’exemple !

Il s’agit de la mise en place d’un déploiement « live » des fichiers du thème.

D’un point de vue global, le but est de ne pas avoir à compiler ni à attendre le déploiement du thème pour chaque modification de CSS ou de javascript (fonctionnalité normalement présente dans les liferay-theme-tasks). Dans le contexte OSGI de Liferay 7, il n’est pas facile d’accéder directement aux fichiers du thème (CSS, javascript, templates, etc.).

L’idée est alors de modifier la manière dont le thème est déployé dans OSGI, en le faisant pointer non pas vers le fichier .war du thème compilé (en mode webbundle, celui par défaut), mais plutôt vers le dossier extrait de ce .war (en mode webbundledir).

Étape 5 – Profitez

Vous avez maintenant un thème Liferay, qui contient uniquement ce que vous désirez pour votre projet, et qui est déployable comme n’importe quel autre thème Liferay.

Tests et résultats

Dans le but d’évaluer les avantages en terme de performances de la mise en place d’un thème léger, vous pouvez lancer un test, sur une même page avec le même contenu, avec 3 cas possibles de choix de thème. De notre côté, nous avons lancé ces tests sur un serveur Liferay configuré pour la production avec 8 CPU, 28Go de RAM et un disque SSD. Ci-dessous les 3 cas pour lesquels nous avons lancé le test.

Les 3 cas possibles de choix de thème

  1. Utilisation d’un thème vanille de Liferay, un thème classique
  2. Utilisation du thème léger que nous avons développé pour le site informationnel de notre client
  3. Utilisation du thème classique avec l’ajout des styles CSS et javascript du thème que nous avons développé pour notre client

Pour réaliser les mesures, nous avons utilisé une instance locale de speedtest.io (6.0.3) avec Chrome 62. Pour chacun des cas, 10 appels ont été réalisés. Ci-dessous un résumé des résultats :

Résultat du cas 1 : Le thème classique de Liferay

  • 52 requests
  • 1064.77 kb
  • DOMContentLoaded : 1.24s (±31.95ms)
  • Chargement : 2.06s (±52.89ms)
  • speedIndex : 1349 (±34.99)

Nous considérons ces résultats comme corrects car ils se trouvent dans la moyenne que l’on peut trouver actuellement sur le web. Néanmoins, il y a tout de même un grand nombre de requêtes, dépassant le seuil des 40, habituellement recommandé.

Résultat du cas 2 : Le thème léger

  • 37 requests
  • 800.38 kb
  • DOMContentLoaded : 588ms (±42.96ms)
  • Chargement : 1.17s (±55.17ms)
  • speedIndex : 863 (±39.57)

Moins de requêtes, une page plus légère, ce thème personnalisé est plus performant que le thème classique de Liferay !

Résultat du cas 3 : Le thème classique avec les CSS et javascript du thème léger de notre client

  • 56 requests
  • 1214.59 kb,
  • DOMContentLoaded: 2.22s (±457.34ms),
  • Load: 2.97s (±458.11ms)
  • speedIndex: 2475 (±456.71)

Ce résultat est très important, car il s’agit d’un cas qui pourrait être réel. Un thème Liferay, avec un visuel complètement personnalisé mais plus que deux fois plus lent à charger…

Conclusion

Dans l’ensemble, cette expérience fut instructive et nous a fourni, ainsi qu’à notre client, des résultats à la hauteur de nos espérances.

Néanmoins, la mise en place d’un thème léger ne peut pas s’appliquer pour n’importe quel type de site web et devenir une solution unique pour vos projets web. De plus, avec cette méthode, certaines fonctionnalités (front-end) de plusieurs Portlet Liferay se trouvent inaccessibles.

 

Revue de presse Inno #11

Développement Web

Bien démarrer avec le rendu côté serveur avec Angular

Par Kévin Barralon

Cette semaine, nous avons mis en ligne un tutoriel pour les développeurs qui utilisent le framework JavaScript Angular. Ce tutoriel a pour but de les aider à initialiser un projet Angular avec le rendu côté serveur pré-configuré. L’intérêt de la mise en place d’un rendu côté serveur permet de rendre le contenu d’une application lisible par les robots (Google, Facebook, Twitter) mais aussi d’améliorer les performances d’une application Angular, avec le transfert d’état entre le côté serveur et le côté client. Ces fonctionnalités étant une nouveauté du framework, la dernière version de Angular (v5) fut utilisée dans ce tutoriel.

Vous pouvez accéder à une version plus complète de ce tutoriel en lisant cet article : Comment créer une application Angular avec le rendu côté serveur ?

Emballer vos applis JavaScript avec Parcel

Par Jacob Cook

L’écosystème JavaScript est connu pour son évolution rapide et constante. Le développement d’une application moderne en JavaScript nécessite une panoplie d’outils et librairies, y compris des “bundlers”, qui gèrent la génération et emballement des “assets” nécessaires lors de la création d’une site Web. Jusqu’à présent, il y a eu deux grands projets de “bundlers” : Browserify et Webpack. Ils ne sont pas vraiment connus pour être faciles à apprendre ou à utiliser. On n’a qu’à aller chercher Google pour savoir “pourquoi est-ce que Webpack est si… lent ? …compliqué ?” et ainsi de suite.

Il est clair que l’écosystème a besoin d’un coup de pouce à ce sujet. Il y a un nouveau projet qui compte justement donner ce coup de pouce, et il s’appelle Parcel. Il fait pas mal les mêmes choses que Webpack à la base (code splitting, transpilation et transformation, hot module replacement) mais avec très peu de “bootstrapping” à faire, et pas beaucoup d’options ou de configurations à écrire pour assurer son bon fonctionnement. Il utilise aussi un système de compilation à multi-cœur, ce qui lui permet d’être bien mieux optimisé en terme de performance et d’utilisation CPU de votre ordinateur à travers plusieurs “workers”.

Reste à voir si Parcel sera couronné le “bundler” JavaScript par excellence, mais si les premiers retours d’utilisations se confirment, il apportera une bouffée d’air frais aux développeurs Web qui ne veulent que démarrer leur prochain projet moderne avec rapidité et efficacité. Et sans avoir besoin d’aspirine ! Pour en savoir plus sur Parcel : https://parceljs.org/

Pause Hivernale !

Merci de nous avoir suivi pendant ces 11 numéros. Toute l’équipe vous souhaite un joyeux temps des fêtes.

On se revoit en Janvier 2018 !
Votre équipe Inno Hebdo

Comment créer une application Angular avec le rendu côté serveur ?

Gestion du rendu côté serveur : Une nouveauté Angular imposant un défi

Angular est un framework utilisant le langage de programmation TypeScript. La version 5 a été mise en ligne en novembre 2017, avec de nouvelles fonctionnalités et corrections de bugs. Cette dernière version est accompagnée de l’outil en ligne de commande Angular CLI, mais aussi de nouveautés  attendues et réellement plébiscitées par la communauté, comme la gestion du rendu côté serveur.

Un des problèmes récurrents que l’on peut rencontrer lorsque l’on met en place un site web avec une librairie moderne (Angular, React, Vue.js, etc.) est que, de manière générale, les robots ne pourront pas lire votre site. Par conséquent, si vous souhaitez partager votre article sur Facebook, ou simplement être bien référencé sur les moteurs de recherche, la partie risque d’être compliquée (bien que dans le cas de Google, il semblerait que leurs robots soient capable de lire des pages générées par Javascript depuis récemment).

La raison est simple, la plupart des robots ne savent pas à quel moment votre page sera entièrement générée par Javascript. Par conséquent, ils ne seront en mesure de lire qu’une infime partie de votre HTML, à savoir, bien souvent, un petit ‘Loading…’ pas très explicite !

Comment peut-on alors créer une application Angular avec le rendu côté serveur ?

Angular CLI

Pour pallier à ce problème, Angular CLI (l’outil qui aide à la génération d’une application Angular) peut venir à la rescousse. Également, avec la version 5 d’Angular, il est désormais possible de gérer le transfert d’état serveur vers le client. Par exemple, une application qui fait une requête à une API Rest ne fera pas la même requête deux fois (une fois côté serveur, une autre fois côté client) mais transférera le résultat côté serveur au client. Nous allons étudier ces deux cas successivement afin de pouvoir bien démarrer une application avec le rendu côté serveur.

Comment initier le projet Angular?

Démarrons en installant l’outil Angular CLI :
npm i -g @angular/cli

On initialise ensuite notre projet :
ng new ssr-app style=scss # Parce que c'est mieux avec le SCSS

On va dans le répertoire de l’application générée et on lance le serveur de développement :

cd ssr-app
ng serve

Allez sur http://localhost:4200/ et enjoy ! Maintenant, nous devons configurer la gestion du rendu côté serveur.

Comment configurer le rendu côté serveur?

Commençons par installer le package platform-server : npm i -S @angular/platform-server

Dans le fichier .angular-cli.json à la racine du projet, il faut ajouter dans la partie « apps », la configuration suivante :

{
   "name": "universal",
   "platform": "server",
   "root": "src",
   "outDir": "dist-server",
   "main": "main.server.ts",
   "tsconfig": "tsconfig.server.json",
   "environmentSource": "environments/environment.ts",
   "environments": {
      "dev": "environments/environment.ts",
      "prod": "environments/environment.prod.ts"
   }
}

Dans notre dossier src/app, on a désormais besoin d’un fichier app.server.module.ts à côté de notre fichier app.module.ts. Ce sera notre point d’entrée pour notre application côté serveur. Son contenu :

import {NgModule} from '@angular/core';
import {ServerModule} from '@angular/platform-server';

import {AppModule} from './app.module';
import {AppComponent} from './app.component';

@NgModule({
   imports: [
      AppModule,
      ServerModule
   ],
   bootstrap: [AppComponent]
})
export class AppServerModule {
}

Le fichier hérite simplement des modules du fichier app.module.ts et ajoute le module ServerModule.

Quant au fichier main.server.js renseigné dans le .angular-cli.json, nous devons le créer à côté du fichier main.ts dans le répertoire src/ avec le contenu suivant :

import {enableProdMode} from '@angular/core';
export {AppServerModule} from './app/app.server.module';

enableProdMode();

Nous devons également créer un fichier tsconfig.app.server.json pour la compilation de TypeScript à côté du tsconfig.app.json dans le même répertoire :

{
   "extends": "./tsconfig.app.json",
   "compilerOptions": {
      "outDir": "../out-tsc/server",
      "module": "commonjs"
   },
   "exclude": [
      "test.ts",
      "**/*.spec.ts"
   ],
   "angularCompilerOptions": {
      "entryModule": "app/app.server.module#AppServerModule"
   }
}

Dans le répertoire src/app, il nous faut désormais modifier le fichier app.module.ts en ajoutant une méthode à notre module BrowserModule :

import {BrowserModule} from '@angular/platform-browser';
import {NgModule} from '@angular/core';
import {AppComponent} from './app.component';

@NgModule({
   declarations: [
      AppComponent
   ],
   imports: [
      BrowserModule.withServerTransition({ appId: 'universal' })
   ],
   providers: [],
   bootstrap: [AppComponent]
})
export class AppModule {
}

On peut désormais builder notre application côté serveur/côté client. Pour cela, rajoutons une ligne dans les scripts de notre package.json :

"scripts": {
   ...
   "universal": "ng build --prod &amp;&amp; ng build --prod --app universal --output-hashing=none",
   ...
}

A quoi sert cette commande ? Tout simplement à générer d’une part, une build côté client et, d’une autre part, une build côté serveur (avec la référence à notre app configurée dans le fichier .angular-cli.json). Pour le côté serveur on enlève la création d’un hash sur le fichier généré main.bundle.js pour pouvoir y faire référence plus tard.

Si on lance la commande npm run universal, on obtient bien nos deux builds dans deux fichiers respectifs dist/ et dist-server/.

Désormais, on souhaite pouvoir lancer notre serveur. Pour l’instant, le package Universal d’Angular ne supporte que Node.js et ASP.NET. Nous allons écrire notre serveur en Node.js.

Il faut tout d’abord installer le package @nguniversal/express-engine qui permettra de bootstraper notre serveur Node.js avec le framework Express. Il suffit donc de lancer la commande npm i -S @nguniversal/express-engine.

On va ensuite écrire un fichier server.js à la racine de notre projet avec ce contenu :

require('zone.js/dist/zone-node');

const express = require('express');
const ngUniversal = require('@nguniversal/express-engine');

/**
* On charge le seul fichier de notre build côté serveur
*/
const bootstrap = require('./dist-server/main.bundle');

/**
* On crée motre instance Express
*/
const app = express();

app.get('/', (req, res) =&gt; res.render('index', {req, res}));

/**
* Obtient les fichiers statics provenant de la build dist/
*/
app.use(express.static(`${__dirname}/dist`));

/**
* Configuration de Express Engine
*/
app.engine('html', ngUniversal.ngExpressEngine({
   bootstrap: bootstrap.AppServerModuleNgFactory
}));
app.set('view engine', 'html');
app.set('views', 'dist');

/**
* Toutes les URLs renvoient à l'index.html du répertoire dist/
* Angular se charge se rediriger vers les bonnes routes
*/
app.get('*', (req, res) =&gt; res.render('index', {req, res}));

/**
* On lance notre serveur
*/
app.listen(3000, () =&gt; console.log(`Listening on http://localhost:3000`));

Champagne ! Nous avons enfin configuré notre application Angular ainsi que notre serveur Node.js.

Lancez le serveur en tapant ‘node server.js’ et accédez à l’URL http://localhost:3000. Votre page est générée côté serveur au lancement, puis prise en charge par la build côté client une fois chargée. Si vous désactivez le Javascript de votre navigateur, miracle ! Votre page est tout de même générée grâce à notre configuration.

Comment transférer l’état de l’application ?

Bien que notre application fonctionne parfaitement avec cette configuration, celle-ci n’est pas complètement optimale.

Si votre application nécessite des requêtes via une API Rest par exemple, celles-ci seront effectuées deux fois au lieu d’une. En effet, si le serveur est sollicité pour effectuer une requête, le navigateur ne le sait pas et effectuera cette même requête une seconde fois lorsque le côté serveur prendra le relai.

Pour l’exemple, nous allons commencer par ajouter le HttpClientModule dans notre app.module.ts et notre app.server.module.ts (l’idéal serait d’avoir un fichier de modules en commun, mais je vous laisse la liberté de le faire !) :

import {HttpClientModule} from '@angular/common/http';

@NgModule({
   ...
   imports: [
      ...
      HttpClientModule
   ],
   ...
})
export class AppModule {
}

Allons dans notre app.component.ts et supprimons le contenu que nous allons remplacer par :

import {Component, OnInit} from '@angular/core';
import {HttpClient} from '@angular/common/http';

@Component({
   selector: 'app-root',
   templateUrl: './app.component.html'
})
export class AppComponent implements OnInit {
   image: any;

   constructor(private http: HttpClient) {
}

ngOnInit() {
   this.http.get('http://www.splashbase.co/api/v1/images/random')
      .subscribe(data =&gt; this.image = data);
    }
}

Nous nous chargeons d’afficher une image random récupérée via une API Rest.

Pour le rendu, éditons notre fichier app.component.html que nous remplacerons par cette unique balise :

< img *ngIf="image" [src]="image.url" >

Cette image sera donc le résultat de notre requête à l’API.

Si nous démarrons une build avec npm run universal et que nous lançons notre serveur avec ‘node server.js’, nous avons bien notre page qui fonctionne correctement. Petit bémol : l’image apparaît quelques millisecondes et est remplacée par une autre image.

La raison est le même que précédemment : une requête est faite côté serveur, et une autre est faite côté client une fois la page chargée. Le requête côté client est donc inutile.

L’idée est donc de transférer l’état de notre requête vers le côté client afin de ne pas multiplier les requêtes inutiles.

Pour cela, nous allons importer le ServerTransferStateModule dans notre app.server.module.ts et le BrowserTransferStateModule dans notre app.module.ts :

/* app.server.module.ts */
import {ServerTransferStateModule} from '@angular/platform-server';

@NgModule({
   imports: [
      ServerTransferStateModule /* Ici ! */
   ],
   bootstrap: [AppComponent],
})
export class AppServerModule {}

/* app.module.ts */
import {BrowserTransferStateModule} from '@angular/platform-browser'

@NgModule({
imports: [
   ...
   BrowserTransferStateModule /* Ici ! */
   ],
   bootstrap: [AppComponent],
})
export class AppServerModule {}

Une fois la configuration effectuée, on peut se rendre dans notre fichier app.component.ts. On crée ensuite une clef avant la déclaration de notre Class et on ajoute TransferState dans notre constructeur :

import {makeStateKey, TransferState} from '@angular/platform-browser';

const IMAGE_KEY = makeStateKey('image');

@Component({
   selector: 'app-root',
   templateUrl: './app.component.html'
})
export class AppComponent implements OnInit {
   ...
   constructor(private http: HttpClient,
      private state: TransferState) {
   }
...
}

Ensuite on modifie notre méthode ngOnInit de cette manière :

ngOnInit() {
   const image: any = this.state.get(IMAGE_KEY, null);

   /**
   * Si l'image n'est pac contenue dans notre clef, on effectue la requête
   */
   if (!image) {
      this.http.get('http://www.splashbase.co/api/v1/images/random')
         .subscribe(data =&gt; {
            this.image = data;
            this.state.set(IMAGE_KEY, data as any);
          });
   }

   /**
   * Sinon, on récupère le contenu de notre clef
   */
   else {
      this.image = image;
   }
}

On lance ensuite une build de notre application ainsi que notre serveur :

npm run universal
node server.js

Désormais, le contenu de l’image est transféré du serveur au client et la requête n’est effectuée qu’une fois !

Conclusion

Vous avez maintenant toutes les cartes en mains pour démarrer une application Angular avec le rendu côté serveur configuré.

Il suffit maintenant de faire attention à ne pas appeler des objets disponibles uniquement sur le navigateur (comme window par exemple) sans condition.

Par exemple pour vérifier que l’on est côté client ou non :

import { PLATFORM_ID, Inject } from '@angular/core';
import { isPlatformBrowser } from '@angular/common';

   constructor(
      @Inject(PLATFORM_ID) private platformId: Object,
      @Inject(APP_ID) private appId: string) {
      if (isPlatformBrowser(platformId)) {
         console.log('Je suis appelé côté client !')
      }
    }

Toutes ces astuces simplifieront vos développements Angular avec tous les avantages du rendu côté serveur !

Revue de presse Inno #7

Mobile

Protocoles génériques et Type Erasure en Swift

Avec Swift, vous pouvez définir des protocoles en leur associant un ou plusieurs types génériques. Ces types sont définis en utilisant le mot-clé « associatedtype ».  L’appellation « type générique » est un peu usurpée ici, nous devrions plutôt parler d’un espace réservé pour un type inconnu. En effet, nous verrons que de tels protocoles n’offrent pas une grande souplesse d’utilisation lorsqu’il s’agit de réellement les considérer comme génériques.
En savoir plus :

Développement Web

Django 2.0 Release Candidate désormais disponible

Par Kévin Barralon

Le framework Django dont la prochaine version 2.0 est prévue autour du 1er décembre vient de publier sa version Candidate ce jeudi 15 novembre. Contrairement à ce que l’on pourrait penser, cette nouvelle version ne va pas apporter d’incompatibilités majeures au sein du framework. Les changements seront donc du même acabit que les versions précédentes.

Cependant, le changement important de cette version 2 sera l’incompatibilité avec Python 2.7, dont la fin du support est programmée pour 2020. Django 2.0 supportera donc au minimum la version 3.4, même s’il est chaudement recommandé de passer directement à la dernière version de Python (3.6 actuellement).

Routage d’URL

Au niveau des nouveautés, la nouvelle fonction django.urls.path() rend la syntaxe du routage des URL beaucoup plus simple et lisible. Ainsi, au lieu d’écrire : url(r'^articles/(?P[0-9]{4})/$', views.year_archive)

vous pourrez écrire : path('articles/<int:year>/', views.year_archive)

Cette nouvelle syntaxe permettra également de recevoir dans la vue (views) les arguments avec le typage défini (un nombre entier dans le cas de year au lieu d’une string).

Dans cet exemple, il n’y a toutefois pas de possibilité d’ajouter une contrainte (une année à 4 chiffres dans notre exemple). Pour cela, la fonction actuelle django.conf.urls.url() sera remplacée par django.urls.re_path(), qui permettra de conserver la possibilité de mettre des expressions régulières dans la définition de l’URL.

La fonction django.conf.urls.include() sera également directement disponible via django.urls. Pour pourrez ainsi importer vos modules de la manière suivante from django.urls import include, path.

Autres nouveautés

  • Pour les autres nouveautés : L’admin de Django 2.0 sera désormais responsive, donc adapté aux appareils mobiles.
  • Une nouvelle classe Window a été ajoutée afin de permettre l’utilisation du mot-clé OVER dans les requêtes SQL.
  • Une liste de tous les ajouts mineurs est disponible dans le communiqué officiel.
En savoir plus :

Déployer des services entiers avec Docker Swarm et Gitlab CI

Chez Savoir-faire Linux, je travaille (entre autres) sur l’infrastructure de déploiement pour plusieurs services que l’on héberge, et je suis toujours à l’affût de méthodes innovantes pour améliorer notre pratique DevOps. Présentement, le système de déploiement est axé autour de l’utilisation de Ansible pour « provisioner » un service dans une machine virtuelle, et l’ajuster au besoin après. Mais pour améliorer la stabilité de nos builds, de déploiements et l’agilité avec laquelle on peut faire des déploiements en continu, nous regardons d’autres approches DevOps, comme l’utilisation des containeurs Docker hébergés dans un Registry et déployés par un outil comme Gitlab CI.
Parmi les outils disponibles pour déployer une architecture de « microservice » (créée avec docker-compose), nous trouvons Docker Swarm. En utilisant un certain nombre de serveurs proprement configuré, on peut déployer un « stack » de containeurs avec un simple docker stack deploy. Docker va choisir par la suite la meilleure configuration pour le déploiement des différents containeurs à travers l’infrastructure du Swarm. Il va même aller jusqu’à configurer la réseautique entre les containeurs automatiquement, comme si tu utilisais docker-compose sur un ordinateur en local.
 
La meilleure partie, c’est le fait que ça marche bien avec notre système d’automatisation des builds déjà existant, GitLab CI. Nous pouvons faire le pipeline « build – test – release – deploy » à travers toute notre infrastructure avec GitLab CI et le GitLab Container Registry. Il y a toujours des parties casse-têtes à régler, mais ce système représente déjà un grand bond vers l’avant pour la simplicité et l’efficacité de notre pratique DevOps.
En savoir plus :

Revue de presse Inno #6

Design

Atomic Design

Par Patrick Bracquart 

Depuis l’avènement du web, on parle de conception de pages web. Ce terme, hérité du domaine imprimé, démontre bien la considération du contenu web depuis les années 90 : une architecture composée de pages consultables, comme un livre. 
Or, depuis maintenant quelques années, la multitude de plateformes disponibles pour consulter du contenu web ne cesse d’augmenter et de se complexifier. De l’ordinateur au mobile en passant par la télévision ou encore les montres intelligentes, il est devenu clair que le concept de design et de structure de pages web est obsolète. 

 

L’atomic design, terme inventé par Brad Frost, est une nouvelle méthodologie de design. Au lieu de penser son contenu comme une page, chaque élément de design est conçu en partant du plus petit élément (comme un call to action) vers un ensemble plus grand. On part de l’atome pour créer une molécule et elles s’assemble pour créer un organisme web cohérent et modulable. 

Chaque atome étant placé individuellement dans une librairie, l’atomic design est un gain de temps et de cohérence en plus d’une mise à jour simplifiée.

Pour en savoir plus :

Développement web

Makefile ou comment éviter de réinventer la roue

Par Samuel Sirois

Après m’être absenté pendant quelques années de la partie frontale des applications web, j’ai été récemment appelé à replonger dans ce monde à travers deux projets auxquels je collabore. Une belle occasion de revisiter mes idées préconçues et mes vieilles habitudes de travail puisqu’une base de code déjà existante et utilisant les derniers outils à la mode est présente sur mon poste après le git clone initial.

Ouf ! Ça bouge vite sur la première ligne ! De nouvelles versions d’ECMAScript supportées par les clients Web modernes, une plénitude de pseudo-langages basés sur JavaScript, la multiplication des pré-processeurs CSS… Que dire de tout ces moteurs de production maintenant disponibles spécifiquement développés par et pour les développeuses et développeurs JavaScript ?

Avec toutes ces merveilles, ces derniers (les moteurs de productions) deviennent essentiels pour éviter que l’effort nécessaire pour agréger, minifier, lier, compiler ?!, tous ces fichiers ne viennent pas annuler les gains en efficacité d’avoir dorénavant les outils nécessaires à la création d’applications web modernes.

Je me questionne tout de même à savoir s’il n’y a pas eu un petit manque de communication entre celles et ceux qui ont plus récemment eu ce besoin dans leurs projets (les développeuses et développeurs de la partie frontale) et celles et ceux qui ont déjà eu ces mêmes besoins et qui ont trouvé une solution (pas la seule) à ce problème depuis les années soixante-dix !

Je n’ai jamais ressenti le besoin d’utiliser ces outils modernes, connaissant déjà Make et ayant déjà été confronté à de nouvelles solutions à la mode à la fin du siècle dernier, j’ai finalement fait marche arrière pour revenir à ce qui fonctionnait déjà. Évidemment, je me fais un devoir de rédiger manuellement les Makefiles des projets auxquels je participe et je n’hésite pas à entretenir cet outil.

Réinventer la roue, pour refaire les mêmes erreurs ou pour vraiment améliorer la situation ? Quelques liens intéressants pour vous faire votre propre opinion :

Contribution

Des contributions au Inno Hackest

Devant le succès des après-midis de contributions, l’équipe a décidé de renforcer l’activité et de bonifier sa formule. Dorénavant, ces après-midis auront lieu aux deux semaines sous le nom de « Hackfest ».

 

Nos premiers Hackfest

 

 

Par petits groupes de personnes, jamais tout seul, nos SFLiens ont l’opportunité de se former sur de nouvelles technologies, de contribuer à des projets qui leur tiennent à cœur ou à travailler sur de nouveaux « side project ».
On y retrouve pêle-mêle des initiations à la réalité virtuelle comme la réalisation d’une simulation de chute de Domino avec le moteur physique Unity et l’Oculus Rift, un atelier sur la technologie Blockchain et l’étude du cas concret de l’annuaire des usernames de Ring, la réalisation de POC et de prototypes par exemple sur des bases de données orientées document.

Review Upgrade

Par Maxime Turcotte

La page du rapport d’analyse de migration de Drupal 8, sur laquelle sont répertoriés les modules qui seront migrés et ceux qui ne le seront pas, avait grand besoin d’une refonte afin d’améliorer l’expérience utilisateur. Durant notre après-midi hackfest, j’ai écrit une première version d’un correctif qui réutilise certains éléments de design du tableau de bord d’administration. Ainsi, en ajoutant simplement quelques icônes, il est beaucoup plus facile de voir d’un seul coup d’œil ce qui requiert notre attention.