Aller au contenu principal

Recapt Q3 2022

· 9 minutes de lecture
Damien Buchet

Désolé pour mon absence ces 3 derniers mois ! Je n'ai pas réussi à trouver le temps pour la rédaction de cette newsletter. C'est fou comment de si petits êtres peuvent vous accaparer autant de temps 👶 🤗

Mais je suis de retour pour rattraper le retard, donc voici les nouveautés et nouvelles qu'il ne fallait pas manquer sur l'écosystème React / Javascript, de Juillet, Août et Septembre 2022 🤗

Au programme, forcément un peu plus long :

  • Bun, Deno, quand Node se fait bousculer !
  • Docusaurus 2.0 est sorti !
  • ViteJS 3.0
  • NextJS 12.3, Remotion 3.1, Sandpack 1.8
  • Un comparatif de performances avec 6 frameworks SSR
  • Vous n'avez peut-être pas besoin d'un useEffect
  • A la découverte de Object.freeze & Object.seal
  • Les outils / packages à surveiller
  • WTF JS?

Bun, Deno, quand Node se fait bousculer !

On connaissait déjà Deno le runtime qui promettait d'envoyer Node à l'age de pierre. Deno adopte une série de changements qui devraient conduire à une adoption plus rapide. Dans les prochains mois, Deno permettra d'importer facilement les packages npm, rendant compatible la grande majorité des packages npm existants ! L'import d'un package npm serait aussi simple que

import express from "npm:express@5";

Ils annoncent également pour leur prochaine release majeure, un nouveau serveur http, qui sera le serveur le plus rapide jamais développé en JS

Mais voilà qu'un nouveau runtime challenger se joint à la bataille : Bun qui annonce simplement des performances entre 3x et 10x supérieures à Node et Deno ! Bun est de plus compatible avec les packages npm et embarque nativement des API Web comme fetch, WebSocket et ReadableStream . Bun intégrant également nativement un transpiler, TypeScript et <JSX> fonctionnent nativement.

On pourrait se questionner sur l'interêt de tous ces runtimes. Personnellement je trouve que c'est une bonne chose, la "compétition" fait toujours avancer les choses. Je ne pense pas que ni Deno ni Bun puissent surpasser Node, mais ça aura au moins le mérite de faire bouger les cycles de développement de Node pour intégrer des fonctionnalités plus rapidement. De la même manière que des preact, vue, svelte,.. donnent des coups de fouet à React

Docusaurus 2.0 est sorti !

Après 4 ans de travail, 75 alpha versions et 22 betas, Docusauraus 2.0 est finalement live ! Pour rappel, Docusaurus est un générateur de site statique très facile à utiliser, et performant. C'est le générateur qui propulse ce blog !

Personnellement, ayant découvert Docusauraus déjà en version 2.0-alphaX je ne peux que saluer les améliorations de fonctionnalités, et stabilité, qu'il y a eu lors de mes 7 mois d'adoption. J'attend maintenant avec impatience la sortie de la version 3.0 qui apportera notamment le support de MDX@2

ViteJS 3.0

16 mois après la v2 voici la v3 de Vite! A priori pas de "gros" changement, mais une amélioration des performances, stabilité,... Pendant ce laps de temps, l'adoption de ViteJS a pris des proprtions énormes. SvelteKit, Astra, Hydrogen, Nuxt, Cypress, Vitest, Laravel, ViteRuby (pour ne citer qu'eux) ont tous décider d'utiliser Vite par défaut. Je vous avais également invité à migrer vers Vite pour vos développement React (créés avec create-react-app) tant les améliorations de performance étaient significatives.

Je n'ai pas encore eu l'occasion de migrer vers vite@3, et de regarder si cela corrigeait notamment mes problématiques lors du build de mon app React, mais je compte m'y pencher prochainement !

L'article de blog par ici !

NextJS 12.3, Remotion 3.1, Sandpack 1.8

Plusieurs mises à jour parmi les gros framework / librairies.

On commence avec NextJS qui passe en vers 12.3, qui apporte son lot d'améliorations QOL (Quality Of Life). En améliorant notamment son fast-refresh, les Image Component et le compilateur SWC qui sont maintenant stable. Vous pouvez lire l'article de blog par ici

Remotion la (formidable) librairie pour créer des vidéos en utilisant react passe en version 3.1. Au menu le support des GIF, de TailwindCSS et une amélioration de la prise en charge de Spring. L'article complet par ici

Et on termine par Sandpack qui est sorti de sa phase de beta fin Mai. Sandpack est un toolkit qui permet de créer des éditeurs de code live (avec un rendu immediat de ce que vous codez) et propulsé par CodeSandbox. C'est ce package qui est utilisé dans mes articles de blog pour les passages de code interactifs

Un comparatif de performances avec 6 frameworks SSR

Enterspeed a effectué un comparatif des performances de 6 frameworks SSR, pour choisir sur lequel ils devaient partir pour lancer un nouveau projet. Pour ce faire, ils ont créé un mini site qu'ils ont déployé Netlify, sur 6 apps différentes donc, chacune correspondant à une technologie.

Rappelons rapidement ce que signifie SSR : Server Side Rendering. Vous pouvez retrouver les explications de ces sigles dans mon précédent article

Ces 6 frameworks sont Astro, Gatsby, Next.js, Nuxt 3, Remix et SvelteKit

Vous pouvez lire la methodologie complète et les étapes en suivant ce lien je vous présente juste en dessous leurs résultats avec Google Lighthouse

