Patrice Ferlet
Patrice Ferlet || Me suivre sur Mastodon
Créateur de ce blog.
Publié le Nov 1, 2021 Temps de lecture: 9 min

Créer une application Web TypeScript / JS en un rien de temps

thumbnail for this post

TypeScript c’est le pied, mais pas “from scratch”. On aime ce que propose Vue, Angular ou encore React en mode “dev” (live reload, HMR, etc…) - alors comment on fait sans framework ? Et bien parlons de “Parcel” qui vient de sortir en version 2 et qui déchire de la licorne (et on parlera aussi de Vite ou SnowPack).

Vous avez déjà codé une application “from scratch” en TypeScript et sans outil particulier ? Si oui, vous connaissez certainement le souci dont je vais vous parler: TypeScript ne remplace pas les “imports” - du coup, votre serveur Web ne trouve pas les ressources. Il faut faire la manipulation d’ajout d’extension. Ça c’est donc le premier souci.

Et puis, soyons honnête, presser F5 pour rafraîchir la page à chaque modification, c’est pas compliqué mais c’est pas confortable.

Allons-y franchement, j’ai envie d’un truc qui ne me pose pas de question, qui me serve ma page pendant que je développe, qui compile correctement le TypeScript, le SCSS, qui me donne quelques possibilités pour les images etc… et ne me prenne pas la tête - ça doit rouler tout seul.

J’ai déjà assez à faire avec mes bugs, pas envie de passer des heures à configurer la construction et/ou l’environnement de développement.

Et c’est pour ça que, pour le moment, je ne pense pas à WebPack. Il est très puissant et configurable, mais moi j’ai pas besoin de ça. Franchement, chapeau bas à ceux et celles qui arrivent à configurer WebPack du premier coup.

Et quid des dépendances à ajouter à package.json pour faire du SCSS, à devoir gérer les versions, et potentiellement devoir adapter les “scripts” pour que tout soit compilé correctement pour avoir une version en développement et en production.

Bref, c’est souvent pour cela que je passe directement par Vue ou Angular, pour m’éviter de devoir me coltiner ces tracas.

Mais j’aime bien coder “from scratch”, parce que je dois juste coder une librairie standard, parce que je veux tester un truc rapidement, bref j’ai pas tout le temps besoin d’avoir un framework complet.

Autre truc, pour une petite application, j’ai des fragments de HTML que je veux utiliser dynamiquement, donc j’ai envie de les importer (à la manière de React, même si je déteste ce Framework) et de les placer dans le DOM. Et ce sans passer par fetch(), juste import "blabla.html".

Et dernier point non négligeable, j’ai envie d’utiliser “Bootstrap”, ou “Bulma” - mais à chaque fois je me demande comment je vais faire pour avoir le droit de toucher à des variables, compiler correctement le bouzin et l’intégrer dans le projet.

Tout ça, tout ce dont je vous parle, c’est ni plus ni moins qu’un besoin de simplification: ne pas utiliser de framework, juste coder, éliminer les dépendances.

Et bien depuis quelques années, une famille d’outil est arrivé pour ça: les Front Build Tools.

Ce que proposent ces outils:

  • un serveur de développement, qui se recharge tout seul lors des modifications, et recharge la page lors de l’injection de module (HMR, Hot Module Replacement)
  • construction de l’application quelque soit la ou les technologies choisies (TypeScript, SCSS, JS, CSS, Less…)
  • transforme les ressources non code en ressources de code (une image, une page HTML, une feuille de style, vous pouvez l’importer et la gérer)

Il en existe tellement, ViteJS, SnowPack ou encore, celui qui m’intéresse le plus et dont on va parler: Parcel

Je vous expliquerai pourquoi j’utilise Parcel et non pas Vite ou SnowPack. Mais vous verrez que ce choix n’est pas figé, et que vous aurez tout à fait raison d’utiliser les autres.

Mais d’abord, commençons par regarder Parcel.

Bon alors Parcel…

Voilà en gros ce que je fais pour commencer à travailler:

# je crée un répertoire de travail
mkdir -p ~/Projects/test-parcel
cd !$

