210 lines
6.7 KiB
JavaScript
210 lines
6.7 KiB
JavaScript
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)
|
|
})()
|