Bundling de modules typescript avec webpack

Pourquoi transpiler du typescript ?

Typescript n’est pas interprétable de base par nodejs. Nou devons utilisez le module typscript afin de transpiler ou d’exécuter le code avec la commande tsc(qui est transpilé en amont). C’est pourquoi il doit être transpilé en javascript avant tout exécution sur un serveur.

Que ce soit pour des raisons de rapide, de prise de tête, ou peu importe la raison d’ailleurs, Nous ne voulons pas forcément installer tout un framework qui peut parfois être une machine à gaz par rapport à ce que nous voulons faire ?

Ici nous allons voir simplement, comment, à l’aide de webpack, transpiler des modules typscripts afin de n’en sortir qu’un seul fichier javascript pret à être envoyé sur un serveur et être exécuté.

Architecture et installation des dépendances

Dans un premier temps, nous allons avoir une architecture de dossier qui ressemblera à ce qui suit:

|-- src
|   |-- index.ts
|-- build
|   |-- ...
|-- dist
|   |-- ...
|-- package.json
|-- tsconfig.json
|-- webpack.config.js
  • src contient tout notre code typescript
  • distcontiendra noter code transpilé en javascript, avec la même architecture de dossier que dans src
  • dist contiendra notre bundle javascript généré à partir du cide javascript dans dist
  • tsconfig.json contiendra notre configuration typescript (fichier source, dossier de build, target de build …)
  • webpack.config.js contiendra notre configuration webpack

Pour que tout cela fonctionne correctement, il faudra installer les dépendances suivantes:

  • typescript
  • webpack
  • webpack-cli
  • webpack-node-externals
  • concurrently

Voici les commandes d’installations pour vous simplifier la vie:

$ npm install --save typescript
$ npm install --save-dev webpack webpack-cli webpack-node-externals concurrently

Configuration des dépendances

tsconfig.json

{
    "compilerOptions": {
        "module": "commonjs",
        "moduleResolution": "node",
        "esModuleInterop": true,
        "outDir": "build",
        "target": "es2016"
    },
    "include": [
        "src"
    ]
}
  • module et le type de module utilisé pour la transpilation (ici commonjs)
  • moduleResolution définit le type de résolution de module. web ou node. (ici node)
  • esModuleInterop définit la stratégie d’import global. Il transpile les import * from "..." de typescript
  • outDir définit le dossier de sortie de la transpilation (ici build comme définit plus haut)
  • target définit le strandart javascript à utiliser (ici ES2016)
  • include: [src] dit au moteur de transpilation de ne résoudre les modules qui ne sont que dans src

webpack.config.js

const path = require('path');
const nodeExternals = require('webpack-node-externals');

module.exports = {
    target: 'node',
    mode: "development",
    externals: [nodeExternals()],
    entry: './build/index.js', 
    output: {
        path: path.join(__dirname, 'dist'),
        filename: 'bundle.js',
    }
}
  • target définit le type de résolution de module (comme pour typescript)
  • mode peut être development ou production`. En modeprouction``, il y a des optimisations supplémentaires
  • externals: [nodeExternals()] exclura les modules node_modules du fichier bundle. Il n’est pas nécessaire des les inclure dedans pour le pas allourdir le fichier. Il est plutôt préférable de ne pas les inclure et d’exécuter un npm install --production sur le serveur.
  • entry définit le fichier à bundler. webpack va résoudre tout les modules et sous modules inclus dans ce fichier.
  • output definit le dossier de sortie du bundle (ici dist). Et notre fichier de sortie se nommera bundle.js

Commandes supplémentaire

Vous pouvez rajouter ces scripts à votre package.json afin de watch la transpilation typescript et le bundling du fichier javascript final.

...
"scripts": {
    "watch-compile:server": "tsc --watch",
    "watch-bundle:server": "webpack --watch",
    "concurrent-watch": "concurrently npm:watch-*"
},
...

Il vous suffira d’exécuter npm run concurrent-watch pour démarrer la transpilation.

Vous pourvez aussi éventuellement rajouter la dépendance nodemon afin d’écouter les modifications sur bundle.js et de réexécuter automatiquement votre node. Mais ça je pense que vous le savez déjà.

Voici un lien vers le repos github pour que vous puissiez plus facilement reprendre le code au besoin.