Passer au contenu

SWC

SWC (Speedy Web Compiler) est une plateforme extensible basée sur Rust qui peut être utilisée pour la compilation et le bundling. Utiliser SWC avec Nest CLI est un excellent moyen simple d’accélérer considérablement votre processus de développement.

Installation

Pour commencer, installez d’abord quelques paquets :

Fenêtre de terminal
$ npm i --save-dev @swc/cli @swc/core

Getting started

Une fois le processus d’installation terminé, vous pouvez utiliser le builder swc avec Nest CLI, comme suit :

Fenêtre de terminal
$ nest start -b swc
# OU nest start --builder swc

Au lieu de passer le flag -b, vous pouvez également définir simplement la propriété compilerOptions.builder à "swc" dans votre fichier nest-cli.json, comme ceci :

{
"compilerOptions": {
"builder": "swc"
}
}

Pour personnaliser le comportement du builder, vous pouvez passer un objet contenant deux attributs, type ("swc") et options, comme suit :

{
"compilerOptions": {
"builder": {
"type": "swc",
"options": {
"swcrcPath": "infrastructure/.swcrc"
}
}
}
}

Pour exécuter l’application en mode watch, utilisez la commande suivante :

Fenêtre de terminal
$ nest start -b swc -w
# OU nest start --builder swc --watch

Type checking

SWC ne réalise pas de vérification de type lui-même (contrairement au compilateur TypeScript par défaut), donc pour l’activer, vous devez utiliser le flag --type-check :

Fenêtre de terminal
$ nest start -b swc --type-check

Cette commande demandera à Nest CLI d’exécuter tsc en mode noEmit avec SWC, qui effectuera la vérification de type de manière asynchrone. Au lieu de passer le flag --type-check, vous pouvez également définir simplement la propriété compilerOptions.typeCheck à true dans votre fichier nest-cli.json, comme ceci :

{
"compilerOptions": {
"builder": "swc",
"typeCheck": true
}
}

CLI Plugins (SWC)

Le flag --type-check exécutera automatiquement les plugins NestJS CLI et produira un fichier de métadonnées sérialisé qui pourra être chargé par l’application au runtime.

SWC configuration

Le builder SWC est pré-configuré pour correspondre aux exigences des applications NestJS. Cependant, vous pouvez personnaliser la configuration en créant un fichier .swcrc dans le répertoire racine et en ajustant les options à votre guise.

{
"$schema": "https://json.schemastore.org/swcrc",
"sourceMaps": true,
"jsc": {
"parser": {
"syntax": "typescript",
"decorators": true,
"dynamicImport": true
},
"baseUrl": "./"
},
"minify": false
}

Monorepo

Si votre dépôt est un monorepo, alors au lieu d’utiliser le builder swc, vous devez configurer webpack pour utiliser swc-loader.

D’abord, installons le paquet requis :

Fenêtre de terminal
$ npm i --save-dev swc-loader

Une fois l’installation terminée, créez un fichier webpack.config.js dans le répertoire racine de votre application avec le contenu suivant :

const swcDefaultConfig = require('@nestjs/cli/lib/compiler/defaults/swc-defaults').swcDefaultsFactory();
module.exports = {
module: {
rules: [
{
test: /\.ts$/,
exclude: /node_modules/,
use: {
loader: 'swc-loader',
options: swcDefaultConfig,
},
},
],
},
};

Monorepo and CLI plugins

Si vous utilisez des plugins CLI, swc-loader ne les chargera pas automatiquement. Au lieu de cela, vous devez créer un fichier séparé qui les chargera manuellement. Pour ce faire, déclarez un fichier generate-metadata.ts près du fichier main.ts avec le contenu suivant :

import { PluginMetadataGenerator } from '@nestjs/cli/lib/compiler/plugins';
import { ReadonlyVisitor } from '@nestjs/swagger/dist/plugin';
const generator = new PluginMetadataGenerator();
generator.generate({
visitors: [new ReadonlyVisitor({ introspectComments: true, pathToSource: __dirname })],
outputDir: __dirname,
watch: true,
tsconfigPath: 'apps/<name>/tsconfig.app.json',
});

Le méthode generate() accepte les options suivantes :

OptionDescription
watchSi vous souhaitez surveiller le projet pour les changements.
tsconfigPathChemin vers le fichier tsconfig.json. Relatif au répertoire de travail actuel (process.cwd()).
outputDirChemin vers le répertoire où le fichier de métadonnées sera sauvegardé.
visitorsUn tableau de visiteurs qui seront utilisés pour générer des métadonnées.
filenameLe nom du fichier de métadonnées. Par défaut metadata.ts.
printDiagnosticsSi vous souhaitez imprimer les diagnostics dans la console. Par défaut true.

Enfin, vous pouvez exécuter le script generate-metadata dans une fenêtre de terminal séparée avec la commande suivante :

Fenêtre de terminal
$ npx ts-node src/generate-metadata.ts
# OU npx ts-node apps/{YOUR_APP}/src/generate-metadata.ts

Common pitfalls