# je crée le projet, avec yarn, mais vous pourriez utiliser npm
yarn init -y

# on installe Parcel en dépendance de développement
yarn add -D parcel

# je remplace dans `package.json` la ligne 
# "main": "index.js"
# par:
# "source": "src/index.html"
sed -i 's,"main": "index.js","source": "src/index.html",' package.json

# je créée la page
mkdir src
echo '<p>Yop</p>' > src/index.html

# et je lane le service de dev
yarn parcel

Voilà, allez à la page http://localhost:1234 et vous avez votre page qui tourne.

La moindre modification de vos sources va rafraîchir la vue. Déjà ça c’est bon !

Et donc, pour le TypeScript ? Facile… Ajoutez un fichier src/main.ts par exemple, et tapez:

class Foo (){
    constructor(private name: string) {}

    hello() {
        console.log(this.name);
    }
}

const f = new Foo("Youpi ?");
f.hello();

et dans index.html:

<script type="module" src="main.ts"></script>

Et voilà, c’est tout… Parcel va utiliser un transpiler pour vous, tout va bien. La page est rafraîchie et dans la console (du navigateur) vous devriez voir apparaître un “Youpi ?”.

Pas une ligne de configuration, rien, que dalle. Ça marche et c’est tout ce qu’on voulait.

Non mais en vrai, on configure un truc ou deux non ?

Oui alors… Parcel n’est pas parfait. Il balance tout dans un répertoire nommé “dist” et je trouve ça pas super pertinent. Parce qu’en plus il ne nettoie pas sa chambre ce bougre. Donc on va améliorer un peu en touchant package.json, voici ce que je fais par habitude:

"scripts" : {
    "predev": "rm -rf .tmp",
    "dev" : "parcel --dist-dir .tmp",
    "prebuild": "rm -rf dist",
    "build": "parcel build"
}

Voilà, comme ça je tape juste yarn dev ou yarn build et tout est propre.

Et pour le SCSS ?

Parcel n’est pas qu’un bundler ou un serveur de dev. Comme ses confrères il a quelques tours dans sa manche.

Partons d’un exemple simple, j’ai envie d’utiliser “Bootstrap”, parce que… je l’ai décidé. Tout va aller très vite:

D’abord j’ajoute bootstrap en dépendance de développement:

yarn add -D bootstrap

Et là vous avez deux solutions:

  • soit vous codez salement comme dans React
  • soit vous décidez de faire les choses plus proprement

Donc, pour les gorets, dans main.ts:

import '../node_modules/bootstrap/scss/bootstrap.scss'

Et sinon pour les vrais professionnels, vous créez un fichier styles.scss:

@import '../node_modules/bootstrap/scss/bootstrap.scss'
/* Et là vous pouvez mettre vos adaptations, changements de couleurs etc... */

et vous ajoutez cela dans index.html:

<link rel="stylesheet" href="styles.scss" />

Dans les deux cas, il va se passer un truc “étrange”, mais tellement génial.

Parcel va, tout seul, ajouter une “devDependencies” dans package.json - un plugin qui va compiler le SCSS et le placer où il faut.

Sans redémarrer le service, sans rien faire de spécial, ça va marcher.

Et bien entendu, en TypeScrip, vous pouvez utiliser “bootstrap” pour injecter des alertes, des “toast”, etc. D’ailleurs, Bootstrap propose une petite page de documentation pour utiliser Parcel et je vous conseille bien entendu d’aller la lire !

“Et tu parlais d’import de ressources ?”

C’est un truc qui marche aussi dans les autres build tools, mais chez Parcel j’aime beaucoup comment on s’en sert.

Faire un fichier config.yaml:

mode: prod
title: "[DEV] Exemple de code"

et importer ça comme ça dans du TypeScript:

import config from "config.yaml";

if (config.mode == "prod") {
    // et faire des choses ici
}

En gros, les ressources qui ne sont pas des fichier JS/TS sont quand mêmes utilisables.

Quand j’ai besoin de faire des fragments de code HTML, j’avoue que l’import est plus tordu. Prenons un exemple, dans mon index.html je vais faire ça:

