Comment intégrer en toute sécurité le code d'interface créé par Claude Code dans un projet existant
TuBrief 편집팀
2026년 9월 12일
0
Computing/Software원본 영상을 바탕으로 AI의 도움을 받아 작성했습니다. 원본 영상이 기준입니다.
커뮤니티의 다른 글
댓글 (0)
Log in to leave a comment
아직 작성된 글이 없습니다
원본 영상을 바탕으로 AI의 도움을 받아 작성했습니다. 원본 영상이 기준입니다.
Log in to leave a comment
아직 작성된 글이 없습니다
Lancez Claude Code dans le terminal et tapez /design, un brouillon d'interface apparaît en quelques secondes. Pour un développeur solo, c'est pratique car ça demande moins d'effort. Le problème commence dès qu'on ouvre ce code.
Il ne prête aucune attention aux composants shadcn/ui déjà configurés dans le projet et recrée de pures balises <button>. Au lieu des couleurs sémantiques enregistrées dans la palette, il sème des codes hexadécimaux arbitraires tels que bg-[#1e293b] dans chaque fichier. À chaque création d'écran, on perd 40 minutes à corriger les chemins d'importation en désordre et à supprimer les styles en ligne.
Ce n'est pas qu'une impression. Selon une étude de GitClear menée en 2024 portant sur l'analyse de 211 millions de lignes de commit, le taux de code complètement abandonné ou réécrit dans les deux semaines suivant l'adoption d'outils d'IA a presque doublé, passant de 3,1 % à 5,7 %. Le taux de refactorisation a chuté à moins de 10 %, contre 25 %. La dette s'accumule aussi vite que le code grandit. Plutôt que d'espérer que le modèle respectera de lui-même le système de design existant, il faut lui lier les mains au niveau du système.
La raison pour laquelle Claude Code ignore le code existant est simple. Il parcourt uniquement les fichiers nécessaires de manière restreinte afin d'économiser la fenêtre de contexte. Sans aucune contrainte, le modèle dessine l'interface en combinant les balises HTML les plus primitives.
Le fichier de configuration à la racine de la session est maintenu à environ 10 % du coût d'entrée de base grâce au prompt caching (mise en cache des prompts). Il ne disparaît pas même si la conversation est réinitialisée ou compressée. En y gravant des règles de réutilisation des composants, on peut empêcher le modèle de créer des balises brutes de manière anarchique.
Écrivez les chemins des composants communs et les règles de style dans le fichier CLAUDE.md à la racine du projet.
`markdown
`
Il n'est pas nécessaire de passer en entier un fichier CSS global de plusieurs milliers de lignes à chaque prompt. Il suffit de sélectionner les noms de tokens dans la configuration Tailwind et de les extraire au format JSON.
`javascript
// scripts/extract-tokens.mjs
import fs from 'fs';
import resolveConfig from 'tailwindcss/resolveConfig.js';
import tailwindConfig from '../tailwind.config.js';
const fullConfig = resolveConfig(tailwindConfig);
const semanticTokens = {
colors: Object.keys(fullConfig.theme.colors || {}).filter(
(name) => !['inherit', 'current', 'transparent'].includes(name)
),
spacing: Object.keys(fullConfig.theme.spacing || {}),
borderRadius: Object.keys(fullConfig.theme.borderRadius || {}),
};
if (!fs.existsSync('.claude')) {
fs.mkdirSync('.claude');
}
fs.writeFileSync(
'.claude/design-tokens.json',
JSON.stringify(semanticTokens, null, 2)
);
`
Ajoutez ce script aux scripts postinstall et predev dans package.json.
`json
{
"scripts": {
"postinstall": "node scripts/extract-tokens.mjs",
"predev": "node scripts/extract-tokens.mjs"
}
}
`
La liste des classes disponibles est actualisée à chaque compilation. Le temps de travail manuel passé à corriger les classes de style comportant des fautes de frappe disparaît.
Peu importe les avertissements inscrits dans le prompt, le modèle sort parfois des valeurs aberrantes. Si on lui jette une capture d'écran en lui demandant de créer une interface, il insère des largeurs fixes telles que w-[380px] en fonction du ratio de l'image. C'est le principal coupable des défilements horizontaux intempestifs sur les écrans mobiles.
Pour respecter les critères WCAG 2.1 AA, il faut spécifier des normes par résolution et effectuer un contrôle obligatoire par l'interpréteur de code dès la création du fichier.
| Zone de vérification | Critère cible | Classes Tailwind obligatoires | Condition de blocage |
|---|---|---|---|
| Mobile | 390px (base) | flex-col, w-full, grid-cols-1 |
Défilement horizontal causé par l'utilisation d'une largeur fixe w-[...px] |
| Tablette | 768px (md:) |
md:flex-row, md:grid-cols-2, md:p-6 |
Maintien d'une structure mobile à 1 colonne sur un écran large |
| Bureau | 1440px (xl:) |
xl:max-w-7xl, mx-auto, xl:grid-cols-4 |
Conteneur de disposition s'étendant à l'infini en haute résolution |
| Mode sombre | Sélecteur .dark |
bg-background, text-foreground |
Laisser des classes par défaut telles que bg-white, text-black isolées |
| Accessibilité | WCAG 2.1 AA | aria-label, <main>, focus-visible:ring-2 |
Absence de texte alternatif pour lecteur d'écran sur les boutons icônes |
Pour contrôler un modèle indiscipliné, il est plus sûr d'utiliser des hooks de cycle de vie. Le hook PostToolUse de Claude Code permet d'exécuter un script dès qu'un fichier est écrit sur le disque.
Enregistrez la commande du hook dans .claude/settings.json.
`json
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit|MultiEdit",
"hooks": [
{
"type": "command",
"command": "node .claude/hooks/ast-lint-guard.mjs",
"timeout": 30
}
]
}
]
}
}
`
Écrivez ensuite le script de vérification. Il intercepte les codes hexadécimaux courants à l'aide d'expressions régulières pour les remplacer par des tokens du projet, et impose les règles via le plugin ESLint pour Tailwind.
`javascript
// .claude/hooks/ast-lint-guard.mjs
import fs from 'fs';
import readline from 'readline';
import { execSync } from 'child_process';
const rl = readline.createInterface({ input: process.stdin });
let inputBuffer = '';
rl.on('line', (line) => { inputBuffer += line; });
rl.on('close', () => {
try {
const payload = JSON.parse(inputBuffer);
const filePath = payload.tool_input?.file_path || payload.tool_input?.path;
if (!filePath || !/\.(tsx|jsx)$/.test(filePath) || !fs.existsSync(filePath)) {
process.exit(0);
}
let code = fs.readFileSync(filePath, 'utf-8');
let changed = false;
const replacementMap = {
'#ffffff': 'bg-background',
'#000000': 'text-foreground',
'#020817': 'bg-background',
'#0f172a': 'bg-card',
'#1e293b': 'bg-muted',
'#64748b': 'text-muted-foreground',
'#2563eb': 'bg-primary',
};
for (const [hex, token] of Object.entries(replacementMap)) {
const regex = new RegExp(`(bg|text|border)-\s*\[${hex}\]`, 'gi');
if (regex.test(code)) {
code = code.replace(regex, token);
changed = true;
}
}
if (changed) {
fs.writeFileSync(filePath, code, 'utf-8');
}
execSync(`npx eslint "${filePath}" --rule "tailwindcss/no-arbitrary-value: error"`, {
stdio: 'pipe',
});
process.exit(0);
} catch (error) {
const failureLog = error.stdout?.toString() || error.stderr?.toString() || error.message;
console.error([Lint Pipeline Block] 스타일 규칙 위반:\n${failureLog});
process.exit(1);
}
});
`
Installez le plugin de linteur dans le projet.
`bash
npm install -D eslint-plugin-tailwindcss
`
Si le script renvoie un code de sortie 1, Claude Code lit le journal d'erreurs et corrige le code avec des classes sémantiques au tour suivant. Cela réduit les moments où l'on s'arrache les cheveux sur des écrans cassés lors de la phase de QA.
Quand on demande à Claude Code de concevoir une interface, il a tendance à mélanger une fonction fetch, un énorme objet de fausses données et le JSX dans un seul fichier. Pour intégrer une API réelle plus tard, il faut alors tout retirer, y compris le code de rendu.
Le code d'interface n'a pas besoin de connaître la méthode de modification d'état. Il est plus sûr de diviser un répertoire fonctionnel en 4 fichiers et de fixer d'abord le schéma des données.
Définissez d'abord la spécification des données.
`typescript
// src/components/features/dashboard-card/schema.ts
import { z } from "zod";
export const MetricItemSchema = z.object({
id: z.string(),
label: z.string(),
value: z.string(),
changePercentage: z.number(),
trend: z.enum(["up", "down", "neutral"]),
});
export const DashboardCardSchema = z.object({
title: z.string().min(1),
metrics: z.array(MetricItemSchema),
});
export type DashboardCardData = z.infer;
export interface DashboardCardViewProps {
data: DashboardCardData;
isLoading?: boolean;
onActionClick?: (metricId: string) => void;
}
`
Ensuite, lors de l'appel de Claude Code dans le terminal, interdisez explicitement l'utilisation de tout état interne.
`bash
claude "src/components/features/dashboard-card/schema.ts의 DashboardCardViewProps를 구현하는 순수 UI 컴포넌트 src/components/features/dashboard-card/dashboard-card-view.tsx를 만들어줘. 내부에서 useState, useEffect, fetch는 절대 쓰지 말고 오직 넘겨받은 Props와 @/components/ui 요소만 사용해서 반응형으로 짜줘."
`
Pour l'intégration des données, enveloppez-les dans un hook. Conservez la même structure pour les fausses données (mock data) et la fonction d'appel API réelle.
`typescript
// src/components/features/dashboard-card/use-dashboard-card.ts
import { useQuery } from "@tanstack/react-query";
import { DashboardCardData } from "./schema";
const MOCK_DATA: DashboardCardData = {
title: "월간 활성 지표",
metrics: [
{ id: "m-1", label: "신규 유입", value: "1,240명", changePercentage: 12.5, trend: "up" },
{ id: "m-2", label: "이탈률", value: "2.1%", changePercentage: -0.4, trend: "down" },
],
};
export const useDashboardCard = (cardId: string, useMock = false) => {
return useQuery({
queryKey: ["dashboard-card", cardId],
queryFn: async () => {
if (useMock) {
return MOCK_DATA;
}
const res = await fetch(/api/dashboard/${cardId});
if (!res.ok) throw new Error("데이터 조회 실패");
return res.json();
},
});
};
`
Assemblez les deux dans le composant conteneur.
`typescript
// src/components/features/dashboard-card/index.tsx
"use client";
import React from "react";
import { DashboardCardView } from "./dashboard-card-view";
import { useDashboardCard } from "./use-dashboard-card";
export function DashboardCardContainer({ cardId, useMock = false }: { cardId: string; useMock?: boolean }) {
const { data, isLoading } = useDashboardCard(cardId, useMock);
if (!data) return null;
return (
<DashboardCardView
data={data}
isLoading={isLoading}
onActionClick={(id) => console.log(id)}
/>
);
}
`
Avant la disponibilité du backend, peaufinez l'interface avec useMock={true}. Une fois l'API achevée, supprimez simplement le drapeau. Le code de vue n'a pas besoin d'être touché d'une seule ligne.
À force de discuter longuement avec le modèle dans le terminal pour bidouiller l'UI, le fichier de configuration global intact se retrouve souvent modifié ou des fichiers temporaires non utilisés s'accumulent aux quatre coins du répertoire. Il est plus confortable de créer un répertoire dédié aux expérimentations tout en préservant son espace de travail initial.
L'utilisation de Git worktree permet d'exécuter Claude Code dans un dossier complètement isolé.
`bash
git worktree add ../saas-ui-sandbox -b experiment/ai-dashboard-ui
cd ../saas-ui-sandbox
claude
`
Si l'expérimentation échoue, supprimez simplement tout le dossier sans hésitation.
`bash
cd ../saas-platform
git worktree remove ../saas-ui-sandbox --force
git branch -D experiment/ai-dashboard-ui
`
Si le résultat obtenu est satisfaisant, ne fusionnez pas toute la branche, mais récupérez uniquement les fragments de code du fichier de vue en mode interactif.
`bash
git checkout main
git checkout -p experiment/ai-dashboard-ui -- src/components/features/dashboard-card/dashboard-card-view.tsx
`
En observant les blocs de code qui s'affichent dans le terminal, appuyez sur y pour les parties qui vous plaisent et sur n pour rejeter les modifications incorrectes.
Lorsque la session dépasse 5 tours, le contexte devient flou et le modèle commence à divaguer. Il faut nettoyer la session à chaque fois :
npx tsc --noEmit. Passez au prompt suivant uniquement s'il y a 0 erreur de type./compact sans hésiter pour réduire le gaspillage de tokens./clear. En cas d'embrouille, revenez au point de contrôle précédent avec /rewind.La capacité de génération élevée d'un modèle et la possibilité d'intégrer ce code en production sont deux choses totalement différentes. En restreignant les voies d'entrée avec CLAUDE.md, en vérifiant le code de sortie avec des hooks de cycle de vie et en séparant l'espace de travail avec worktree, vous éviterez de passer vos nuits à réparer le code recraché par l'IA.