Notes de cours, exercices et projets réalisés dans le cadre de la formation Développeur Web et Web Mobile.
| Lien utile |
|---|
| Cours |
| Exercices |
| Recap des présentations |
- Saison 1
- HTML / CSS / JavaScript (La trinité du web 💪)
- Saison 2
- React / Props / State / Hooks
- Saison 3
- Méthode agile / Workflows git / Context
- Saison 4
- API / Fetch / Express / MySQL / Merise
- Saison 5
- Middleware / Authentification / Tests / JWT / Argon2
- Saison Bonus
- Plein de livecoding ❤️
Woaw, passer 5 mois avec vous a été une expérience incroyable, j'ai appris énormément de choses et j'ai adoré partager mes connaissances avec vous ! N'oubliez pas que vous êtes des développeurs incroyables et que vous avez tout ce qu'il faut pour réussir dans ce domaine. Continuez à apprendre, à coder et à vous amuser, et surtout, n'oubliez pas de prendre soin de vous et de vous reposer (prenez des pauses !) Je vous souhaite à tous une belle continuation dans vos projets et j'espère vous revoir bientôt avec d'excellentes nouvelles ! 🚀
📦 Récap du jour
Nous allons voir comment créer des routes protégées avec React.
Pour protéger une route, nous allons utiliser un HOC (Higher Order Component).
// ./src/components/ProtectedRoute.tsx
import { Navigate, Outlet } from "react-router-dom";
import { useAuth } from "../context/AuthContext";
function ProtectedRoute() {
const { isAuthenticated } = useAuth();
return isAuthenticated ? <Outlet /> : <Navigate to={redirectTo} />;
}
export default ProtectedRoute;Et voilà !
Maintenant, pour protéger une route, il suffit de l'entourer avec notre ProtectedRoute.
// ./src/main.tsx
const router = createBrowserRouter([
{
element: <Layout />,
children: [
{
path: "/",
element: <App />,
},
{
path: "/login",
element: <Login />,
},
{
path: "/signin",
element: <SignIn />,
},
// Routes protégées pour les utilisateurs connectés
{
element: <ProtectedRoute />,
children: [
{
path: "/profile",
element: <Profile />, // Page profil
},
{
path: "/cart",
element: <Cart />, // Page panier
},
],
},
],
},
]);🔗 Liens utiles
📦 Récap du jour
Nous allons faire un petit livecoding pour le fameux forgot password.
Nous allons mettre en place plein de petites choses, alors, oui, ça peut être un peu difficile, mais en vrai c'est cool !
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Création d'un table pour stocker les tokens
CREATE TABLE password_resets (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
token VARCHAR(64) NOT NULL,
expires_at DATETIME NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);/**
* Ici, je met tout sur une seule page sans prendre le temps de ranger dans des dossiers.
* Il faudra bien sûr ranger tout ça dans des fichiers séparés en l'adaptant à votre architecture.
*/
import express from "express";
import crypto from "node:crypto";
import nodemailer from "nodemailer";
import pool from "../db.js";
const router = express.Router();
// 📌 1️⃣ Route pour demander la réinitialisation du mot de passe
router.post("/forgot-password", async (req, res) => {
const { email } = req.body;
try {
const [users] = await pool.query(
"SELECT id FROM users WHERE email = ?",
[email]
);
if (users.length === 0) {
return res.status(400).json({ message: "Email non trouvé" });
}
const userId = users[0].id;
// Génère un token sécurisé
const resetToken = crypto.randomBytes(32).toString("hex");
const hashedToken = crypto
.createHash("sha256")
.update(resetToken)
.digest("hex");
const expiresAt = new Date(Date.now() + 15 * 60 * 1000); // 15 min
// Supprimer les anciens tokens
await pool.query("DELETE FROM password_resets WHERE user_id = ?", [
userId,
]);
// Sauvegarde le token en base de données
await pool.query(
"INSERT INTO password_resets (user_id, token, expires_at) VALUES (?, ?, ?)",
[userId, hashedToken, expiresAt]
);
// Envoi de l'email avec le lien
const resetLink = `http://localhost:3000/reset-password?token=${resetToken}&email=${email}`;
await transporter.sendMail({
to: email,
subject: "Réinitialisation de votre mot de passe",
text: `Cliquez sur ce lien pour réinitialiser votre mot de passe : ${resetLink}`,
});
res.json({ message: "Email envoyé ! Vérifiez votre boîte mail." });
} catch (error) {
console.error(error);
res.status(500).json({ message: "Erreur serveur" });
}
});
// 📌 2️⃣ Route pour réinitialiser le mot de passe
router.post("/reset-password", async (req, res) => {
const { token, email, newPassword } = req.body;
try {
const [users] = await pool.query(
"SELECT id FROM users WHERE email = ?",
[email]
);
if (users.length === 0) {
return res.status(400).json({ message: "Email invalide" });
}
const userId = users[0].id;
const hashedToken = crypto
.createHash("sha256")
.update(token)
.digest("hex");
// Vérifier le token en base
const [tokens] = await pool.query(
"SELECT * FROM password_resets WHERE user_id = ? AND token = ? AND expires_at > NOW()",
[userId, hashedToken]
);
if (tokens.length === 0) {
return res
.status(400)
.json({ message: "Token invalide ou expiré" });
}
// Hacher le nouveau mot de passe avec Argon2
const hashedPassword = await argon2.hash(newPassword);
// Mettre à jour le mot de passe
await pool.query("UPDATE users SET password = ? WHERE id = ?", [
hashedPassword,
userId,
]);
// Supprimer le token après utilisation
await pool.query("DELETE FROM password_resets WHERE user_id = ?", [
userId,
]);
res.json({ message: "Mot de passe mis à jour avec succès" });
} catch (error) {
console.error(error);
res.status(500).json({ message: "Erreur serveur" });
}
});
export default router;// ./src/pages/ForgotPassword.tsx
import { useState } from "react";
import axios from "axios";
const ForgotPassword = () => {
const [email, setEmail] = useState("");
const handleSubmit = async (e) => {
e.preventDefault();
await axios.post("http://localhost:3310/api/forgot-password", {
email,
});
alert("Si l'email existe, un lien a été envoyé.");
};
return (
<form onSubmit={handleSubmit}>
<input
type="email"
placeholder="Email"
onChange={(e) => setEmail(e.target.value)}
required
/>
<button type="submit">Envoyer</button>
</form>
);
};
export default ForgotPassword;Une fois que le formulaire remplie, vous arrivez sur la page reset-password grâce au lien envoyé par email.
// ./src/pages/ResetPassword.tsx
import { useState } from "react";
import { useSearchParams } from "react-router-dom";
import axios from "axios";
const ResetPassword = () => {
const [searchParams] = useSearchParams();
const email = searchParams.get("email");
const token = searchParams.get("token");
const [password, setPassword] = useState("");
const handleSubmit = async (e) => {
e.preventDefault();
await axios.post("http://localhost:3310/api/reset-password", {
email,
token,
newPassword: password,
});
alert("Mot de passe réinitialisé !");
};
return (
<form onSubmit={handleSubmit}>
<input
type="password"
placeholder="Nouveau mot de passe"
onChange={(e) => setPassword(e.target.value)}
required
/>
<button type="submit">Changer</button>
</form>
);
};
export default ResetPassword;Et voilà ! Vous avez un système de réinitialisation de mot de passe.
🔗 Liens utiles
📦 Récap du jour
Nous allons voir comment fonctionne l'envoi de mail avec Node.js.
npm install nodemailer// ./src/helpers/transporter.ts
import nodemailer from "nodemailer";
const transporter = nodemailer.createTransport({
host: "smtp.ethereal.email",
port: 587,
auth: {
user: process.env.MAIL_USER,
pass: process.env.MAIL_PASS,
},
});
export { transporter };// ./src/helpers/sendMail.ts
import { transporter } from "./transporter";
const sendMail = async (to: string, subject: string, text: string) => {
const info = await transporter.sendMail({
from: "noreply@gmail.com",
to,
subject,
text,
});
console.log("Preview URL: %s", nodemailer.getTestMessageUrl(info));
};
export { sendMail };Je vous invite à voir le repository pour voir aussi comment envoyer un template HTML avec EJS & Nodemailer.
🔗 Liens utiles
📦 Récap du jour
Des petits tips en vetu en voilà !
Et oui, nous utilisons axios pour faire des requêtes HTTP, c'est très bien, mais marquer tout le temps
const response = await axios.get("http://localhost:3310");
const response = await axios.post("http://localhost:3310", data);
const restponse = await axios.put("http://localhost:3310", data);
// etc...C'est un peu répétitif, non ?
Surtout que si je met en ligne mon site, je vais devoir changer toutes les URL. plusieurs fois. 😱
Et bien, il existe une solution, une solution simple, une solution élégante, une solution qui va vous changer la vie !
// ./src/helpers/api.ts
import axios from "axios";
const api = axios.create({
baseURL: import.meta.env.VITE_API_URL ?? "http://localhost:3310",
});
export { api };Grâce à axios.create, je crée une instance d'axios avec une URL de base.
Et maintenant, je peux faire des requêtes HTTP de cette manière :
// ./src/components/MyComponent.tsx
import { api } from "../helpers/api";
const MyComponent = () => {
const fetchData = async () => {
const response = await api.get("/users");
console.log(response.data);
};
return (
<div>
<button onClick={fetchData}>Fetch data</button>
</div>
);
};
export default MyComponent;Je n'importe plus axios, et je n'ai plus besoin de mettre l'URL de base à chaque fois.
Nous avons aussi, pour allez plus loin, la possibilité de créer des interceptors, n'hésitez pas à regarder la documentation.
Nous avons vu comment créer un AuthContext pour gérer l'authentification.
// ./src/context/AuthContext.tsx
import { createContext, useContext, useState } from "react";
type AuthContextType = {
user: User | null;
handleLogin: (user: User) => void;
handleLogout: () => void;
};
const AuthContext = createContext<AuthContextType | null>(null);
type ChildrenType = {
children: React.ReactNode;
};
type User = {
id: number;
email: string;
avatar: string;
};
export function AuthProvider({ children }: ChildrenType) {
const [user, setUser] = useState<User | null>(null);
// handleLogin permet d'enregistrer l'utilisateur connecté dans le context
const handleLogin = (user: User) => {
setUser(user);
};
// handleLogout permet de déconnecter l'utilisateur coté client, mais il ne faut pas oublier de le déconnecter coté serveur avec une requête HTTP par exemple.
const handleLogout = () => {
setUser(null);
};
return (
<AuthContext.Provider
value={{
user,
handleLogin,
handleLogout,
}}
>
{children}
</AuthContext.Provider>
);
}
// useAuth est un Custom Hook qui permet de récupérer le context
export const useAuth = () => {
const value = useContext(AuthContext);
if (value == null) {
throw new Error("useAuth has to be used within <AuthProvider />");
}
return value;
};🔗 Liens utiles
📦 Récap du jour
Installation et utilisation d'un JWT (JSON Web Token) pour l'authentification.
Un JSON Web Token (JWT) est un standard ouvert (RFC 7519) qui définit une manière compacte et autonome de transmettre des informations entre les parties en tant qu'objet JSON.
Un JWT se compose de trois parties :
- Header
- Payload
- Signature
npm install jsonwebtoken// ./src/middleware/jwtMiddleware.ts
import { Request, Response, NextFunction } from "express";
import jwt from "jsonwebtoken";
const createToken = (user: User) => {
return jwt.sign({ user }, process.env.JWT_SECRET, {
expiresIn: "1h",
});
};
const verifyToken = (req: Request, res: Response, next: NextFunction) => {
const token = req.cookies.token;
if (!token) {
res.status(401).json({ message: "Unauthorized" });
return;
}
try {
const user = jwt.verify(token, process.env.JWT_SECRET);
req.user = user;
next();
} catch (error) {
res.status(401).json({ message: "Unauthorized" });
}
};
export { createToken, verifyToken };Et maintenant, nous allons l'utiliser dans notre server.
// ./src/actions/auth.ts
import { Request, Response } from "express";
import { authRepository } from "../repositories/auth";
import { createToken } from "../services/jwt";
const login = async (req: Request, res: Response) => {
const { email, password } = req.body;
const user = await authRepository.findOne({ email, password });
if (!user) {
res.status(401).json({ message: "Invalid credentials" });
return;
}
// Ici, nous créons un token JWT
const token = createToken(user);
// Et nous le passons dans un cookie (ne pas oublier d'installer cookie-parser)
res.cookie("token", token, { httpOnly: true }).json({
message: "Logged in",
});
};
export { login };Et avec le verifyToken nous pouvons avoir des routes sécurisées.
Utilisation dans une route
// ./src/routes/users.ts
import { Router } from "express";
import { verifyToken } from "../middlewares/jwtMiddleware";
const router = Router();
router.get("/users", verifyToken, (req, res) => {
res.json({ message: "Users" });
});
export { router };🔗 Liens utiles
📦 Récap du jour
Nous continuons avec les livecoding sur des cas précis, ici, nous allons parler de l'upload de fichier.
Nous allons voir comment uploader un fichier sur notre serveur.
Voilà un exemple de code pour uploader un fichier avec Express.
// ./src/routes/upload.ts
import { Router } from "express";
const router = Router();
router.post("/upload", (req, res) => {
res.json({ message: "File uploaded" });
});
export { router };Nous allons créer un middleware pour gérer l'upload de fichier.
Tout d'abord, nous allons installer multer.
npm install multerEnsuite, nous allons créer un fichier uploadMiddleware.ts dans notre dossier middlewares.
// ./src/middlewares/uploadMiddleware.ts
import { Request, Response, NextFunction } from "express";
import multer from "multer";
// configuration de multer
const storage = multer.diskStorage({
// La destination du fichier, ici, dans un dossier uploads
destination: function (req, file, cb) {
cb(null, "uploads/");
},
// Le nom du fichier, ici, on garde le nom original, mais on peut le renommer
/**
* exemple :
* filename: (req, file, cb) => {
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1e9);
req.body.filename = uniqueSuffix + path.extname(file.originalname);
cb(null, uniqueSuffix + path.extname(file.originalname));
}
*
* */
filename: function (req, file, cb) {
req.body.filename = file.originalname;
cb(null, file.originalname);
},
});
const upload = multer({ storage: storage });
const uploadMiddleware = (req: Request, res: Response, next: NextFunction) => {
if (!req.file) {
res.status(400).json({ message: "No file uploaded" });
return;
}
next();
};
export { uploadMiddleware, upload };Et pour finir, nous allons ajouter nos middlewares sur notre route /upload.
// ./src/routes/upload.ts
import { Router } from "express";
import { uploadMiddleware, upload } from "../middlewares/uploadMiddleware";
const router = Router();
router.post("/upload", upload.single("file"), uploadMiddleware, (req, res) => {
res.json({ message: "File uploaded" });
});
export { router };Nous devons envoyer notre fichier depuis react maintenant.
// ./src/components/Upload.tsx
import { useState } from "react";
import axios from "axios";
const Upload = () => {
const [file, setFile] = useState<File | null>(null);
const handleChange = (e) => {
setFile(e.target.files[0]);
};
const handleSubmit = async () => {
// Ici, nous allons créer un objet FormData
// FormData est obligatoire pour envoyer un fichier et/ou des données textuelles
const formData = new FormData();
formData.append("file", file);
/**
* Axios gere automatiquement le header Content-Type: multipart/form-data
* Mais dans le doute, on peut l'ajouter aussi :)
*
* Exemple :
*
* const response = await axios.post(
"http://localhost:3310/upload",
formData,
{
headers: {
"Content-Type": "multipart/form-data",
},
}
);
*
*
* */
const response = await axios.post(
"http://localhost:3310/upload",
formData
);
console.log(response.data);
};
return (
<div>
<input type="file" onChange={handleChange} />
<button onClick={handleSubmit}>Upload</button>
</div>
);
};
export default Upload;🔗 Liens utiles
📦 Récap du jour
On commence les livecoding sur des cas précis, ici, nous allons comprendre comment utiliser les middlewares pour sécuriser nos routes.
Nous allons faire des routes pour s'inscrire et se connecter.
Nous n'allons pas faire les actions, c'est juste là à titre d'exemple.
// ./src/routes/auth.ts
import { Router } from "express";
import { authAction } from "../actions/auth";
const router = Router();
router.post("/register", authAction.register);
router.post("/login", authAction.login);Nous allons ajouter sur nos routes ci-dessus, nos middlewares vont pouvoir hasher le mot de passe avant de l'envoyer en base de données & vérifier si l'utilisateur existe déjà.
Il ne faut pas oublier d'installer argon2.
npm install argon2// ./src/middlewares/authMiddleware.ts
import { Request, Response, NextFunction } from "express";
import { authRepository } from "../repositories/auth";
// import de argon2 pour hasher le mot de passe
import * as argon2 from "argon2";
// function pour hasher le mot de passe
const hashPassword = async (password: string): Promise<string> => {
return argon2.hash(password);
};
// function pour comparer le mot de passe
const comparePassword = async (
password: string,
hash: string
): Promise<boolean> => {
return argon2.verify(hash, password);
};
// middleware pour vérifier si l'utilisateur existe déjà
const authMiddleware = async (
req: Request,
res: Response,
next: NextFunction
) => {
const { email, password } = req.body;
try {
const user = await authRepository.findOne({ email });
if (!user) {
res.status(401).json({ message: "User not found" });
return;
}
const isPasswordValid = await comparePassword(password, user.password);
if (!isPasswordValid) {
res.status(401).json({ message: "Invalid password" });
return;
}
req.user = user;
next();
} catch (error) {
console.error(error);
res.status(500).json({ message: "Internal server error" });
}
};
// middleware pour hasher le mot de passe
const hashPasswordMiddleware = async (
req: Request,
res: Response,
next: NextFunction
) => {
const { password } = req.body;
try {
const hashedPassword = await hashPassword(password);
req.body.password = hashedPassword;
next();
} catch (error) {
console.error(error);
res.status(500).json({ message: "Internal server error" });
}
};
export { authMiddleware, hashPasswordMiddleware };Et maintenant, nous allons ajouter nos middlewares sur nos routes login & register.
// ./src/routes/auth.ts
import { Router } from "express";
const router = Router();
import { authAction } from "../actions/auth";
import {
authMiddleware,
hashPasswordMiddleware,
} from "../middlewares/authMiddleware";
router.post("/register", hashPasswordMiddleware, authAction.register);
router.post("/login", authMiddleware, authAction.login);🔗 Liens utiles
📦 Récap du jour
Nous allons parler des tests aujourd'hui.
Il existe plusieurs types de tests :
- Test unitaire : permet de tester une fonction ou un module de manière isolée.
- Test d'intégration : permet de tester l'interaction entre plusieurs modules.
- Test end-to-end : permet de tester l'application dans son environnement de production.
Il existe plusieurs librairies pour faire des tests en JavaScript :
- Jest
- Mocha
- Chai
- Jasmine
- ...
Nous allons voir comment faire des tests avec Jest.
Les tests unitaires permettent de tester une fonction ou un module de manière isolée.
// ./src/add.ts
export const add = (a: number, b: number): number => a + b;// ./src/add.test.ts
import { add } from "./add";
test("add", () => {
expect(add(1, 2)).toBe(3);
});Les tests d'intégration permettent de tester l'interaction entre plusieurs modules.
// ./src/add.ts
export const add = (a: number, b: number): number => a + b;// ./src/subtract.ts
export const subtract = (a: number, b: number): number => a - b;// ./src/add.test.ts
import { add } from "./add";
import { subtract } from "./subtract";
test("add and subtract", () => {
expect(subtract(add(1, 2), 1)).toBe(2);
});Les tests end-to-end permettent de tester l'application dans son environnement de production. Il y a plusieurs outils pour faire des tests end-to-end :
- Cypress
- Puppeteer
- Playwright
- ...
🔗 Liens utiles
- Monorepo [FR] - Tests
- Jest · 🃏 Delightful JavaScript Testing
- Using Matchers · Jest
- Antho-Instructor/testUnitaireJS
📦 Récap du jour
Nous arrivons sur le dernier jour de la semaine avec l'apprentissage des middlewares.
Les middlewares sont des fonctions qui vont s'exécuter entre la requête et la réponse.
// ./index.js
const middleware = (req, res, next) => {
console.log("Je suis un middleware");
next();
};
app.get("/", middleware, (req, res) => {
res.send("Hello World !");
});On reconnaît un middleware par le fait qu'il possède un 3ème paramètre next.
Ce next permet de passer à la fonction suivante.
// ./index.js
const middleware = (req, res, next) => {
console.log("Je suis un middleware");
next();
};
const middleware2 = (req, res, next) => {
console.log("Je suis un middleware 2");
next();
};
app.get("/", middleware, middleware2, (req, res) => {
res.send("Hello World !");
});Ici, les exemples sont simples, mais les middlewares sont très utiles pour vérifier des informations, par exemple, si un utilisateur est connecté ou non.
// ./index.js
const isLogged = (req, res, next) => {
if (req.session.user) {
next();
} else {
res.sendStatus(401);
}
};Ici, nous avons un middleware qui vérifie si l'utilisateur est connecté ou non.
🔗 Liens utiles
📦 Récap du jour
SQL AVANCÉ !! 😱
- AND / OR
SELECT * FROM users
WHERE name = 'John' AND age = 25;
-- WHERE name = 'John' OR age = 25;- LIKE
- Attention, inssensible à la casse
- "%" : n'importe quel caractère
- "a%" : commence par a
- "%a" : fini par a
- "%a%" : contient a
SELECT * FROM users
WHERE name LIKE 'J%';- BETWEEN
SELECT * FROM users
WHERE age BETWEEN 18 AND 25;- IS NULL / IS NOT NULL
SELECT * FROM users
WHERE age IS NULL;SELECT * FROM users
WHERE age IS NOT NULL;Distinct permet de récupérer des valeurs uniques.
SELECT DISTINCT(name) FROM users;- LENGTH
SELECT LENGTH(name) FROM users;- CONCAT
SELECT CONCAT(name, ' ', lastname) FROM users;- NOW
SELECT NOW() FROM users;- DATE_FORMAT
SELECT DATE_FORMAT(NOW(), '%d/%m/%Y') FROM users;- COUNT
SELECT COUNT(*) FROM users;- MAX / MIN
SELECT MAX(age) FROM users;SELECT MIN(age) FROM users;- AVG
SELECT AVG(age) FROM users;SELECT name, COUNT(*) FROM users
GROUP BY name;Having est un WHERE pour les agrégations. (ici, COUNT)
SELECT name, COUNT(*) FROM users
GROUP BY name
HAVING COUNT(*) > 1;il y a 3 types de jointures très utilisées :
- (INNER) JOIN
ici, inner est entre parenthèse car c'est le type de jointure par défaut.
SELECT * FROM users
INNER JOIN posts ON users.id = posts.user_id;- LEFT JOIN
SELECT * FROM users
LEFT JOIN posts ON users.id = posts.user_id;- RIGHT JOIN
SELECT * FROM users
RIGHT JOIN posts ON users.id = posts.user_id;🔗 Liens utiles
📦 Récap du jour
Nous avons ce matin les bases de données avec le monorepo js.
- DBAL (Database Abstraction Layer) : permet de communiquer avec la base de données.
- ORM (Object-Relational Mapping) : permet de manipuler les données de la base de données comme des objets.
Voilà notre architecture, un monorepo avec un client React et un serveur Express avec Node.js et une base de données MySQL.
Dans le détail:
Si on zoom sur le serveur, on peut voir que nous avons plusieurs fichiers :
🔗 Liens utiles
📦 Récap du jour
Ce matin, nous avons vu la POO (Programmation Orientée Objet).
Nous avons vu plein de chose :
- Les classes (en PascalCase)
class MyClass {}
- Les méthodes (en camelCase)
sayHello() {}
- Les propriétés
- Publique:
this.name = "John" - Privé:
this.#lastname = "Doe"
- Publique:
- Les constructeurs
-
constructor(name, lastname) { this.name = name; this.#lastname = lastname; }
- super
super(name, lastname)- permet d'appeler le constructeur de la classe parente
- Les getters & setters
-
getName() { return this.#name; } setName(name) { this.#name = name; }
-
- Les héritages
class MyClass extends MyOtherClass {}
🔗 Liens utiles
📦 Récap du jour
Nous allons voir comment fonctionne le monorepo.
sequenceDiagram
box Web Client
participant React as React
participant Fetcher as Fetcher
end
box Web Server
participant Express as Express
participant Module as Module
end
box DB Server
participant DB as MySQL Server
end
React-)Fetcher: event
activate Fetcher
Fetcher-)Express: requête (HTTP)
activate Express
Express-)Module: appel
activate Module
Module-)DB: requête SQL
activate DB
DB--)Module: données
deactivate DB
Module--)Express: json
deactivate Module
Express--)Fetcher: réponse HTTP
deactivate Express
Fetcher--)React: render
deactivate Fetcher
Voilà l'architecture de notre monorepo.
C'est une architecture dite modulaire.
L'architecture modulaire est une approche de conception logicielle qui divise un système en plusieurs modules indépendants qui peuvent être développés, testés et déployés séparément.
- Facilité de maintenance : Les modules sont indépendants les uns des autres, ce qui facilite la maintenance et la mise à jour du code.
- Réutilisabilité du code : Les modules peuvent être réutilisés dans d'autres projets, ce qui permet de gagner du temps et de l'argent.
- Sécurité : Les modules sont isolés les uns des autres, ce qui réduit les risques de failles de sécurité.
Vous le connaissiez déjà, c'est notre bon vieux React.
Nous avons utilisé Express pour créer notre serveur. Il est très simple à utiliser et très performant.
Nous ne pouvons pas tout expliquer ici, car c'est assez complexe. Mais si vous avez des questions, n'hésitez pas.
Nous avons utilisé MySQL pour stocker nos données.
🔗 Liens utiles
📦 Récap du jour
Merise: Et oui, maintenant dans votre devlodex vous avez un nouveau mot !
Merise est une méthode de conception de base de données relationnelles.
Nous avons appris à faire un MCD (Modèle Conceptuel de Données) et un MLD (Modèle Logique de Données) & un MPD (Modèle Physique de Données).
Les relations et les cardinalités sont très importantes dans la conception d'une base de données et surtout, ils n'ont plus de secret pour vous !
💡 Ce qu'il faut retenir
Les cardinalités permettent de définir le nombre d'occurrences d'une entité qui peuvent être associées à une autre entité.
Il y a 3 types de cardinalités :
- 1 : une seule occurrence.
- 0 : aucune occurrence.
- n : plusieurs occurrences.
Comment savoir si je met 0, 1 ou n ?
Admettons les entitées suivantes :
User & Role et la relation entre les deux est have.
erDiagram
User ||--o{ Role : have
Nous nous posons la question suivante :
Un utilisateur a au minimum doit avoir un rôle, et un utilisateur a au maximum un rôle. Donc, la cardinalité est 11 du côté de l'utilisateur.
Ensuite pour le Role, un rôle peut être associé au minimum a aucun user et au maximum à plusieurs utilisateurs. Donc, la cardinalité est 0n du côté du rôle.
Il y a 3 types de relations :
- 1 to 1 : une seule entité est liée à une autre entité.
- 1 to many : une entité est liée à plusieurs entités.
- many to many : plusieurs entités sont liées à plusieurs entités.
- Clé primaire vers n'importe quelle table pour être clé étrangère
- La clé primaire cotée many passe étrangère coté one
- Création d'un table de liaison
🔗 Liens utiles
- SQL [FR] - Database Modelling
- Modéliser une base de données | Wild code school
- GorskiAnthony/tp-bdd
- 👨🎓 Après la théorie, des exos
📦 Récap du jour
Nous avons enfin vu MySQL ! Vous allez pouvoir stocker vos données.
Mais pour ce faire, un petit rappel sur les bases de données relationnelles.
Structured Query Language ou SQL est un langage de manipulation de données, il permet de créer, de lire, de mettre à jour et de supprimer des données dans une base de données relationnelle.
Voilà une liste des commandes SQL :
mysql -u <username> -p: permet de se connecter à mysqlCREATE DATABASE <database_name>;: permet de créer une base de donnéesSHOW DATABASES;: permet de voir les bases de donnéesUSE <database_name>;: permet de sélectionner une base de donnéesSELECT DATABASE();: permet de voir la base de données sélectionnéeSHOW TABLES;: permet de voir les tables d'une base de donnéesDESCRIBE <table_name>;: permet de voir les colonnes d'une table
CREATE TABLE <table_name> (id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255), age INT);: permet de créer une tableINSERT INTO <table_name> (name, age) VALUES ("John", 25);: permet d'insérer des données dans une tableSELECT * FROM <table_name>;: permet de voir toutes les données d'une tableTRUNCATE TABLE <table_name>;: permet de vider une tableDROP TABLE <table_name>;: permet de supprimer une tableUPDATE <table_name> SET name = "Mike" WHERE id = 1;: permet de modifier une donnée dans une tableDELETE FROM <table_name> WHERE id = 1;: permet de supprimer une donnée dans une table
ALTER TABLE <table_name> ADD COLUMN <column_name> <type>;: permet d'ajouter une colonne dans une tableALTER TABLE <table_name> MODIFY COLUMN <column_name> <type>;: permet de modifier une colonne dans une tableALTER TABLE <table_name> DROP COLUMN <column_name>;: permet de supprimer une colonne dans une table
🔗 Liens utiles
- SQL [FR] - Intro
- Base de données | Wild code school
- Cours et Tutoriels sur le Langage SQL
- SQL Tutorial
📦 Récap du jour
Nous allons comprendre comment fonctionne une API (la suite de la semaine du 07/11).
Tout d'abord, nous avons créé un serveur avec Express (ultra minimaliste).
// index.ts
import express, { Request, Response } from "express";
const app = express();
const port = 3310;
app.get("/", (request: Request, response: Response) => {
response.json({ message: "Hello World!" });
});
app.listen(port, () => {
console.log(`Server is running on http://localhost:${port}`);
});⬆️ ici, nous avons fait un serveur qui écoute sur le port 3310 et qui renvoie un objet JSON { message: "Hello World!" } quand on fait une requête sur la route /.
Voilà un exemple plus complet :
// index.ts
import express, { Request, Response } from "express";
const app = express();
const port = 3310;
app.get("/", (request: Request, response: Response) => {
response.json({ message: "Hello World!" });
});
app.get("/users", (request: Request, response: Response) => {
response.json([
{ id: 1, name: "John" },
{ id: 2, name: "Jane" },
{ id: 3, name: "Bob" },
]);
});
app.listen(port, () => {
console.log(`Server is running on http://localhost:${port}`);
});⬆️ ici, nous avons ajouté une route /users qui renvoie un tableau d'objets JSON.
[
{ "id": 1, "name": "John" },
{ "id": 2, "name": "Jane" },
{ "id": 3, "name": "Bob" }
]N'hésitez pas à tester avec Postman, Insomnia, Bruno, extension VSCode.
Coté client, nous savons déjà comment consommer une API avec fetch.
// index.ts
fetch("http://localhost:3310")
.then((response) => response.json())
.then((data) => console.log(data));🔗 Liens utiles
📦 Récap du jour
Retour à React :D
Et cette fois-ci, nous allons voir la notion de Context.
Et oui, le context est très utile pour passer des données de composant en composant sans passer par les props.
L'avantage, c'est que l'on peut passer des données de composant en composant sans passer par les props.
// context/NameContext.js
// j'importe createContext depuis react ainsi que useState
import { createContext, useState } from "react";
// je crée mon context
const NameContext = createContext("");
// je crée mon provider
const NameContextProvider = ({ children }) => {
const [name, setName] = useState("");
const handleChange = (e) => {
setName(e.target.value);
};
return (
<NameContext.Provider value={{ name, handleChange }}>
{children}
</NameContext.Provider>
);
};
export { NameContextProvider, NameContext };Et pour l'utiliser
// main.jsx
// car je vais utiliser mon provider dans mon main
import ReactDOM from "react-dom/client";
import App from "./App.jsx";
// J'encapsule mon application dans le contexte NameContextProvider
// Maintenant, tous les composants de mon application ont accès au contexte NameContext
import { NameContextProvider } from "./context/NameContext.jsx";
import "./index.css";
ReactDOM.createRoot(document.getElementById("root")).render(
<React.StrictMode>
<NameContextProvider>
<App />
</NameContextProvider>
</React.StrictMode>
);Le composant B2
// B2.jsx
import { useContext } from "react";
import { NameContext } from "../context/NameContext.jsx";
const B2 = () => {
// Ici, je récupère le contexte NameContext
// Je peux récupérer la valeur de name
// grâce à la destructuration
const { name } = useContext(NameContext);
return (
<div className="block">
<h1>B2, and hello {name} 👋</h1>
</div>
);
};
export default B2;🔗 Liens utiles
📦 Récap du jour
Les API ! C'est cool ! Mais c'est quoi une API ?
Une API (Application Programming Interface) est un ensemble de règles et de protocoles qui permettent à des logiciels de communiquer entre eux.
Il existe plusieurs types d'API :
- API REST
- API SOAP
- API GraphQL
- ...
Nous allons nous concentrer sur les API REST ✨ !
API REST pour Representational State Transfer est un style d'architecture qui définit un ensemble de contraintes pour la création de services web.
Les méthodes HTTP sont des verbes qui permettent de définir l'action à effectuer sur une ressource. Il y a une méthode pour chaque action.
| Méthode HTTP | Action | Description |
|---|---|---|
| POST | CREATE |
Créer une entrée |
| GET | READ |
Récupérer une information |
| PUT | UPDATE |
Mettre à jour une information |
| DELETE | DELETE |
Supprimer un élément |
Les codes de statut HTTP sont des codes numériques qui indiquent le résultat d'une requête HTTP. Il y a pleins de catégories de codes :
1xx: Information2xx: Succès3xx: Redirection4xx: Erreur client5xx: Erreur serveur
Pour consommer une API en JS, il faut utiliser la méthode fetch().
fetch("https://api.exemple.com")
.then((response) => response.json())
.then((data) => console.log(data));En mode async/await, ça donne ça :
async function fetchData() {
const response = await fetch("https://api.exemple.com");
const data = await response.json();
console.log(data);
}Le mot clé async permet de définir une fonction asynchrone. Une fonction asynchrone est une fonction qui retourne une Promise.
Le mot clé await permet de mettre en pause l'exécution d'une fonction asynchrone jusqu'à ce qu'une Promise soit résolue.
Le JSON (JavaScript Object Notation) est un format de données textuelles qui est facile à lire et à écrire pour les humains.
{
"key": "value",
"key2": "value2"
}🔗 Liens utiles
- JS [FR] - API & fetch
- WildCodeSchool-2024-09/JS-RemoteFR-Crew404-API_Fetch
- API REST : définition
- Asynchrone by Anthony Gorski
📦 Récap du jour
Nous allons pas écrire grand chose pour ce jour car ce n'est pas une généralité mais quand même, nous allons parler du workflow git de la Wild.
Nous allons avoir 3 branches disctinctes :
-
main 🔐: c'est la branche qui contient le code de production, c'est à dire le code qui est en ligne. -
staging 🔐: c'est la branche qui contient le code de préprod, c'est à dire le code qui simule celui qui est en ligne. -
dev 🔐: c'est la branche qui contient le code de développement, c'est à dire le code qui est en cours de développement. -
features: c'est la branche qui contient le code de la feature que vous êtes en train de développer.
Nous vous conseillons d'appeler vos branches de la manière suivante :
<N° du sprint><N° de l'US>_<Ma feature>
Ex :
S01US01_navbarS02US12_contact_form
Nous vous conseillons de faire un commit à chaque fois que vous avez fini une tâches technique.
- HTML
- Style
- Validation
Par exemple.
Nous vous quelques labels pour définir l'état de votre US.
- REVIEWED
- CHANGES REQUESTED
- CORRECTIONS DONE
- CONFLICTS
- CONFLICTS RESOLVED
🔗 Liens utiles
Nous avons fait un petit cours sur la méthodologie Agile avec le framwork Scrum.
Nous n'allons pas faire un gros récap, car le cours est assez long.
Mais en gros, pourquoi choisir la méthodologie Agile dans un projet ?
Regardé le cours, et si vous avez des questions, n'hésitez pas. (J'ai aussi mis un lien vers mon cours sur github)
📦 Récap du jour
🔗 Liens utiles
🚨 Nouvelle notion ! 🚨
Et oui, nous avons appris le nouveau hook useEffect aujourd'hui !
useEffectprend en paramètres :- une fonction qui va être exécutée à chaque fois que le composant est rendu.
- tableau de dépendances, ce tableau permet de définir quand la fonction va être exécutée.
Concernant le tableau de dépendances, il est possible de définir :
rien: la fonction va être exécutée à chaque fois que le composant est rendu.[]: la fonction va être exécutée une seule fois, au moment du rendu du composant.[value]: la fonction va être exécutée à chaque fois que la valeur devaluechange.
import { useEffect } from "react";
function App() {
useEffect(() => {
console.log("render");
}, []);
return <div>App</div>;
}Le hook useEffect peut être utilisé pour effectuer différentes tâches, telles que :
- Récupérer des données depuis une API et mettre à jour l'état du composant en conséquence
- Abonner le composant à des événements (ex : clics de souris, mouvements de la souris, frappes de clavier, etc.)
- Mettre à jour le DOM pour refléter les changements d'état du composant Nettoyer les effets de bord, tels que les abonnements aux événements, les connexions à des API, etc.
Il est important de noter que le hook useEffect doit être utilisé avec prudence, car il peut entraîner des effets de bord indésirables s'il est mal utilisé. Il est recommandé de ne pas exécuter de code coûteux dedans
En résumé, le hook useEffect est un outil puissant pour gérer les effets de bord dans les composants React. Il peut être utilisé pour exécuter une logique après le rendu d'un composant, telle que la récupération de données depuis une API, l'abonnement à des événements, la mise à jour du DOM, etc.
🔗 Liens utiles
Ce matin, il y avait un atelier sur react-router-dom.
Il y a beaucoup de texte, mais dans tout ça, il faut retenir que react-router-dom est une librairie qui permet de gérer la navigation dans une application React.
Pour installer react-router-dom, il faut taper la commande suivante :
$ npm install react-router-domcreateBrowserRouter: permet de créer un contexte de navigation, il contient toute la logique de navigation.Link: permet de créer un lien vers une autre page. (Celle ci ne recharge pas la page)RouterProvider: permet de fournir le contexte de navigation à l'application.
import { createBrowserRouter, RouterProvider } from "react-router-dom";
const router = createBrowserRouter([
{
// le chemin de l'URL, ici `/`
path: "/",
element: (
<>
<nav>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
</nav>
<main>
// le composant à afficher, bien sûr, il faut l'importer
<Home />
</main>
</>
),
},
{
// le chemin de l'URL, ici `/about`
path: "/about",
element: (
<>
<nav>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
</nav>
<main>
// le composant à afficher, bien sûr, il faut l'importer
<About />
</main>
</>
),
},
]);Nous pouvons créer un composant Layout qui va contenir la navigation et le composant à afficher.
Ce composant Layout sera la base de notre application, son affichage ne changera pas.
Pour pouvoir passer un composant différent en fonction de l'URL, nous allons utiliser le composant Outlet.
Outlet: permet d'afficher le composant correspondant à l'URL.
Voilà à quoi ressemble notre Layout :
// Layout.jsx
import { Link, Outlet } from "react-router-dom";
function Layout() {
return (
<>
<nav>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
</nav>
<main>
<Outlet />
</main>
</>
);
}
export default Layout;Maintenant que nous avons notre Layout, nous pouvons l'utiliser dans notre router.
import { createBrowserRouter, RouterProvider } from "react-router-dom";
// router creation
const router = createBrowserRouter([
{
path: "/",
element: <Layout />,
children: [
{
path: "/",
element: <Home />,
},
{
path: "/about",
element: <About />,
},
],
},
]);Oh, un nouveau mot clé children est apparu, il permet de définir les routes enfants. C'est à dire les routes qui sont dans le Layout.
Dans notre exemple, / possède le composant <Home /> et va donc être affiché dans le Layout à la place de <Outlet />. La même chose pour /about.
Si je souhaite avoir une route qui n'est pas dans le Layout, je peux la définir en dehors.
const router = createBrowserRouter([
{
path: "/",
element: <Layout />,
children: [
{
path: "/",
element: <Home />,
},
{
path: "/about",
element: <About />,
},
],
},
{
path: "/contact",
element: <Contact />,
},
]);Si vous souhaitez avoir une route "dynamique", alors, vous pouvez utiliser les paramètres.
const router = createBrowserRouter([
{
path: "/",
element: <Layout />,
children: [
{
path: "/",
element: <Home />,
},
{
path: "/about",
element: <About />,
},
{
path: "/user/:id",
element: <User />,
},
],
},
]);Pour récupérer le paramètre, vous pouvez utiliser useParams().
// User.jsx
import { useParams } from "react-router-dom";
function User() {
// Ici, useParams est un hook qui permet de récupérer les paramètres de l'URL
// Dans notre cas, on récupère l'id. l'"id" est la clé que nous avons défini dans la route
const { id } = useParams();
return <h1>User {id}</h1>;
}🔗 Liens utiles
📦 Récap du jour
Nous avons fait un petit projet de trombinoscope avec React. Nous avons vu comment créer un composant, comment passer des props, comment utiliser des hooks, etc. Le replay est disponible.
🔗 Liens utiles
📦 Récap du jour
Nous avons fait toutes les quêtes pokémons pour comprendre toutes les subtilités entre props, state, partage de state, etc.
Un state est contenu dans un composant, il est propre à ce composant. Il est donc IMPOSSIBLE de le partager entre plusieurs composants.
Pour certaine raison, il est essential de partager un state entre plusieurs composants. Pour cela, il faut remonter le state au composant parent le plus proche.
Dans le cas ci dessus, nous allons passer en props le state message dans le composant Messages (<Messages text={message} />) et dans le composant Input (<Input setMessage={setMessage} />).
Du coup, le composant Messages et Input ont accès au state message.
🔗 Liens utiles
📦 Récap du jour
Aujourd'hui, nous allons apprendre encore un truc de ouf ! Les hooks ! Et plus particulièrement le hook useState !
Le hook useState permet de gérer le state dans un composant de type fonction.
Son utilité est de pouvoir modifier la valeur d'une variable sans avoir à recharger la page.
Vous voulez un exemple ? Et bien en voilà un !
// Composant
// App.jsx
// j'importe useState depuis react
import React, { useState } from "react";
function App() {
// On initialise la variable count à 0
// structure :
// const [variable, fonction] = useState(valeur)
const [count, setCount] = useState(0);
return (
<div className="App">
<h1>{count}</h1>
{/* On utilise la fonction setCount pour modifier la valeur de count
seul setCount permet de modifier la valeur de count, count est en lecture seule.
Ça permettra de modifier la valeur de count sans recharger la page mais uniquement le composant.
*/}
<button onClick={() => setCount(count + 1)}>+</button>
</div>
);
}Dans l'exemple ci dessus, nous avons une variable count qui est initialisée à 0 et une fonction setCount qui permet de modifier la valeur de count.
Bien sûr, vous pouvez avoir plusieurs variables et fonctions dans un composant.
// Composant
// App.jsx
import React, { useState } from "react";
function App() {
const [count, setCount] = useState(0);
const [name, setName] = useState("John");
return (
<div className="App">
<h1>{count}</h1>
<h1>{name}</h1>
<button onClick={() => setCount(count + 1)}>+</button>
<button onClick={() => setCount(count - 1)}>-</button>
<button onClick={() => setName("Mike")}>Change name</button>
</div>
);
}Et oui, useState est asynchrone, c'est à dire que si vous faites ça :
// Composant
// App.jsx
import React, { useState } from "react";
function App() {
const [count, setCount] = useState(0);
return (
<div className="App">
<h1>{count}</h1>
<button onClick={() => setCount(count + 1)}>+</button>
<button onClick={() =>
setCount(count - 1)
console.log(count)
}>-</button>
</div>
);
}Et bien, le console.log(count) ne sera pas à jour, car useState est asynchrone. C'est à dire que le console.log va s'exécuter avant que la valeur de count soit modifiée.
Si je souhaite faire par exemple, soustraire 2 à count, je dois faire comme ça :
// Composant
// App.jsx
import React, { useState } from "react";
function App() {
const [count, setCount] = useState(0);
return (
<div className="App">
<h1>{count}</h1>
<button onClick={() => setCount(count + 1)}>+</button>
<button
onClick={() => {
setCount((prev) => prev - 1);
setCount((prev) => prev - 1);
}}
>
-
</button>
</div>
);
}💡 Et avec les classes, comment fonctionne les states ?
A l'origine, les states sont apparus avec les classes. C'est uniquement depuis la version 16.8 de React que l'on peut utiliser les hooks dans les composants de type fonction.
Donc, pour utiliser les states avec les classes, il faut faire comme ça :
// Composant
// App.jsx
import React, { Component } from "react";
class App extends Component {
// On initialise le state dans le constructor
constructor(props) {
super(props);
this.state = { count: 0 };
// On bind la fonction increment
// pour que le this soit accessible dans la fonction
this.increment = this.increment.bind(this);
}
increment() {
const { count } = this.state;
this.setState({ count: count + 1 });
}
render() {
const { count } = this.state;
return <button onClick={this.increment}>{count}</button>;
}
}🔗 Liens utiles
- 🧑🎓 - manipulalation du state n°1
- JS-RemoteFR-Crew404-Simpson at saisons2
- JS-RemoteFR-Crew404-MarmiWild
- React [FR] - Basics
Les props sont des arguments passés à un composant React.
On passe TOUJOURS les props de parent à enfant.
// src/App.js
import Welcome from "./components/Welcome";
function App() {
return (
<div>
<Welcome name="Hermione" />
<Welcome name="Ron" />
<Welcome name="Harry" />
</div>
);
}Props est un objet qui contient les propriétés passées à un composant.
// src/components/Welcome.js
function Welcome(props) {
console.log(props);
/* ex: { name: "Hermione" } */
return <h1>Hello, {props.name}</h1>;
}La destructuration permet de récupérer une valeur d'un objet ou d'un tableau.
Dans notre exemple, voilà comment on peut faire :
// src/components/User.jsx
function User(props) {
const { firstname } = props;
return (
<div>
<h1>{firstname}</h1>
</div>
);
}
// OU cette façon qui est plus utilisée
function User({ firstname }) {
return (
<div>
<h1>{firstname}</h1>
</div>
);
}Les retours (return) implicites en JS
// return implicite
const sum = (a, b) => a + b;
// syntaxe classique
const multiply = (a, b) => {
return a * b;
};
console.log(sum(5, 7));
console.log(multiply(2, 2));🔗 Liens utiles
📦 Récap du jour
REACT 👏👏👏
REACT 👏👏👏
REACT 👏👏👏
Et oui, nous entamons la partie React de notre formation.
Alors qu'avons-nous vu aujourd'hui ?
React est une bibliothèque JavaScript pour la construction d'interfaces utilisateur.
- Facile à apprendre : React est facile à apprendre, surtout si vous avez des connaissances en HTML, CSS et JavaScript.
- Réutilisable : React vous permet de créer des composants réutilisables.
- Performant : React utilise une technique appelée DOM virtuel qui améliore les performances de l'application.
JSX est une extension de la syntaxe JavaScript qui permet d'écrire du HTML dans du JavaScript. Alors le JSX ça ressemble à l'html, à l'odeur, à la couleur, mais ce n'est pas de l'html.
const element = <h1>Hello, world!</h1>;Les composants sont les éléments de base de React. Ils permettent de diviser l'interface utilisateur en morceaux indépendants et réutilisables.
function Welcome() {
return <h1>Hello world!</h1>;
}🔗 Liens utiles
Le cours viendra plus tard, car il est assez long et je ne veux pas vous spoiler. 😎
📦 Récap du jour
Node.js, c'est quoi ? C'est un environnement d'exécution JavaScript côté serveur.
Node.js est basé sur le moteur JavaScript V8 de Chrome.
Pour utiliser Node.js, il faut installer Node.js sur votre machine => Node.js
Ensuite, vous pouvez écrire du code JavaScript dans un fichier .js et l'exécuter avec Node.js.
$ node
> console.log("Hello World !");Pas terrible comme utilisation, du coup, nous allons utiliser plutôt un fichier.
// index.js
console.log("Hello World !");$ node index.js
# output
Hello World !NPM (Node Package Manager) est un gestionnaire de paquets pour Node.js.
Il permet d'installer des paquets (bibliothèques) pour Node.js.
$ npm install chalk@4.1.2Détail de la commande :
npm: le gestionnaire de paquetsinstall: commande pour installer un paquetchalk: le nom du paquet@4.1.2: la version du paquet
Je prend la version 4.1.2 de chalk car la version 5 ou plus utilise ESM (ECMAScript Modules) et je ne veux pas vous embrouiller avec ça.
// index.js
const chalk = require("chalk");
console.log(chalk.blue("Hello World !"));🔗 Liens utiles
📦 Récap du jour
Comment faire une bonne démo voilà le thème abordé aujourd'hui.
Nous avons vu ce qu'il fallait faire et ne pas faire lors d'une démo. ⬇️
- N’attendez pas la dernière minute
- Soyez clair et concis
- Appuyez-vous sur votre support
- Adaptez-vous à votre interlocuteur
- Préparez la répartition de la parole
- Anticipez les questions / réponses
- Entraînez-vous !!!!!
🔗 Liens utiles
Partie 2
📦 Récap du jour
Encore rien de nouveau, mais ça ne fait pas de mal 😎
N'hésite pas à aller au 08/10/2024, c'est quasiment le même cours.
L'opérateur de chaînage optionnel ?. permet de lire la valeur d'une propriété située au sein d'une chaîne de connexion avec une valeur null ou undefined sans lever d'erreur.
let user = {}; // l'utilisateur est sans nom
alert(user?.address?.street); // undefined (pas d'erreur)Alors que sans l'opérateur de chaînage optionnel, nous aurions une erreur :
let user = {}; // l'utilisateur est sans nom
alert(user.address.street); // Erreur !Les fonctions fléchées sont des raccourcis pour déclarer des fonctions.
// syntaxe
// ici, en plus de la syntaxe, nous avons un return implicite
let sum = (a, b) => a + b;
/* équivalent à */
let sum = function (a, b) {
return a + b;
};La différence entre classic function & arrow function
const user = {
name: "anthony",
classicFunction: function () {
console.log(this, this.name);
},
arrowFunction: () => {
console.log(this, this.name);
},
};
user.classicFunction();
user.arrowFunction();
/**********/
/* output */
/**********/
// {name: "anthony", classicFunction: ƒ, arrowFunction: ƒ} "anthony"
// Window {window: Window, self: Window, document: document, name: "", location: Location, …} undefinedCe que ça veut dire, c'est que les fonctions fléchées n'ont pas de this propre, elles prennent le this de leur parent.
ET SURTOUT ! JAVA !== JAVASCRIPT
code java pour un hello world:
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World");
}
}code javascript pour un hello world:
console.log("Hello, World");Alors, c'est plus simple JS non ? 😉
🔗 Liens utiles
Partie 1
📦 Récap du jour
Bon, rien de trop nouveau sous le soleil. Mais on quand même vu les bases.
N'hésite pas à aller au 08/10/2024, c'est quasiment le même cours.
Ici, nous avons une fonction qui s'appel et s'execute directement. On appelle ça une IIFE (Immediately Invoked Function Expression).
//IIFE
(function () {
//code
})();🔗 Liens utiles
- JS [FR] - JS Basics
- Can I use... Support tables for HTML5, CSS3, etc
- Optional chaining (?.) - JavaScript | MDN
📦 Récap du jour
✨ Enfin la manipulation du DOM ✨
Le DOM (Document Object Model) est une interface de programmation pour les documents HTML.
Il représente la page web sous forme d'arbre d'objets.
Nous avons besoins de 3 étapes pour manipuler le DOM :
- Sélectionner un élément
- Ajouter un événement
- Modifier le contenu
Il existe plusieurs façons de sélectionner un élément :
document.getElementById('id')document.getElementsByClassName('class')document.getElementsByTagName('tag')
Moi je préfère utiliser les méthodes suivantes :
document.querySelector('selecteur')document.querySelectorAll('selecteur')
Si vous avez appris a utiliser les sélecteurs CSS, vous serez à l'aise avec ces méthodes.
#id: sélectionne un élément par son iddocument.querySelector('#id')
.class: sélectionne un élément par sa classedocument.querySelector('.class')
tag: sélectionne un élément par sa balisedocument.querySelector('tag')
Il existe plusieurs type d'événements :
click: au clicchange: à la modificationmouseover: au survol- ...
Il existe plusieurs manière de modifier le contenu :
innerHTML: permet de modifier le contenu HTMLtextContent: permet de modifier le contenu textuelsetAttribute: permet de modifier un attributstyle: permet de modifier le style- ...
🔗 Liens utiles
📦 Récap du jour
✨ LES BASES PROGRAMMATIONS ✨
Alors, oui, c'est assez dur, il y a plein de choses à connaître, mais en vrai. Çaaa vaaaaa !
Les éléments communs pour tout le monde :
Une variable est un espace mémoire qui permet de stocker une valeur.
let maVariable = "Hello World !";Attention, quand une variable est réassignée, elle perd sa valeur précédente.
let prenom = "anthony";
prenom = "bob";anthony est remplacé par bob.
Il existe plusieurs types de données :
Les primitifs :
string: chaîne de caractèresnumber: nombreboolean: vrai ou fauxnull: nulundefined: non défini- ...
Les non primitifs :
object: objetarray: tableaufunction: fonction- ...
Il y a les opérateurs mathématiques que vous connaissez déjà, mais il y en a d'autres.
Voilà le lien pour les opérateurs : Opérateurs
Les tableaux permettent de stocker plusieurs valeurs.
let monTableau = [2, "Hello", true, ["coucou"]];Il existent plusieurs méthodes pour manipuler les tableaux :
push(): ajoute un élément à la fin du tableaupop(): supprime le dernier élément du tableaushift(): supprime le premier élément du tableauunshift(): ajoute un élément au début du tableau
Les conditions permettent de faire des choix dans le code.
L'architecture d'un if/else:
// Une condition doit obligatoirement se répondre par true ou false
if (condition) {
// code
} else if (condition) {
// code
} else {
// code
}Ex:
let maVariable = "Bouh";
if (maVariable === "Hello World !") {
console.log("C'est cool !");
} else {
console.log("C'est pas cool !");
}💡 Astuce !
Si votre condition est un booléen (true ou false), vous pouvez faire comme ça :
let maVariable = true;
if (maVariable) {
console.log("C'est cool !");
} else {
console.log("C'est pas cool !");
}Ou encore :
if (!maVariable) {
console.log("C'est pas cool !");
} else {
console.log("C'est cool !");
}Les boucles permettent de répéter une action.
Il y a 3 informations importantes :
- L'initialisation
- La condition d'arrêt
- L'incrémentation
Boucle for:
for (let i = 0; i < 10; i++) {
console.log(i);
}Boucle while & do while: (attention à ne pas faire de boucle infinie !)
let i = 0;
while (condition) {
// code
i++;
}let i = 0;
do {
// code
i++;
} while (condition);Il existe tout un tas d'autre façon de boucler, mais ce sont les plus courants.
Les fonctions permettent de réutiliser du code.
La syntaxe :
function: mot clé pour déclarer une fonctionmaFonction: nom de la fonction(): les paramètres{}: le corps de la fonction
function maFonction() {
console.log("Hello World !");
}
/* réutilisation de la fonction maFonction */
maFonction();
maFonction();console.log() ne sert à rien !
Il faut que la fonction retourne (return) une valeur.
function maFonction() {
return "Hello World !";
}Et pour récupérer la valeur de la fonction :
let maVariable = maFonction();Un exemple qui regroupe plein d'info 😎
// ma variable students qui est un tableau d'étudiants
const students = [
"Camille G",
"Marc",
"Manon",
"Elodie",
"Antoine",
"Nabil",
"Julie",
"Camille L",
"Joey",
"Charles",
"Thomas",
"Frank Sena",
"Ryan",
"Rudy",
];
// une fonction sayHello qui prend 1 paramètre `name`
function sayHello(name) {
console.log("Coucou " + name + " 👋");
}
// Une boucle for qui commence à 0 jusqu'à la taille du tableau
for (let i = 0; i < students.length; i += 1) {
// utilisation de la fonction sayHello qui prend un argument
// students[i] qui vaut le prénom de mon tableau "students" à l'index `i`
sayHello(students[i]);
}Les 6 falsy values sont des valeurs qui sont évaluées à false dans une condition.
false0""nullundefinedNaN
Si vous voulez en savoir plus, voici un article qui en parle : Les 6 falsy values
🔗 Liens utiles
📦 Récap du jour
Git est un logiciel de versionning, c'est à dire qu'il permet de gérer les versions de notre code, il est en local.
Github est un service en ligne qui permet de stocker notre code en ligne.
| commande | description |
|---|---|
git init |
permet d'initialiser un repo git |
git add . |
permet d'ajouter tous les fichiers au stage |
git commit -m "message" |
permet de créer un commit |
git push |
permet d'envoyer le code sur github |
git pull |
permet de récupérer le code sur github |
git status |
permet de voir l'état du repo git |
git checkout |
permet de changer de branche |
git switch |
depuis la version 2.23 |
git branch |
permet de créer une branche |
Si vous souhaitez avoir un git cheat sheet, voici le lien : Git Cheat Sheet
gitGraph
commit
commit
branch develop
checkout develop
commit
commit
checkout main
merge develop
commit
commit
Ensuite, à vous l'atelier git & github !
🔗 Liens utiles
📦 Récap du jour
Nous avons vu aujourd'hui comment passer des wireframes papier vers un prototype sur figma ainsi que les bonnes pratiques UX/UI.
Pour rappel :
🔗 Liens utiles
- Analyse et vérification du contraste | Adobe Color
- User Inyerface - A worst-practice UI experiment
- Définition de la Loi de Fitts, son rôle dans l'expérience utilisateur (UX)
- Les lois de la Gestalt appliquées au Design | bluedrop.fr, Agence web Drupal - Usinons Drupal
📦 Récap du jour
Notre petit cours d'aujourd'hui était sur les bases du web.
Le principe est de comprendre comment fonctionne le web, et ainsi, faire la différence entre le web et internet.
Web
Le web est un système de publication et de consultation de documents hypertextes liés entre eux et accessibles via le réseau internet.
Internet
Internet est un réseau informatique mondial accessible au public. Il permet de partager des informations et des ressources.
Protocoles
- HTTP(S) : Hypertext Transfer Protocol (Secure)
- FTP : File Transfer Protocol
- etc.
Navigateur
Un navigateur web est un logiciel permettant de consulter des pages web. Les plus connus sont Chrome, Firefox, Safari, Edge, Opera.
URL
Une URL (Uniform Resource Locator) est une adresse web. Elle est composée de plusieurs éléments :
- Protocole :
http://ouhttps:// - Nom de domaine :
www.google.com - Chemin :
/search?q=hello+world
🔗 Liens utiles
📦 Récap du jour
Nouvelle connaissance débloquée : Le Terminal.
Oui, le terminal est un outil puissant, mais il peut être intimidant au début. C'est pourquoi nous avons vu les bases pour vous aider à vous familiariser avec cet outil.
Le kit de survie du terminal :
| Commande | Description |
|---|---|
pwd |
affiche le répertoire courant |
ls |
liste les fichiers et dossiers du répertoire courant |
cd |
change de répertoire |
mkdir |
crée un dossier |
touch |
crée un fichier |
rm |
supprime un fichier |
rm -r |
supprime un dossier |
mv |
déplace un fichier ou un dossier |
cp |
copie un fichier ou un dossier |
cat |
affiche le contenu d'un fichier |
echo |
affiche un message à l'écran |
clear |
efface le terminal |
. |
répertoire courant |
.. |
répertoire parent |
man |
affiche le manuel d'une commande |
history |
affiche l'historique des commandes |
Bien sûr, il y a beaucoup plus de commandes, mais ce sont les bases pour commencer.
🔗 Liens utiles
📦 Récap du jour
Ladies and gentlemen, aujourd'hui, nous avons vu les bases du responsive design.
Le responsive, c'est la capacité d'un site web à s'adapter à la taille de l'écran de l'utilisateur. C'est un élément essentiel pour un site web, car il est important que le site soit lisible sur tous les supports.
Nous avons parler des grids et flexbox, qui sont des outils de mise en page en CSS. Ils permettent de créer des mises en page complexes et de les rendre responsive.
Voilà un petit récap des breakpoints (points de rupture) les plus utilisés :
🔗 Liens utiles
- Am I Responsive?
- Responsively App - A web developer's browser
- Interactive CSS Grid Generator | Layoutit Grid
- CSS Flexbox Generator - CSS Portal
- :root - CSS : Feuilles de style en cascade | MDN
📦 Récap du jour
Aujourd'hui, nous avons vu les bases de l'HTML et du CSS et comment lier les deux.
Je tiens à vous rassurer, il n'est pas nécessaire de tout retenir, mais il est important de comprendre les concepts de base.
- HTML : c'est la structure de la page web
- Les balises HTML sont des éléments de structure
<h1></h1>: titre de niveau 1<p></p>: paragraphe<a></a>: lien<img />: image- etc.
- Les balises HTML sont des éléments de structure
- CSS : c'est la mise en forme de la page web
- Les sélecteurs CSS permettent de cibler des éléments HTML
h1: cible tous les titres de niveau 1.ma__classe: cible tous les éléments ayant la classeclass="ma__classe"#mon__id: cible l'élément ayant l'idid="mon__id"
- Les sélecteurs CSS permettent de cibler des éléments HTML
<!DOCTYPE html>
<html>
<head>
<title>Nom de mon site</title>
<link rel="stylesheet" type="text/css" href="./style.css" />
</head>
<body>
<h1>Titre de la page</h1>
<p>Un paragraphe</p>
</body>
</html>h1 {
color: blue;
font-size: 12px;
}Priorité des sélecteurs (spécificité) L'ordre de priorité des sélecteurs est important :
- Sélecteur d'ID (
#id) : Priorité la plus élevée. - Sélecteur de classe (
.classe) : Priorité moyenne. - Sélecteur de balise (
balise) : Priorité la plus basse.
Concernant les propriétés CSS, il est important de comprendre qu'il est impossible de toutes les retenir. C'est pourquoi il est essentiel de savoir où trouver les informations. L'anglais est un atout pour la programmation, car la majorité des ressources sont en anglais.
🔗 Liens utiles
- MDN Web Docs
- W3Schools Online Web Tutorials
- HTML Reference
- CSS Reference
- Méthodologie BEM pour le CSS
- Flexbox Froggy - Un jeu pour apprendre les flexbox CSS
- Grid Garden - Un jeu pour apprendre les grid CSS
- CSS Diner - Un jeu pour apprendre les sélecteurs CSS
- CSS Battle - Un jeu pour apprendre le CSS
- Codepen - Un site pour partager du code HTML/CSS/JS
📦 Récap du jour
Aujourd'hui c'est présentation ! Vous avez eu un aperçu de ce qui vous attend dans les prochains mois.
Vous avez même eu le mot du CEO de la Wild Code School !
Nous avons aussi pris une superbe photo de groupe ! 📸
🔗 Liens utiles







