Si vous utilisez TypeORM/MikroORM ou tout autre ORM dans votre application, vous pouvez rencontrer des problèmes d’importation circulaire. SWC ne gère pas bien les imports circulaires, donc vous devriez utiliser la solution de contournement suivante :

@Entity()
export class User {
@OneToOne(() => Profile, (profile) => profile.user)
profile: Relation<Profile>; // <--- voir le type "Relation<>" ici au lieu de simplement "Profile"
}

Cela empêche le type de la propriété d’être enregistré dans le code transpilé dans les métadonnées de la propriété, empêchant ainsi les problèmes de dépendance circulaire.

Si votre ORM ne fournit pas une solution de contournement similaire, vous pouvez définir vous-même le type wrapper :

/**
* Type wrapper utilisé pour contourner le problème de dépendance circulaire des modules ESM
* causé par la sauvegarde des métadonnées de réflexion du type de la propriété.
*/
export type WrapperType<T> = T; // WrapperType === Relation

Pour toutes les injections de dépendance circulaires dans votre projet, vous devrez également utiliser le type wrapper personnalisé décrit ci-dessus :

@Injectable()
export class UserService {
constructor(
@Inject(forwardRef(() => ProfileService))
private readonly profileService: WrapperType<ProfileService>,
) {}
}

Jest + SWC

Pour utiliser SWC avec Jest, vous devez installer les paquets suivants :

Fenêtre de terminal
$ npm i --save-dev jest @swc/core @swc/jest

Une fois l’installation terminée, mettez à jour le fichier package.json/.jest.config.js (selon votre configuration) avec le contenu suivant :

{
"jest": {
"transform": {
"^.+\\.(t|j)s?$": ["@swc/jest"]
}
}
}

De plus, vous devrez ajouter les propriétés transform suivantes à votre fichier .swcrc : legacyDecorator, decoratorMetadata :

{
"$schema": "https://json.schemastore.org/swcrc",
"sourceMaps": true,
"jsc": {
"parser": {
"syntax": "typescript",
"decorators": true,
"dynamicImport": true
},
"transform": {
"legacyDecorator": true,
"decoratorMetadata": true
},
"baseUrl": "./"
},
"minify": false
}

Si vous utilisez les plugins NestJS CLI dans votre projet, vous devrez exécuter PluginMetadataGenerator manuellement. Consultez cette section pour en savoir plus.

Vitest

Vitest est un exécuteur de tests rapide et léger, conçu pour travailler avec Vite. Il fournit une solution de test moderne, rapide et facile à utiliser qui peut être intégrée aux projets NestJS.

Installation

Pour commencer, installez d’abord les paquets requis :

Fenêtre de terminal
$ npm i --save-dev vitest unplugin-swc @swc/core @vitest/coverage-v8

Configuration

Créez un fichier vitest.config.ts dans le répertoire racine de votre application avec le contenu suivant :

import swc from 'unplugin-swc';
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
globals: true,
root: './',
},
plugins: [
// Ceci est requis pour construire les fichiers de test avec SWC
swc.vite({
// Définir explicitement le type de module pour éviter d'hériter de cette valeur d'un fichier de configuration `.swcrc`
module: { type: 'es6' },
}),
],
});

Ce fichier de configuration configure l’environnement Vitest, le répertoire racine et le plugin SWC. Vous devez également créer un fichier de configuration séparé pour les tests E2E, avec un champ include supplémentaire qui spécifie l’expression régulière du chemin de test :

import swc from 'unplugin-swc';
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
include: ['**/*.e2e-spec.ts'],
globals: true,
root: './',
},
plugins: [swc.vite()],
});

De plus, vous pouvez définir les options alias pour prendre en charge les chemins TypeScript dans vos tests :

import swc from 'unplugin-swc';
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
include: ['**/*.e2e-spec.ts'],
globals: true,
alias: {
'@src': './src',
'@test': './test',
},
root: './',
},
resolve: {
alias: {
'@src': './src',
'@test': './test',
},
},
plugins: [swc.vite()],
});

Mettre à jour les imports dans les tests E2E

Changez les imports de tout test E2E utilisant import * as request from 'supertest' vers import request from 'supertest'. Cela est nécessaire car Vitest, lorsqu’il est bundlé avec Vite, s’attend à un import par défaut pour supertest. Utiliser un import namespace peut provoquer des problèmes dans cette configuration spécifique.

Enfin, mettez à jour les scripts de test dans votre fichier package.json vers :

{
"scripts": {
"test": "vitest run",
"test:watch": "vitest",
"test:cov": "vitest run --coverage",
"test:debug": "vitest --inspect-brk --inspect --logHeapUsage --threads=false",
"test:e2e": "vitest run --config ./vitest.config.e2e.ts"
}
}

Ces scripts configurent Vitest pour exécuter des tests, surveiller les changements, générer des rapports de couverture de code et déboguer. Le script test:e2e est spécifiquement destiné à exécuter des tests E2E avec un fichier de configuration personnalisé.

Avec cette configuration, vous pouvez désormais profiter des avantages d’utilisation de Vitest dans votre projet NestJS, notamment une exécution de test plus rapide et une expérience de test plus moderne.