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) })()