<div id="app"></div>

Et j’ajoute un fichier content.html:

<p>Et voilà le contenu !</p>

Dans le main.ts voilà ce que je peux faire:

// comme je veux le texte, je demande un import "bundle-text"
import  content from "bundle-text:./content.html";

document.querySelector("#app").innerHTML = content

Tout est expliqué dans la page qui parle de bundle inline.

Il faut utiliser ça avec parcimonie, n’est-ce pas chers amis fans de React…

Et quand on foire ?

Pas de panique, que ce soit dans la console ou le navigateur, l’erreur apparaît et vous aide beaucoup à corriger.

Exemple d’erreur qui apparait dans le navigateur

Mais vraiment, pour Typescript, ajoutez des dépendances

Parcel s’occupe de construire et empaqueter, mais il ne paramètre pas votre IDE. C’est pourquoi j’ajoute quand même deux dépendances:

yarn add -D eslint@^7 typescript

# et je génère les fichiers de conf
yarn tsc --init
yarn eslint --init

Aux questions de eslint je fais en sorte de prendre en compte TypeScript, je “réponds aux question de style” pour forcer les “double-quote” et les point-virgules, et supprime finalement la partie “indent” du fichier .eslintrc.json - parce que finalement, 2 espaces c’est pas si mal1

En utilisant “NeoVim” + “Coc” (https://github.com/neoclide/coc.nvim) j’ai de quoi coder, avec des imports automatiques, des correction automatiques, documentation et autocompletion, le tout dans le terminal2.

NeoVim TS error NeoVim TS documentation

Bref, zero-conf oui, mais faut pas non plus faire la feignasse tout le long, avoir de quoi bosser proprement ça demande un peu de paramétrage, soyons sérieux.

Alors donc, pourquoi pas Vite ou SnowPack ?

“Vite” et “SnowPack” sont excellents. Je ne vais pas dire le contraire et je pousse les gens à regarder les trois outils.

“Vite” est d’ailleurs bien plus populaire. Pour des raisons certainement très défendables.

Alors, calmez vous les fans de Vite et SnowPack, je ne dis pas qu’ils sont moins bons - attendez de lire ce qui suit.

SnowPack ne correspond pas à mon besoin, il demande une structure et je dois passer par une phase “d’init” (yarn snowpack init, changer le “root” etc…) - il est certes puissant et très performant mais je cherche avant tout, justement, à me passer de la configuration. SnowPack a un autre objectif et dans le cas que je présente ici, ce n’est pas le plus adapté.

“Vite” était à deux doigts de me convenir, mais… il ne prend pas la base de code par défaut en passant par package.json, et du coup les “imports” de ressources typescript, ainsi que SCSS ou autres, ne sont pas “logiques” à mes yeux. Le souci est que “Vite” prend la base de code à la racine du projet, et que vous devez donc forcer le chemin au démarrage du serveur web. Et bon bha c’est pas aussi facile et rapide à utiliser au final.

Alors que dire ? qu’il ne faut pas les utiliser ? Certainement pas ! - ils sont au moins aussi bon que Parcel, mais ils sont adaptés à d’autres situations.

Pour être exact, j’utilise aussi “Vite” ou “SnowPack”, mais dans des conditions différentes. Par exemple j’adore les templates de “Vite” pour VueJS. Vous ne devez en aucun cas ignorer les autres outils.

Bref, Parcel n’est peut-être pas ce dont vous avez besoin et vous auriez tout à fait raison de passer par un autre outil zero-conf.

Parcel est, à mon sens, parfait pour le prototypage et le “build simplifié” - il est pratique pour sa qualité de HMR et sa gestion super intelligente des imports de ressources. Mais il a ses défaut (plus lent, plus lourd, difficile de sortir de l’obscurification, etc…) - je n’abandonne donc pas ses confrères (je n’utilise pas le mot “concurrent”, car ils ne le sont clairement pas), j’utilise juste le bon outil pour le bon besoin.


  1. allez-y, trollez sur les indentations ! ↩︎

  2. allez-y, trollez sur vim ! ↩︎

comments powered by Disqus