update
This commit is contained in:
+251
@@ -0,0 +1,251 @@
|
||||
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);
|
||||
})();
|
||||
Reference in New Issue
Block a user