Pourquoi Déployer NestJS sur Vercel ?
Dans un monde où le développement moderne repose sur la rapidité et l'efficacité, le déploiement rapide de nos applications devient une nécessité incontournable. Les outils comme Vercel offrent des avantages importants pour les développeurs qui cherchent à déployer leurs applications NestJS avec une facilité et une performance optimales.
Un cas d'usage concret est que vous ayez un service de gestion de tâches en cours de développement. Vous souhaiteriez voir votre application en production pour tester sa fiabilité et sa scalabilité, sans avoir à passer par des étapes complexes de déploiement traditionnel. Vercel facilite ce processus, permettant une mise à jour instantanée et sécurisée de votre application NestJS.
Prerequis
- Connaissance approfondie de la technologie NestJS
- Compréhension des concepts de routes, controllers, services et modules en NestJS
- Familiarité avec les outils de gestion de paquets npm et yarn
- Un compte Vercel
- Un environnement local configuré (Node.js, npm)
- Connaissance de la ligne de commande
Concepts Fondamentaux
1. Projets NestJS
Un projet NestJS est une application Node.js qui utilise le framework NestJS. Il comprend généralement des controllers, des services et des modules pour structurer l'application.
// app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
@Module({
imports: [],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
2. Controllers
Les controllers gèrent les requêtes HTTP et renvoient les réponses.
// app.controller.ts
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get()
getHello(): string {
return this.appService.getHello();
}
}
3. Services
Les services contiennent la logique métier de l'application.
// app.service.ts
import { Injectable } from '@nestjs/common';
@Injectable()
export class AppService {
getHello(): string {
return 'Hello World!';
}
}
Mise en Pratique : Projet Fil Rouge
Nous allons créer un simple API de blog pour illustrer le déploiement sur Vercel. L'API devra permettre de créer, lire, mettre à jour et supprimer des articles.
Étape 1 : Initialiser le projet NestJS
Créer un nouveau projet NestJS :
nest new blog-api
cd blog-api
Étape 2 : Créer les entités et services
Créez une entité Article et un service associé.
// src/article/article.entity.ts
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
@Entity()
export class Article {
@PrimaryGeneratedColumn()
id: number;
@Column()
title: string;
@Column()
content: string;
}
typescript
// src/article/article.service.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Article } from './article.entity';
@Injectable()
export class ArticleService {
constructor(
@InjectRepository(Article)
private readonly articleRepository: Repository<Article>,
) {}
findAll(): Promise<Article[]> {
return this.articleRepository.find();
}
findOne(id: number): Promise<Article> {
return this.articleRepository.findOne(id);
}
async remove(id: number): Promise<void> {
await this.articleRepository.delete(id);
}
async create(article: Article): Promise<Article> {
return this.articleRepository.save(article);
}
}
Étape 3 : Créer les contrôleurs
Créez des contrôleurs pour gérer les requêtes HTTP.
// src/article/article.controller.ts
import { Controller, Get, Post, Body, Param, Delete } from '@nestjs/common';
import { ArticleService } from './article.service';
import { Article } from './article.entity';
@Controller('articles')
export class ArticleController {
constructor(private readonly articleService: ArticleService) {}
@Post()
async create(@Body() article: Article): Promise<Article> {
return this.articleService.create(article);
}
@Get()
async findAll(): Promise<Article[]> {
return this.articleService.findAll();
}
@Get(':id')
async findOne(@Param('id') id: number): Promise<Article> {
return this.articleService.findOne(id);
}
@Delete(':id')
async remove(@Param('id') id: number): Promise<void> {
await this.articleService.remove(id);
}
}
Étape 4 : Configurer le fichier app.module.ts
Incluez le module de l'article dans le module principal.
// src/app.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ArticleModule } from './article/article.module';
@Module({
imports: [
TypeOrmModule.forRoot({
type: 'sqlite',
database: 'db.sqlite',
entities: [__dirname + '/**/*.entity{.ts,.js}'],
synchronize: true,
}),
ArticleModule,
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
Étape 5 : Configurer le fichier article.module.ts
Définissez le module pour l'article.
// src/article/article.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ArticleController } from './article.controller';
import { ArticleService } from './article.service';
import { Article } from './article.entity';
@Module({
imports: [TypeOrmModule.forFeature([Article])],
controllers: [ArticleController],
providers: [ArticleService],
})
export class ArticleModule {}
Étape 6 : Créer un fichier vercel.json pour le déploiement
Créez un fichier vercel.json à la racine de votre projet.
{
"version": 2,
"frameworks": [
{
"type": "nextjs"
}
],
"builds": [
{
"src": "main.ts",
"use": "@vercel/node"
}
]
}
Étape 7 : Déploiement sur Vercel
Connectez votre compte Vercel et importez votre projet. Sélectionnez le déploiement manuel ou utilisez un dépôt Git pour le déclencher automatiquement.
Erreurs Fréquentes et Debugging
Erreur 1 : TypeError: Cannot read property 'find' of undefined
Le problème peut se produire si la table n'est pas correctement créée dans la base de données SQLite.
// src/app.module.ts
TypeOrmModule.forRoot({
type: 'sqlite',
database: 'db.sqlite',
entities: [__dirname + '/**/*.entity{.ts,.js}'],
synchronize: true, // Ajustez cette ligne si vous rencontrez des problèmes avec la synchronisation.
})
Erreur 2 : Cannot find module './app.module'
Le problème peut se produire si le chemin du fichier est incorrect.
npm run start:dev
Erreur 3 : Missing required peer dependency 'typescript@^4.0.0'
Ce message indique que vous n'avez pas installé la version requise de TypeScript.
npm install typescript@^4.0.0 --save-dev
Pour Aller Plus Loin
1. Intégration avec Docker
Utilisez Docker pour containeriser votre application NestJS.
## Dockerfile
FROM node:14
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["npm", "run", "start"]
2. Utilisation de Swagger pour la documentation API
Ajoutez Swagger pour générer automatiquement la documentation de votre API.
npm install @nestjs/swagger swagger-ui-express --save
Créez un fichier main.ts pour configurer Swagger.
// main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
const config = new DocumentBuilder()
.setTitle('Blog API')
.setDescription('API pour le blog')
.setVersion('1.0')
.addTag('articles')
.build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api', app, document);
await app.listen(3000);
}
bootstrap();
3. Optimisation des performances
Optimisez les performances de votre application en utilisant le cache et la mise en cache des données.
// src/app.module.ts
TypeOrmModule.forRoot({
type: 'sqlite',
database: 'db.sqlite',
entities: [__dirname + '/**/*.entity{.ts,.js}'],
synchronize: true,
caching: true, // Activer le cache pour les requêtes TypeORM.
})
Défi Pratique
Créez un service de scraping pour extraire des données d'une page web et les stocker dans votre base de données.
// src/scraping/scraping.service.ts
import { Injectable } from '@nestjs/common';
import axios from 'axios';
@Injectable()
export class ScrapingService {
async scrape(url: string): Promise<string> {
const response = await axios.get(url);
return response.data;
}
}
Ajoutez une route pour déclencher le scraping.
// src/scraping/scraping.controller.ts
import { Controller, Get, Param } from '@nestjs/common';
import { ScrapingService } from './scraping.service';
@Controller('scrape')
export class ScrapingController {
constructor(private readonly scrapingService: ScrapingService) {}
@Get(':url')
async scrape(@Param('url') url: string): Promise<string> {
return this.scrapingService.scrape(url);
}
}
Ajoutez le module et le service au fichier app.module.ts.
// src/app.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ArticleModule } from './article/article.module';
import { ScrapingModule } from './scraping/scraping.module';
@Module({
imports: [
TypeOrmModule.forRoot({
type: 'sqlite',
database: 'db.sqlite',
entities: [__dirname + '/**/*.entity{.ts,.js}'],
synchronize: true,
}),
ArticleModule,
ScrapingModule, // Ajoutez le module du scraping.
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
Ajoutez une nouvelle entité et un service pour stocker les données scrapées.
// src/scraped-data/scraped-data.entity.ts
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
@Entity()
export class ScrapedData {
@PrimaryGeneratedColumn()
id: number;
@Column('text')
data: string;
}
typescript
// src/scraped-data/scraped-data.service.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { ScrapedData } from './scraped-data.entity';
@Injectable()
export class ScrapedDataService {
constructor(
@InjectRepository(ScrapedData)
private readonly scrapedDataRepository: Repository<ScrapedData>,
) {}
async save(data: string): Promise<void> {
const newData = this.scrapedDataRepository.create({ data });
await this.scrapedDataRepository.save(newData);
}
}
typescript
// src/scraped-data/scraped-data.controller.ts
import { Controller, Get, Param } from '@nestjs/common';
import { ScrapingService } from '../scraping/scraping.service';
import { ScrapedDataService } from './scraped-data.service';
@Controller('scraped-data')
export class ScrapedDataController {
constructor(
private readonly scrapingService: ScrapingService,
private readonly scrapedDataService: ScrapedDataService,
) {}
@Get(':url')
async scrapeAndSave(@Param('url') url: string): Promise<void> {
const data = await this.scrapingService.scrape(url);
await this.scrapedDataService.save(data);
}
}
Ajoutez le module et le service au fichier app.module.ts.
// src/app.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ArticleModule } from './article/article.module';
import { ScrapingModule } from './scraping/scraping.module';
import { ScrapedDataModule } from './scraped-data/scraped-data.module';
@Module({
imports: [
TypeOrmModule.forRoot({
type: 'sqlite',
database: 'db.sqlite',
entities: [__dirname + '/**/*.entity{.ts,.js}'],
synchronize: true,
}),
ArticleModule,
ScrapingModule,
ScrapedDataModule, // Ajoutez le module du scraping des données.
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
Ce tutoriel a couvert les concepts de base pour déployer une application NestJS sur Vercel. Vous avez créé un projet complet et réalisé un déploiement efficace. N'oubliez pas d'explorer davantage les fonctionnalités de Vercel et de NestJS pour améliorer votre développement et votre production continue.