Pourquoi Deployer React sur AWS ?
Deployer une application React sur AWS offre plusieurs avantages :
- Echelle : AWS permet d'adapter l'échelle de votre application en fonction du trafic, ce qui est essentiel pour une application moderne.
- Fonctionnalités cloud : AWS propose des services tels que Amazon RDS (pour la base de données), CloudFront (pour le CDN) et IAM (pour la gestion des identités et des accès).
- Sécurité : AWS offre un ensemble complet d'outils de sécurité pour protéger vos applications contre les menaces.
- Opérations optimisées : AWS gère les mises à jour du système d'exploitation, la maintenance des serveurs et beaucoup plus encore.
Un cas concret est la création d'un portail interne pour une entreprise. Ce portail nécessite une grande échelle pour accueillir de nombreux utilisateurs et doit être sécurisé pour protéger les informations sensibles. Deployer ce portail sur AWS permet de tirer pleinement parti des avantages cloud tout en maintenant une sécurité élevée.
Prerequis
Connaissances :
- JavaScript (ES6+)
- React
- Node.js et npm
- Terminal et commandes bash
- Concepts de base d'infrastructure as code (IaC)
Outils à installer :
- Node.js v14.x ou plus récent (https://nodejs.org/)
- npm v6.x ou plus récent (vient avec Node.js)
- AWS CLI v2.x ou plus récent (https://aws.amazon.com/cli/)
- Docker (facultatif, mais recommandé pour le déploiement)
Concepts fondamentaux
1. Création d'une application React
Créez un nouveau projet React en utilisant Create React App :
npx create-react-app task-manager
cd task-manager
Structure de base du projet :
public/: contient les fichiers statiques de l'application.src/: contient le code source de l'application.
2. Configuration du serveur back-end
Pour gérer les données, nous allons utiliser Node.js avec Express :
npm install express cors body-parser
Créez un fichier server.js dans la racine du projet :
// server.js
const express = require('express');
const cors = require('cors');
const bodyParser = require('body-parser');
const app = express();
const port = process.env.PORT || 5000;
app.use(cors());
app.use(bodyParser.json());
let tasks = [
{ id: 1, title: 'Task 1', completed: false },
{ id: 2, title: 'Task 2', completed: true }
];
// Récupérer toutes les tâches
app.get('/tasks', (req, res) => {
res.json(tasks);
});
// Ajouter une nouvelle tâche
app.post('/tasks', (req, res) => {
const newTask = { id: tasks.length + 1, ...req.body };
tasks.push(newTask);
res.status(201).json(newTask);
});
// Mettre à jour une tâche
app.put('/tasks/:id', (req, res) => {
const taskId = parseInt(req.params.id);
const updatedTask = { id: taskId, ...req.body };
tasks = tasks.map(task => task.id === taskId ? updatedTask : task);
res.json(updatedTask);
});
// Supprimer une tâche
app.delete('/tasks/:id', (req, res) => {
const taskId = parseInt(req.params.id);
tasks = tasks.filter(task => task.id !== taskId);
res.status(204).send();
});
app.listen(port, () => {
console.log(`Server running on port ${port}`);
});
3. Intégration front-end et back-end
Modifiez le composant App.js pour utiliser le back-end :
// src/App.js
import React, { useState, useEffect } from 'react';
function App() {
const [tasks, setTasks] = useState([]);
const [newTask, setNewTask] = useState({ title: '', completed: false });
useEffect(() => {
fetch('/tasks')
.then(response => response.json())
.then(data => setTasks(data));
}, []);
const handleAddTask = () => {
fetch('/tasks', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(newTask)
})
.then(response => response.json())
.then(task => setTasks([...tasks, task]));
setNewTask({ title: '', completed: false });
};
const handleToggleComplete = (taskId) => {
fetch(`/tasks/${taskId}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ completed: !tasks.find(task => task.id === taskId).completed })
})
.then(response => response.json())
.then(updatedTask => setTasks(tasks.map(task => task.id === taskId ? updatedTask : task)));
};
const handleDelete = (taskId) => {
fetch(`/tasks/${taskId}`, { method: 'DELETE' })
.then(() => setTasks(tasks.filter(task => task.id !== taskId)));
};
return (
<div className="App">
<h1>Task Manager</h1>
<form onSubmit={(e) => e.preventDefault()}>
<input
type="text"
value={newTask.title}
onChange={(e) => setNewTask({ ...newTask, title: e.target.value })}
/>
<button type="submit" onClick={handleAddTask}>Add Task</button>
</form>
<ul>
{tasks.map(task => (
<li key={task.id}>
<input
type="checkbox"
checked={task.completed}
onChange={() => handleToggleComplete(task.id)}
/>
{task.title}
<button onClick={() => handleDelete(task.id)}>Delete</button>
</li>
))}
</ul>
</div>
);
}
export default App;
Mise en pratique : projet fil rouge
1. Création d'un fichier Dockerfile pour le back-end
## Dockerfile
FROM node:14-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 5000
CMD ["node", "server.js"]
2. Configuration de package.json pour le back-end
{
"name": "task-manager",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"start": "node server.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"body-parser": "^1.19.0",
"cors": "^2.8.5",
"express": "^4.17.1"
}
}
3. Création d'un fichier docker-compose.yml pour les services
## docker-compose.yml
version: '3'
services:
app:
build: .
ports:
- "5000:5000"
volumes:
- .:/app
4. Déploiement sur AWS Elastic Beanstalk
Créer un environnement Elastic Beanstalk :
aws elasticbeanstalk create-environment --environment-name task-manager-env --application-name task-manager-app --solution-stack-name "64bit Amazon Linux 2 v3.0.7 running Node.js 14" --option-settings Namespace=aws:elasticbeanstalk:container:nodejs,OptionName=NodeVersion,Value=14Déployer le code :
aws elasticbeanstalk update-environment --environment-name task-manager-env --version-label $(git describe --tags)
5. Configuration du CDN avec CloudFront
Créer un distribution CloudFront :
- Sélectionnez l'ARN de votre environnement Elastic Beanstalk comme origin.
- Configurez les paramètres pour permettre le trafic HTTPS.
Mettre à jour le domaine DNS :
- Pointez votre domaine personnalisé vers la distribution CloudFront.
Erreurs fréquentes et debugging
1. Error: Cannot find module 'express'
Cause : Le module express n'est pas installé.
Correction :
npm install express
2. TypeError: Cannot read property 'map' of undefined
Cause : Les données récupérées du back-end sont undefined.
Correction :
Ajoutez une vérification avant de mapper les tâches :
{ tasks ? tasks.map(...) : [] }
3. Access to fetch at 'http://localhost:5000/tasks' from origin 'http://localhost:3000' has been blocked by CORS policy
Cause : Le serveur n'autorise pas les requêtes cross-origin.
Correction :
Ajoutez le middleware cors dans votre application Express :
const cors = require('cors');
app.use(cors());
Pour aller plus loin
Utilisation de AWS Amplify : Simplifie le développement cloud avec des outils faciles à utiliser.
Configuration du déploiement continu (CI/CD) : Automatisez les tests et le déploiement de votre application.
Intégration avec AWS Lambda : Exécutez des fonctions serverless pour gérer les requêtes back-end.
Défi pratique
Développez une API de blog simple utilisant Express et déployez-la sur AWS Elastic Beanstalk. Incluez des routes pour créer, lire, mettre à jour et supprimer les articles du blog.