AstroGatsbyNext.jsNuxt 3RemixSvelteKit
Date de créationMars 2021Mai 2015Octobre 2016Mars 2021Octobre 2020Octobre 2020
⭐ sur Github18.2k53.4k91.8k8.7k19k10.1k
Lighthouse Performance Score99.295.698.698.898.899
FCP (First Contentful Paint)0.8s0.8s0.9s1.1s0.8s0.9s
Speed Index2.8s5.6s3.2s2.9s2.8s2.3s
Largest Contentful Paint (LCP)0.8s1.9s1.2s1.2s1.2s0.9s
Total Blocking Time (TBT)0ms28ms54ms20ms30ms36ms
Time To First Byte (TTFB)137ms133ms63ms438ms136ms62ms

Vous n'avez peut-être pas besoin d'un useEffect

Je vois passer dans les revues de code, aussi bien au sein des élèves de la Wild Code School, que sur Stack Overflow, une mauvaise utilisation des useEffect. Dan Abramov s'est également emparé du sujet en rajoutant un tuto dans le "learning" de la nouvelle documentation React

L'idée à comprendre derrière est qu'un useEffect doit être déclenché quand on a besoin d'effectuer un re-render du composant. Le calcul de variable servant à effectuer le render ne sont pas des effet et doivent être calculés pendant le render. Par exemple :

const MyComp = () => {
const [firstName, setFirstName] = useState('Taylor');
const [lastName, setLastName] = useState('Swift');

// 🔴 Avoid: redundant state and unnecessary Effect
const [fullName, setFullName] = useState('');
useEffect(() => {
setFullName(`${firstName} ${lastname}`);
}, [firstName, lastName]);
}

Ici fullName n'a PAS besoin d'être calculé dans un useEffect et défini dans un state. Cette logique provoquerait d'ailleurs un re-render supplémentaire, car après le premier render, le useEffect sera exécuté, et provoquerait un nouveau re-render. Ici, il suffit de calculer fullName pendant la phase de render

const MyComp = () => {
const [firstName, setFirstName] = useState('Taylor');
const [lastName, setLastName] = useState('Swift');
// ✅ Good: calculated during rendering
const fullName = `${firstName} ${lastname}`;
}

En cas de calcul "lourd", vous pourriez être tenté d'utiliser un useEffect pour stocker le retour du calcul dans un state, et ainsi s'assurer que celui-ci ne soit pas ré-exécuté

const TodoList = ({ todos, filter }) => {
const [newTodo, setNewTodo] = useState('');

// 🔴 Avoid: redundant state and unnecessary Effect
const [visibleTodos, setVisibleTodos] = useState([]);
useEffect(() => {
setVisibleTodos(getFilteredTodos(todos, filter));
}, [todos, filter]);
}

De la même manière, ce n'est pas un "Effect" mais un calcul, il vous faut donc l'exécuter directement pendant la phase de render

const TodoList = ({ todos, filter }) => {
const [newTodo, setNewTodo] = useState('');
// ✅ This is fine if getFilteredTodos() is not slow.
const visibleTodos = getFilteredTodos(todos, filter);
}

Mais vous allez me dire que si le calcul requiert énormement de ressource, il va être ré-exécuté à chaque render, et vous avez raison. Dans ce cas, il faudra "cacher" (ou mémoriser) le résultat du calcul, pour ne l'exécuter qu'une seule fois

import { useMemo, useState } from 'react';

const TodoList = ({ todos, filter }) => {
const [newTodo, setNewTodo] = useState('');

// ✅ Does not re-run unless todos or filter change
const visibleTodos = useMemo(() => {
return getFilteredTodos(todos, filter);
}, [todos, filter]);
}

A la découverte de Object.freeze & Object.seal

Un petit tuto rapide sur ces 2 méthodes freeze et seal.

Object.freeze va permettre de geler un objet. C'est à dire qu'on ne pourra pas ajouter de nouvelles propriétés, ni de modifier ou supprimer les existantes

const obj = {
foo: 'bar'
}

Object.freeze(obj);

obj.foo = "baz";
obj.baz = "foo";

console.log(obj.foo) // 'bar'
console.log(obj.baz) // undefined

Object.seal de son coté va sceller l'objet, ce qui veut dire que vous ne pourrez plus ajouter ou supprimer des propriétés, mais vous pourrez modifier les propriétés existantes

const obj = {
foo: 'bar',
bar: 'foo',
}

Object.seal(obj);

obj.foo = "baz";
obj.baz = "foo";
delete obj.bar;

console.log(obj.foo) // 'baz'
console.log(obj.baz) // undefined
console.log(obj.bar) // 'foo'

Les outils / packages à surveiller

  • reassure Tests de performance pour React & React Native
  • MillionJs Un virtual DOM qui se veut hyper léger (< 1 Ko) et 11x plus rapide que React
  • Awesome React Components Une liste des meilleurs composants React, pour faire à peu près tout ce dont vous avez besoin !
  • Firebase hooks Une librairie de Hooks pour interagir avec Firebase
  • grex Un générateur de RegEx "inversé". Vous lui donnez vos tests cases, et il va (essayer) de se débrouiller pour trouver la RegEx qui match vos exemples

WTF JS?

Que va afficher ce console.log ?

console.log( true + true == true )
Afficher la solution et les explications !

😱 false 😱

Alors pourquoi ?

On va encore se trouver face à un problème de transtypage si cher à Javascript

Utiliser le + en JS est toujours un petit challenge 😃 S'il y a 1 seul String dans l'opération, tout va être transtypé en string, puis vous allez concaténer les chaînes. S'il n'y a pas String, c'est une opération mathématique. Et pour faire une opération mathématique, on transtype en Number !

Et Number(true) === 1. Donc nous avons 1 + 1 == 1, ce qui est donc... false 😉

Ne manquez pas un article !

Envie de recevoir par email mes derniers articles et Recapt ?

Essayez de taper register <votre adresse email> dans la console 🎉