feat(Images): convert images to AVIF format for improved performance
- Updated image references in various components and configuration files to use AVIF format instead of PNG and JPG. - Modified the build process to include a script for converting images to AVIF, enhancing loading times and reducing file sizes. - Ensured consistency across the application by updating image paths in the footer, main layout, and content components.
This commit is contained in:
@@ -7,7 +7,7 @@
|
|||||||
"start": "cross-env NODE_OPTIONS=\"--no-deprecation\" webpack serve --progress --mode development --no-open",
|
"start": "cross-env NODE_OPTIONS=\"--no-deprecation\" webpack serve --progress --mode development --no-open",
|
||||||
"start:seedheads": "cross-env PROXY_TARGET=https://seedheads.de NODE_OPTIONS=\"--no-deprecation\" webpack serve --progress --mode development --no-open",
|
"start:seedheads": "cross-env PROXY_TARGET=https://seedheads.de NODE_OPTIONS=\"--no-deprecation\" webpack serve --progress --mode development --no-open",
|
||||||
"prod": "webpack serve --progress --mode production --no-client-overlay --no-client --no-web-socket-server --no-open --no-live-reload --no-hot --compress --no-devtool",
|
"prod": "webpack serve --progress --mode production --no-client-overlay --no-client --no-web-socket-server --no-open --no-live-reload --no-hot --compress --no-devtool",
|
||||||
"build:client": "cross-env NODE_ENV=production webpack --progress --mode production && shx cp dist/index.html dist/index_template.html",
|
"build:client": "node scripts/convert-images-to-avif.cjs && cross-env NODE_ENV=production webpack --progress --mode production && shx cp dist/index.html dist/index_template.html",
|
||||||
"build": "npm run build:client",
|
"build": "npm run build:client",
|
||||||
"analyze": "cross-env ANALYZE=true NODE_ENV=production webpack --progress --mode production",
|
"analyze": "cross-env ANALYZE=true NODE_ENV=production webpack --progress --mode production",
|
||||||
"lint": "eslint src/**/*.{js,jsx}",
|
"lint": "eslint src/**/*.{js,jsx}",
|
||||||
|
|||||||
@@ -152,7 +152,7 @@ const saveProductImages = async (socket, products, categoryName, outputDir) => {
|
|||||||
"public",
|
"public",
|
||||||
"assets",
|
"assets",
|
||||||
"images",
|
"images",
|
||||||
"sh.png"
|
"sh.avif"
|
||||||
);
|
);
|
||||||
|
|
||||||
// Ensure assets/images directory exists
|
// Ensure assets/images directory exists
|
||||||
@@ -236,7 +236,7 @@ const saveProductImages = async (socket, products, categoryName, outputDir) => {
|
|||||||
|
|
||||||
fs.writeFileSync(imagePath, processedImageBuffer);
|
fs.writeFileSync(imagePath, processedImageBuffer);
|
||||||
console.log(
|
console.log(
|
||||||
` ✅ Applied centered inverted sh.png overlay to ${estimatedFilename}`
|
` ✅ Applied centered inverted sh.avif overlay to ${estimatedFilename}`
|
||||||
);
|
);
|
||||||
} catch (overlayError) {
|
} catch (overlayError) {
|
||||||
console.log(
|
console.log(
|
||||||
|
|||||||
@@ -1,4 +1,12 @@
|
|||||||
const generateCategoryJsonLd = (category, products = [], baseUrl, config) => {
|
const generateCategoryJsonLd = (category, products = [], baseUrl, config) => {
|
||||||
|
// Category IDs to skip (seeds, plants, headshop items)
|
||||||
|
const skipCategoryIds = [689, 706, 709, 711, 714, 748, 749, 896, 710, 924, 923, 922, 921, 916, 278, 259, 258];
|
||||||
|
|
||||||
|
// Check if category ID is in skip list
|
||||||
|
if (category.id && skipCategoryIds.includes(parseInt(category.id))) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
const categoryUrl = `${baseUrl}/Kategorie/${category.seoName}`;
|
const categoryUrl = `${baseUrl}/Kategorie/${category.seoName}`;
|
||||||
|
|
||||||
// Calculate price valid date (current date + 3 months)
|
// Calculate price valid date (current date + 3 months)
|
||||||
|
|||||||
BIN
public/assets/images/cutlings.avif
Normal file
BIN
public/assets/images/cutlings.avif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.1 KiB |
BIN
public/assets/images/gg.avif
Normal file
BIN
public/assets/images/gg.avif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.1 KiB |
BIN
public/assets/images/maps.avif
Normal file
BIN
public/assets/images/maps.avif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
BIN
public/assets/images/seeds.avif
Normal file
BIN
public/assets/images/seeds.avif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
BIN
public/assets/images/sh.avif
Normal file
BIN
public/assets/images/sh.avif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.8 KiB |
58
scripts/convert-images-to-avif.cjs
Normal file
58
scripts/convert-images-to-avif.cjs
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
const sharp = require('sharp');
|
||||||
|
const path = require('path');
|
||||||
|
const fs = require('fs');
|
||||||
|
|
||||||
|
const imagesToConvert = [
|
||||||
|
{ src: 'sh.png', dest: 'sh.avif' },
|
||||||
|
{ src: 'seeds.jpg', dest: 'seeds.avif' },
|
||||||
|
{ src: 'cutlings.jpg', dest: 'cutlings.avif' },
|
||||||
|
{ src: 'gg.png', dest: 'gg.avif' },
|
||||||
|
{ src: 'maps.png', dest: 'maps.avif' }
|
||||||
|
];
|
||||||
|
|
||||||
|
const run = async () => {
|
||||||
|
const imagesDir = path.join(__dirname, '../public/assets/images');
|
||||||
|
let hasError = false;
|
||||||
|
|
||||||
|
for (const image of imagesToConvert) {
|
||||||
|
const inputPath = path.join(imagesDir, image.src);
|
||||||
|
const outputPath = path.join(imagesDir, image.dest);
|
||||||
|
|
||||||
|
if (!fs.existsSync(inputPath)) {
|
||||||
|
console.warn(`⚠️ Input file not found: ${inputPath}`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if output file exists and compare modification times
|
||||||
|
// Only convert if source is newer or destination doesn't exist
|
||||||
|
let shouldConvert = true;
|
||||||
|
if (fs.existsSync(outputPath)) {
|
||||||
|
const inputStat = fs.statSync(inputPath);
|
||||||
|
const outputStat = fs.statSync(outputPath);
|
||||||
|
if (inputStat.mtime <= outputStat.mtime) {
|
||||||
|
shouldConvert = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldConvert) {
|
||||||
|
try {
|
||||||
|
await sharp(inputPath)
|
||||||
|
.toFormat('avif')
|
||||||
|
.toFile(outputPath);
|
||||||
|
console.log(`✅ Converted ${image.src} to ${image.dest}`);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`❌ Error converting ${image.src}:`, error.message);
|
||||||
|
hasError = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Silent skip if already up to date to keep logs clean, or use verbose flag
|
||||||
|
// console.log(`Skipping ${image.src} (already up to date)`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasError) {
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
run();
|
||||||
26
scripts/convert-logo-to-avif.js
Normal file
26
scripts/convert-logo-to-avif.js
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
const sharp = require('sharp');
|
||||||
|
const path = require('path');
|
||||||
|
const fs = require('fs');
|
||||||
|
|
||||||
|
const run = async () => {
|
||||||
|
const inputPath = path.join(__dirname, '../public/assets/images/sh.png');
|
||||||
|
const outputPath = path.join(__dirname, '../public/assets/images/sh.avif');
|
||||||
|
|
||||||
|
if (!fs.existsSync(inputPath)) {
|
||||||
|
console.error('Input file not found:', inputPath);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await sharp(inputPath)
|
||||||
|
.toFormat('avif')
|
||||||
|
.toFile(outputPath);
|
||||||
|
console.log(`Successfully converted ${inputPath} to ${outputPath}`);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error converting image:', error);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
run();
|
||||||
|
|
||||||
@@ -722,7 +722,7 @@ class Content extends Component {
|
|||||||
justifyContent: 'center'
|
justifyContent: 'center'
|
||||||
}}>
|
}}>
|
||||||
<img
|
<img
|
||||||
src="/assets/images/seeds.jpg"
|
src="/assets/images/seeds.avif"
|
||||||
alt="Seeds"
|
alt="Seeds"
|
||||||
fetchPriority="high"
|
fetchPriority="high"
|
||||||
loading="eager"
|
loading="eager"
|
||||||
@@ -783,7 +783,7 @@ class Content extends Component {
|
|||||||
justifyContent: 'center'
|
justifyContent: 'center'
|
||||||
}}>
|
}}>
|
||||||
<img
|
<img
|
||||||
src="/assets/images/cutlings.jpg"
|
src="/assets/images/cutlings.avif"
|
||||||
alt="Stecklinge"
|
alt="Stecklinge"
|
||||||
fetchPriority="high"
|
fetchPriority="high"
|
||||||
loading="eager"
|
loading="eager"
|
||||||
|
|||||||
@@ -296,7 +296,7 @@ class Footer extends Component {
|
|||||||
>
|
>
|
||||||
<Box
|
<Box
|
||||||
component="img"
|
component="img"
|
||||||
src="/assets/images/gg.png"
|
src="/assets/images/gg.avif"
|
||||||
alt="Google Reviews"
|
alt="Google Reviews"
|
||||||
sx={{
|
sx={{
|
||||||
height: { xs: 50, md: 60 },
|
height: { xs: 50, md: 60 },
|
||||||
@@ -326,7 +326,7 @@ class Footer extends Component {
|
|||||||
>
|
>
|
||||||
<Box
|
<Box
|
||||||
component="img"
|
component="img"
|
||||||
src="/assets/images/maps.png"
|
src="/assets/images/maps.avif"
|
||||||
alt="Google Maps"
|
alt="Google Maps"
|
||||||
sx={{
|
sx={{
|
||||||
height: { xs: 40, md: 50 },
|
height: { xs: 40, md: 50 },
|
||||||
|
|||||||
@@ -163,8 +163,8 @@ const MainPageLayout = () => {
|
|||||||
|
|
||||||
const allContentBoxes = {
|
const allContentBoxes = {
|
||||||
home: [
|
home: [
|
||||||
{ title: t('sections.seeds'), image: "/assets/images/seeds.jpg", bgcolor: "#e1f0d3", link: "/Kategorie/Seeds" },
|
{ title: t('sections.seeds'), image: "/assets/images/seeds.avif", bgcolor: "#e1f0d3", link: "/Kategorie/Seeds" },
|
||||||
{ title: t('sections.stecklinge'), image: "/assets/images/cutlings.jpg", bgcolor: "#e8f5d6", link: "/Kategorie/Stecklinge" }
|
{ title: t('sections.stecklinge'), image: "/assets/images/cutlings.avif", bgcolor: "#e8f5d6", link: "/Kategorie/Stecklinge" }
|
||||||
],
|
],
|
||||||
aktionen: [
|
aktionen: [
|
||||||
{ title: t('sections.oilPress'), image: "/assets/images/presse.jpg", bgcolor: "#e1f0d3", link: "/presseverleih" },
|
{ title: t('sections.oilPress'), image: "/assets/images/presse.jpg", bgcolor: "#e1f0d3", link: "/presseverleih" },
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ const Logo = () => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
src="/assets/images/sh.png"
|
src="/assets/images/sh.avif"
|
||||||
alt="SH Logo"
|
alt="SH Logo"
|
||||||
width="108px"
|
width="108px"
|
||||||
height="45px"
|
height="45px"
|
||||||
|
|||||||
@@ -206,7 +206,7 @@ const config = {
|
|||||||
|
|
||||||
// Images
|
// Images
|
||||||
images: {
|
images: {
|
||||||
logo: "/assets/images/sh.png",
|
logo: "/assets/images/sh.avif",
|
||||||
placeholder: "/assets/images/nopicture.jpg"
|
placeholder: "/assets/images/nopicture.jpg"
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user