Chapitre 2.5 — Naissance de Drill
Où on en est : toolchain complète, téléphone et émulateur opérationnels. On crée maintenant le projet qui nous accompagnera 18 parties durant — proprement.
⏱️ TL;DR —
pnpm create expo-app drill, nettoyage du template d’exemple (on garde la structure, on vide le contenu), configuration d’app.json(nom, slug, scheme), premier écran d’accueil à nous, arborescence cible (components/,lib/,constants/), git init + premier commit. Drill affiche « Prêt à drill? » sur votre téléphone.
🎯 Objectifs
- Créer le projet Drill sur une base saine et le nettoyer du contenu d’exemple.
- Poser l’arborescence et les conventions qui tiendront tout le cours.
- Configurer l’identité de base dans
app.json. - Premier commit git d’un projet Expo (et savoir quoi ignorer).
Création et état des lieux
cd C:\Users\Alexl\Desktop
pnpm create expo-app@latest drill
cd drill
npx expo startScannez, vérifiez que le template tourne sur le téléphone. À partir d’ici, chaque chapitre du cours modifie CE projet.
Le nettoyage
Le template livre un exemple riche (deux onglets, composants de démo, animations). Pédagogique, mais on veut partir de zéro maîtrisé. Le template fournit d’ailleurs un script pour ça :
npm run reset-project
# → déplace l'exemple dans app-example/ et crée un app/ minimalRépondez y pour déplacer (on pourra fouiller app-example/ plus tard comme référence), puis
supprimez app-example/ quand vous n’en aurez plus besoin. Il reste :
drill/
├── app/
│ ├── _layout.tsx ← layout racine minimal
│ └── index.tsx ← l'unique écran (route /)
├── assets/
├── app.json
├── package.json
└── tsconfig.jsonL’arborescence cible du cours
Créez tout de suite les dossiers vides qui structureront la suite :
drill/
├── app/ ← écrans (Expo Router) — Parties 5+
├── components/ ← UI réutilisable — dès la Partie 3
├── lib/ ← logique pure TS — scoring, tirage… (Partie 6)
├── constants/ ← thème, config — Partie 4
└── assets/ ← images, sons, policesRègle d’or maintenue jusqu’au bout : lib/ ne doit jamais importer react-native. La
logique de score, le tirage aléatoire des questions, le calcul de streak — tout ça est du
TypeScript pur, testable en un clin d’œil (Partie 14).
L’identité dans app.json
// app.json — les champs qu'on fixe dès aujourd'hui
{
"expo": {
"name": "Drill",
"slug": "drill",
"scheme": "drill",
"version": "0.1.0",
"orientation": "portrait",
"userInterfaceStyle": "automatic",
"newArchEnabled": true
}
}name: "Drill"— le nom sous l’icône.scheme: "drill"— les URLsdrill://…ouvriront l’app (deep links, Partie 5 ; la notification du défi quotidien s’en servira en Partie 9).orientation: "portrait"— un quiz se joue en portrait ; on verrouille et on ne pense plus jamais au paysage.- Le
packageAndroid (com.alex.drill) attendra la Partie 12 — il n’est nécessaire qu’au premier build.
Le premier écran
Remplaçons l’écran minimal par le nôtre — votre premier vrai code RN (les composants sont expliqués en détail dès le prochain chapitre ; ici, on plante le drapeau) :
// app/index.tsx
import { StyleSheet, Text, View } from 'react-native'
export default function HomeScreen() {
return (
<View style={styles.container}>
<Text style={styles.title}>Drill</Text>
<Text style={styles.subtitle}>Prêt à drill ?</Text>
</View>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#0b1216',
gap: 8,
},
title: {
color: '#58c4dc',
fontSize: 48,
fontWeight: '800',
},
subtitle: {
color: '#e2e8f0',
fontSize: 18,
},
})// app/_layout.tsx
import { Stack } from 'expo-router'
export default function RootLayout() {
return <Stack screenOptions={{ headerShown: false }} />
}Sauvegardez : votre téléphone affiche l’écran sombre « Drill / Prêt à drill ? ». Première pierre posée.
💡 Pour un dev Next.js — Trois différences déjà visibles dans ce petit fichier :
View/Textau lieu dediv/h1; les styles sont un objet JS passé par prop (pas de classe, pas de fichier CSS) ; etflex: 1sur le conteneur racine — l’équivalent deheight: 100vh, indispensable sinon la View ne mesure que son contenu. Tout s’éclaircit dans les Parties 3 et 4.
Git
Le .gitignore généré est déjà correct (il exclut node_modules/, .expo/, et les dossiers
natifs générables). Vérifiez juste ces lignes clés, puis committez :
# .gitignore (déjà présent — les lignes qui comptent)
node_modules/
.expo/
dist/
# generated native folders (CNG)
/android
/iosgit init
git add -A
git commit -m "Drill : projet Expo SDK 57 nettoyé, premier écran"⚠️ Piège — Ne committez PAS
.expo/(état local de la CLI) ni, pour l’instant,android/(généré par prebuild — CNG, chapitre 1.3). Un repo Expo propre ne contient QUE du TS, la config et les assets. Si un jourandroid/apparaît après unexpo run:android, le.gitignoreci-dessus l’ignore déjà.
Récapitulatif de la Partie 2
Vous avez désormais :
- ✅ Node + pnpm + la CLI Expo opérationnels
- ✅ Expo Go sur le téléphone, connecté en WiFi (et le plan B USB/tunnel)
- ✅ Android Studio : SDK, émulateur Pixel, adb dans le PATH
- ✅ VS Code + DevTools (
j) + element inspector - ✅ Drill v0.1.0 : projet propre, arborescence posée, premier écran, premier commit
✏️ Exercices
1. Faites la manip complète vous-même (création → reset → arborescence → app.json → écran →
commit). Puis vérifiez : git log --oneline montre 1 commit, git status est propre.
✅ Solution
Suivre le chapitre dans l’ordre. Vérifications : l’app affiche l’écran Drill sur le téléphone,
git status ne liste ni .expo/ ni node_modules/, et npx expo-doctor ne remonte aucune
erreur bloquante.
2. Changez la couleur du titre pour la couleur officielle de VOTRE thème préféré, observez
le Fast Refresh, puis remettez #58c4dc (c’est le cyan React qu’on gardera).
✅ Solution
Modifier styles.title.color, sauvegarder → le changement apparaît sans perdre l’état. Noter au
passage : la valeur est une string dans un objet JS, pas une propriété CSS — les erreurs de
frappe se voient à l’exécution, pas à la compilation (NativeWind + TS amélioreront ça, Partie 4).
3. Créez lib/greeting.ts exportant greeting(name: string): string, importez-la dans
l’écran et affichez son résultat. Pourquoi ce petit exercice illustre-t-il la règle d’or de lib/ ?
✅ Solution
// lib/greeting.ts
export function greeting(name: string): string {
return `Prêt à drill, ${name} ?`
}Import et usage : <Text style={styles.subtitle}>{greeting('Alex')}</Text>. La fonction ne
sait pas que RN existe : elle serait testable avec Jest sans aucun mock, et réutilisable dans
un script Node. Toute la logique de jeu de Drill suivra ce modèle.
🧠 Quiz
1. Que fait npm run reset-project dans le template Expo ?
Réponse
Il déplace le contenu d’exemple (onglets de démo, composants) vers app-example/ et crée un
app/ minimal (_layout.tsx + index.tsx) — un point de départ propre.
2. À quoi servira le champ scheme d’app.json ?
Réponse
Aux deep links : les URLs drill://… ouvriront l’app directement sur un écran donné
(Partie 5), notamment depuis la notification du défi quotidien (Partie 9).
3. Citez deux entrées indispensables du .gitignore d’un projet Expo.
Réponse
node_modules/, .expo/ (état local CLI), et les dossiers natifs générés /android /ios
(artefacts CNG régénérables par prebuild).
4. Pourquoi lib/ ne doit-il jamais importer react-native ?
Réponse
Pour garder la logique métier pure : testable avec Jest sans environnement RN, réutilisable hors app, et insensible aux changements d’UI. Le scoring de Drill n’a pas besoin de View.
5. Que fait flex: 1 sur la View racine de l’écran ?
Réponse
Elle prend tout l’espace disponible de son parent (l’écran entier ici). Sans ça, la View ne mesurerait que son contenu et le centrage vertical n’aurait aucun espace où opérer. Détails flexbox en Partie 4.
👉 Partie suivante : Partie 3 — Fondamentaux : penser natif — View, Text, Pressable, FlatList : le vocabulaire de base, et les pièges qui piègent tous les devs web.