const fs = require("fs"); const path = require("path"); const parser = require("@babel/parser"); const traverse = require("@babel/traverse").default; const entryFile = path.resolve(__dirname, "index.js"); const srcDir = path.resolve(__dirname, "src"); // Extensions de fichiers à analyser const scriptExtensions = [".js", ".jsx", ".ts", ".tsx", ".web.js"]; const imageExtensions = [".png", ".jpg", ".jpeg", ".gif", ".svg"]; // Fonction pour obtenir tous les fichiers dans un dossier avec des extensions spécifiques function getAllFiles(dir, extensions, fileList = []) { const files = fs.readdirSync(dir); files.forEach(function (file) { const filePath = path.join(dir, file); const stat = fs.statSync(filePath); if (stat.isDirectory()) { getAllFiles(filePath, extensions, fileList); } else if (extensions.includes(path.extname(file))) { fileList.push(filePath); } }); return fileList; } // Vérifie si un chemin est un fichier valide function isValidFile(filePath) { return fs.existsSync(filePath) && fs.statSync(filePath).isFile(); } // Résout le chemin de l'import en un fichier valide function resolveImport(filePath, importPath) { let importedFile = path.resolve(path.dirname(filePath), importPath); // Liste des extensions à tester, y compris .web.js const allExtensions = scriptExtensions; // Si le chemin n'a pas d'extension, essayer avec différentes extensions if (!path.extname(importedFile)) { for (const ext of allExtensions) { if (isValidFile(importedFile + ext)) { return importedFile + ext; } } } // Si un fichier avec l'extension actuelle existe, le retourner if (isValidFile(importedFile)) { return importedFile; } // Si le chemin est un répertoire, chercher un index avec les extensions if (fs.existsSync(importedFile) && fs.statSync(importedFile).isDirectory()) { const indexFiles = allExtensions.map((ext) => "index" + ext); for (const indexFile of indexFiles) { const indexFilePath = path.join(importedFile, indexFile); if (isValidFile(indexFilePath)) { return indexFilePath; } } } // Aucun fichier valide trouvé return null; } // Analyse des fichiers pour trouver les imports function getDependencies( filePath, visitedFiles = new Set(), usedDependencies = new Set(), usedFiles = new Set(), usedAssets = new Set() ) { if (visitedFiles.has(filePath)) return { usedDependencies, usedFiles, usedAssets }; visitedFiles.add(filePath); usedFiles.add(filePath); const content = fs.readFileSync(filePath, "utf-8"); let ast; try { ast = parser.parse(content, { sourceType: "module", plugins: ["jsx", "typescript", "classProperties", "dynamicImport"], }); } catch (error) { console.error(`Erreur lors de l'analyse du fichier ${filePath}:`, error); return { usedDependencies, usedFiles, usedAssets }; } traverse(ast, { ImportDeclaration({ node }) { const importPath = node.source.value; handleImport( filePath, importPath, visitedFiles, usedDependencies, usedFiles, usedAssets ); }, CallExpression({ node }) { if ( node.callee.type === "Import" || (node.callee.name === "require" && node.arguments.length) ) { const importArg = node.arguments[0]; if (importArg && importArg.type === "StringLiteral") { const importPath = importArg.value; handleImport( filePath, importPath, visitedFiles, usedDependencies, usedFiles, usedAssets ); } } }, }); // Vérifier si un fichier .web.js correspondant existe if (filePath.endsWith(".js")) { const webFilePath = filePath.replace(/\.js$/, ".web.js"); if (isValidFile(webFilePath)) { getDependencies( webFilePath, visitedFiles, usedDependencies, usedFiles, usedAssets ); } } return { usedDependencies, usedFiles, usedAssets }; } // Fonction pour gérer les imports function handleImport( filePath, importPath, visitedFiles, usedDependencies, usedFiles, usedAssets ) { if (importPath.startsWith(".")) { // Chemin relatif const resolvedPath = resolveImport(filePath, importPath); if (resolvedPath) { const ext = path.extname(resolvedPath); if (scriptExtensions.includes(ext)) { getDependencies( resolvedPath, visitedFiles, usedDependencies, usedFiles, usedAssets ); } else if (imageExtensions.includes(ext)) { usedAssets.add(resolvedPath); } } } else { // Dépendance de node_modules const dep = importPath.split("/")[0]; usedDependencies.add(dep); } } (async () => { // Étape 1: Obtenir tous les fichiers utilisés const allScriptFiles = getAllFiles(srcDir, scriptExtensions); const allAssetFiles = getAllFiles(srcDir, imageExtensions); const { usedDependencies, usedFiles, usedAssets } = getDependencies(entryFile); // Étape 2: Supprimer les fichiers scripts inutilisés const unusedScriptFiles = allScriptFiles.filter( (file) => !usedFiles.has(file) ); unusedScriptFiles.forEach((file) => { fs.unlinkSync(file); console.log(`Fichier script supprimé: ${file}`); }); // Étape 3: Supprimer les images non utilisées const unusedAssetFiles = allAssetFiles.filter( (file) => !usedAssets.has(file) ); unusedAssetFiles.forEach((file) => { fs.unlinkSync(file); console.log(`Fichier image supprimé: ${file}`); }); // Étape 4: Optimiser les images utilisées sans perte de qualité async function optimizeImages(usedAssets) { // Import dynamique des modules ES const imagemin = (await import("imagemin")).default; const imageminOptipng = (await import("imagemin-optipng")).default; const imageminJpegtran = (await import("imagemin-jpegtran")).default; const imageminGifsicle = (await import("imagemin-gifsicle")).default; const imageminSvgo = (await import("imagemin-svgo")).default; for (const file of usedAssets) { const ext = path.extname(file).toLowerCase(); const plugins = []; if (ext === ".png") { plugins.push(imageminOptipng({ optimizationLevel: 3 })); } else if (ext === ".jpg" || ext === ".jpeg") { plugins.push(imageminJpegtran({ progressive: true })); } else if (ext === ".gif") { plugins.push(imageminGifsicle({ optimizationLevel: 3 })); } else if (ext === ".svg") { plugins.push(imageminSvgo()); } else { continue; } try { const optimized = await imagemin([file], { destination: path.dirname(file), plugins: plugins, }); if (optimized && optimized.length > 0) { console.log(`Image optimisée: ${file}`); } else { console.log(`Image déjà optimisée ou non optimisable: ${file}`); } } catch (error) { console.error( `Erreur lors de l'optimisation de l'image ${file}:`, error ); } } } await optimizeImages(usedAssets); })();