1
0
mirror of https://github.com/kamranahmedse/developer-roadmap.git synced 2025-08-19 07:31:24 +02:00

feat: implement image compressor (#5551)

* wip: image compressor

* fix: ignore increase file

* Compress images

* Compress images

---------

Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
This commit is contained in:
Arik Chakma
2024-04-26 22:05:54 +06:00
committed by GitHub
parent f173220966
commit 240c55cc6a
203 changed files with 381 additions and 33 deletions

154
scripts/compress-images.ts Normal file
View File

@@ -0,0 +1,154 @@
import fs from 'node:fs/promises';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import sharp from 'sharp';
// ERROR: `__dirname` is not defined in ES module scope
// https://iamwebwiz.medium.com/how-to-fix-dirname-is-not-defined-in-es-module-scope-34d94a86694d
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const allowedFileExtensions = [
'.avif',
'.gif',
'.heif',
'.jpeg',
'.png',
'.raw',
'.tiff',
'.webp',
] as const;
type AllowedFileExtension = (typeof allowedFileExtensions)[number];
const publicDir = path.join(__dirname, '../public');
const cacheFile = path.join(__dirname, '/compressed-images.json');
const KB_IN_BYTES = 1024;
const COMPRESS_CONFIG = {
avif: {
chromaSubsampling: '4:4:4',
effort: 9.0,
},
gif: {
effort: 10.0,
},
jpeg: {
chromaSubsampling: '4:4:4',
mozjpeg: true,
trellisQuantisation: true,
overshootDeringing: true,
optimiseScans: true,
},
png: {
compressionLevel: 9.0,
palette: true,
},
raw: {},
tiff: {
compression: 'lzw',
},
webp: {
effort: 6.0,
},
};
(async () => {
let cache: string[] = [];
const isCacheFileExists = await fs
.access(cacheFile)
.then(() => true)
.catch(() => false);
if (isCacheFileExists) {
const cacheFileContent = await fs.readFile(cacheFile, 'utf8');
cache = JSON.parse(cacheFileContent);
}
const images = await recursiveGetImages(publicDir);
for (const image of images) {
const extname = path.extname(image).toLowerCase() as AllowedFileExtension;
if (
!allowedFileExtensions.includes(extname) ||
image.includes('node_modules') ||
image.includes('.astro') ||
image.includes('.vscode') ||
image.includes('.git')
) {
continue;
}
const stats = await fs.stat(image);
const relativeImagePath = path.relative(path.join(__dirname, '..'), image);
if (cache.includes(relativeImagePath)) {
continue;
}
const prevSize = stats.size / KB_IN_BYTES;
let imageBuffer: Buffer | undefined;
switch (extname) {
case '.avif':
imageBuffer = await sharp(image).avif(COMPRESS_CONFIG.avif).toBuffer();
break;
case '.gif':
imageBuffer = await sharp(image).gif(COMPRESS_CONFIG.gif).toBuffer();
break;
case '.heif':
imageBuffer = await sharp(image).heif().toBuffer();
break;
case '.jpeg':
imageBuffer = await sharp(image).jpeg(COMPRESS_CONFIG.jpeg).toBuffer();
break;
case '.png':
imageBuffer = await sharp(image).png(COMPRESS_CONFIG.png).toBuffer();
break;
case '.raw':
imageBuffer = await sharp(image).raw().toBuffer();
break;
case '.tiff':
imageBuffer = await sharp(image).tiff(COMPRESS_CONFIG.tiff).toBuffer();
break;
case '.webp':
imageBuffer = await sharp(image).webp(COMPRESS_CONFIG.webp).toBuffer();
break;
}
if (!imageBuffer) {
console.error(`${image} Compressing failed!`);
continue;
}
const newSize = imageBuffer.length / KB_IN_BYTES;
const diff = prevSize - newSize;
if (diff <= 0) {
console.log(`📦 Skipped ${relativeImagePath}`);
continue;
}
const diffPercent = ((diff / prevSize) * 100).toFixed(2);
console.log(
`📦 Reduced ${prevSize.toFixed(2)}KB → ${newSize.toFixed(2)}KB (${diff.toFixed(2)}KB, ${diffPercent}%) for ${relativeImagePath}`,
);
await fs.writeFile(image, imageBuffer);
cache.push(relativeImagePath);
// So that we don't lose the cache if the script crashes
await fs.writeFile(cacheFile, JSON.stringify(cache, null, 2), 'utf8');
}
await fs.writeFile(cacheFile, JSON.stringify(cache, null, 2), 'utf8');
})();
async function recursiveGetImages(dir: string): Promise<string[]> {
const subdirs = await fs.readdir(dir, { withFileTypes: true });
const files = await Promise.all(
subdirs.map((dirent) => {
const res = path.resolve(dir, dirent.name);
return dirent.isDirectory() ? recursiveGetImages(res) : res;
}),
);
return Array.prototype.concat(...files);
}

View File

@@ -0,0 +1,199 @@
[
"public/authors/dmytrobol.png",
"public/authors/ebrahimbharmal007.png",
"public/authors/jesse.png",
"public/authors/peter-thaleikis.png",
"public/best-practices/api-security.png",
"public/best-practices/aws.png",
"public/best-practices/backend-performance.png",
"public/best-practices/frontend-performance.png",
"public/guides/asymptotic-notation.png",
"public/guides/avoid-render-blocking-javascript-with-async-defer.png",
"public/guides/backend-languages/back-vs-front.png",
"public/guides/backend-languages/backend-roadmap-part.png",
"public/guides/backend-languages/javascript-interest.png",
"public/guides/backend-languages/pypl-go-index.png",
"public/guides/bash-vs-shell.jpeg",
"public/guides/basic-authentication/chrome-basic-auth.png",
"public/guides/basic-authentication/safari-basic-auth.png",
"public/guides/basic-authentication.png",
"public/guides/big-o-notation.png",
"public/guides/character-encodings.png",
"public/guides/ci-cd.png",
"public/guides/dhcp.png",
"public/guides/jwt-authentication.png",
"public/guides/llms.png",
"public/guides/project-history.png",
"public/guides/proxy/forward-proxy.png",
"public/guides/proxy/proxy-example.png",
"public/guides/proxy/reverse-proxy.png",
"public/guides/random-numbers.png",
"public/guides/session-authentication.png",
"public/guides/sli-slo-sla.jpeg",
"public/guides/ssl-tls-https-ssh.png",
"public/guides/token-authentication.png",
"public/guides/torrent-client/download.png",
"public/guides/torrent-client/pipelining.png",
"public/guides/unfamiliar-codebase.png",
"public/guides/web-vitals.png",
"public/images/brand.png",
"public/images/default-avatar.png",
"public/images/features/in-progress.png",
"public/images/icons8-wand.gif",
"public/images/partners/ambassador-graphic-1.png",
"public/images/partners/ambassador-graphic-2.png",
"public/images/partners/apollo-workshop.png",
"public/images/partners/graphql-summit.png",
"public/images/partners/nginx.png",
"public/images/roadmap-editor.jpeg",
"public/images/system-design.png",
"public/images/team-promo/contact.png",
"public/images/team-promo/documentation.png",
"public/images/team-promo/growth-plans.png",
"public/images/team-promo/hero-img.png",
"public/images/team-promo/hero.png",
"public/images/team-promo/invite-members.png",
"public/images/team-promo/many-roadmaps.png",
"public/images/team-promo/onboarding.png",
"public/images/team-promo/our-roadmaps.png",
"public/images/team-promo/progress-tracking.png",
"public/images/team-promo/roadmap-editor.png",
"public/images/team-promo/sharing-settings.png",
"public/images/team-promo/skill-gap.png",
"public/images/team-promo/team-dashboard.png",
"public/images/team-promo/team-insights.png",
"public/images/team-promo/update-progress.png",
"public/manifest/apple-touch-icon.png",
"public/manifest/icon152.png",
"public/manifest/icon196.png",
"public/manifest/icon32.png",
"public/og-images/best-practices/api-security.png",
"public/og-images/best-practices/aws.png",
"public/og-images/best-practices/backend-performance.png",
"public/og-images/best-practices/code-review.png",
"public/og-images/best-practices/frontend-performance.png",
"public/og-images/guides/asymptotic-notation.png",
"public/og-images/guides/avoid-render-blocking-javascript-with-async-defer.png",
"public/og-images/guides/backend-developer-skills.png",
"public/og-images/guides/backend-developer-tools.png",
"public/og-images/guides/backend-languages.png",
"public/og-images/guides/basic-authentication.png",
"public/og-images/guides/basics-of-authentication.png",
"public/og-images/guides/big-o-notation.png",
"public/og-images/guides/character-encodings.png",
"public/og-images/guides/ci-cd.png",
"public/og-images/guides/consistency-patterns-in-distributed-systems.png",
"public/og-images/guides/design-patterns-for-humans.png",
"public/og-images/guides/dhcp-in-one-picture.png",
"public/og-images/guides/dns-in-one-picture.png",
"public/og-images/guides/free-resources-to-learn-llms.png",
"public/og-images/guides/history-of-javascript.png",
"public/og-images/guides/how-to-setup-a-jump-server.png",
"public/og-images/guides/http-basic-authentication.png",
"public/og-images/guides/http-caching.png",
"public/og-images/guides/introduction-to-llms.png",
"public/og-images/guides/journey-to-http2.png",
"public/og-images/guides/jwt-authentication.png",
"public/og-images/guides/levels-of-seniority.png",
"public/og-images/guides/oauth.png",
"public/og-images/guides/proxy-servers.png",
"public/og-images/guides/random-numbers.png",
"public/og-images/guides/scaling-databases.png",
"public/og-images/guides/session-authentication.png",
"public/og-images/guides/session-based-authentication.png",
"public/og-images/guides/setup-and-auto-renew-ssl-certificates.png",
"public/og-images/guides/single-command-database-setup.png",
"public/og-images/guides/ssl-tls-https-ssh.png",
"public/og-images/guides/sso.png",
"public/og-images/guides/token-authentication.png",
"public/og-images/guides/torrent-client.png",
"public/og-images/guides/unfamiliar-codebase.png",
"public/og-images/guides/what-are-web-vitals.png",
"public/og-images/guides/what-is-internet.png",
"public/og-images/guides/what-is-sli-slo-sla.png",
"public/og-images/guides/why-build-it-and-they-will-come-wont-work-anymore.png",
"public/og-images/roadmaps/android.png",
"public/og-images/roadmaps/angular.png",
"public/og-images/roadmaps/aspnet-core.png",
"public/og-images/roadmaps/aws.png",
"public/og-images/roadmaps/backend.png",
"public/og-images/roadmaps/blockchain.png",
"public/og-images/roadmaps/code-review.png",
"public/og-images/roadmaps/computer-science.png",
"public/og-images/roadmaps/cpp.png",
"public/og-images/roadmaps/cyber-security.png",
"public/og-images/roadmaps/data-analyst.png",
"public/og-images/roadmaps/datastructures-and-algorithms.png",
"public/og-images/roadmaps/design-system.png",
"public/og-images/roadmaps/devops.png",
"public/og-images/roadmaps/docker.png",
"public/og-images/roadmaps/flutter.png",
"public/og-images/roadmaps/frontend.png",
"public/og-images/roadmaps/full-stack.png",
"public/og-images/roadmaps/game-developer.png",
"public/og-images/roadmaps/golang.png",
"public/og-images/roadmaps/graphql.png",
"public/og-images/roadmaps/java.png",
"public/og-images/roadmaps/javascript.png",
"public/og-images/roadmaps/kubernetes.png",
"public/og-images/roadmaps/mlops.png",
"public/og-images/roadmaps/mongodb.png",
"public/og-images/roadmaps/nodejs.png",
"public/og-images/roadmaps/postgresql-dba.png",
"public/og-images/roadmaps/prompt-engineering.png",
"public/og-images/roadmaps/python.png",
"public/og-images/roadmaps/qa.png",
"public/og-images/roadmaps/react-native.png",
"public/og-images/roadmaps/react.png",
"public/og-images/roadmaps/rust.png",
"public/og-images/roadmaps/server-side-game-developer.png",
"public/og-images/roadmaps/software-architect.png",
"public/og-images/roadmaps/software-design-architecture.png",
"public/og-images/roadmaps/spring-boot.png",
"public/og-images/roadmaps/sql.png",
"public/og-images/roadmaps/system-design.png",
"public/og-images/roadmaps/technical-writer.png",
"public/og-images/roadmaps/typescript.png",
"public/og-images/roadmaps/ux-design.png",
"public/og-images/roadmaps/vue.png",
"public/og-images/sql-roadmap.png",
"public/roadmaps/android.png",
"public/roadmaps/aspnet-core.png",
"public/roadmaps/aws.png",
"public/roadmaps/backend.png",
"public/roadmaps/blockchain.png",
"public/roadmaps/computer-science.png",
"public/roadmaps/cpp.png",
"public/roadmaps/cyber-security.png",
"public/roadmaps/data-analyst.png",
"public/roadmaps/design-system.png",
"public/roadmaps/devops.png",
"public/roadmaps/docker.png",
"public/roadmaps/flutter.png",
"public/roadmaps/frontend.png",
"public/roadmaps/full-stack.png",
"public/roadmaps/game-developer.png",
"public/roadmaps/graphql.png",
"public/roadmaps/intro.png",
"public/roadmaps/java.png",
"public/roadmaps/javascript.png",
"public/roadmaps/kubernetes.png",
"public/roadmaps/mlops.png",
"public/roadmaps/mongodb.png",
"public/roadmaps/nodejs.png",
"public/roadmaps/python.png",
"public/roadmaps/qa.png",
"public/roadmaps/react.png",
"public/roadmaps/rust.png",
"public/roadmaps/software-architect.png",
"public/roadmaps/software-design-architecture.png",
"public/roadmaps/sql.png",
"public/roadmaps/technical-writer.png",
"public/roadmaps/typescript.png",
"public/roadmaps/ux-design.png",
"public/roadmaps/vue.png",
"public/og-images/roadmaps/ai-data-scientist.png",
"public/og-images/roadmaps/linux.png",
"public/roadmaps/ai-data-scientist.png",
"public/roadmaps/linux.png"
]