mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
refactor: implement scalable asset manifest system for dynamic images
Created build-time script to generate TypeScript manifest from public/assets, avoiding import.meta.glob limitations. Images stay in public/ for scalability (supports hundreds), while components get type-safe auto-discovery. Manifest auto-regenerates before builds.
This commit is contained in:
@@ -49,6 +49,9 @@
|
||||
"zustand": "4.4.3"
|
||||
},
|
||||
"scripts": {
|
||||
"generate:assets": "node scripts/generate-asset-manifest.js",
|
||||
"prebuild": "yarn generate:assets",
|
||||
"prestart": "yarn generate:assets",
|
||||
"start": "vite",
|
||||
"build": "cross-env PUBLIC_URL=./ GENERATE_SOURCEMAP=false vite build",
|
||||
"build:preload": "vite build --config electron/vite.preload.config.js",
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import { readdirSync, writeFileSync, mkdirSync } from 'fs';
|
||||
import { join, dirname } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
const publicDir = join(__dirname, '..', 'public');
|
||||
|
||||
// Scan for banners
|
||||
const bannersDir = join(publicDir, 'assets', 'banners');
|
||||
const banners = readdirSync(bannersDir)
|
||||
.filter((file) => /^banner-.*\.(jpg|jpeg|gif|png)$/i.test(file))
|
||||
.map((file) => `assets/banners/${file}`);
|
||||
|
||||
// Scan for not-found images
|
||||
const notFoundDir = join(publicDir, 'assets', 'not-found');
|
||||
const notFoundImages = readdirSync(notFoundDir)
|
||||
.filter((file) => /^not-found-.*\.(jpg|jpeg|gif|png)$/i.test(file))
|
||||
.map((file) => `assets/not-found/${file}`);
|
||||
|
||||
// Generate TypeScript file
|
||||
const output = `// Auto-generated file - do not edit manually
|
||||
// Run 'node scripts/generate-asset-manifest.js' to regenerate
|
||||
// This file is generated from public/assets/ directory
|
||||
|
||||
export const BANNERS = ${JSON.stringify(banners, null, 2)} as const;
|
||||
|
||||
export const NOT_FOUND_IMAGES = ${JSON.stringify(notFoundImages, null, 2)} as const;
|
||||
`;
|
||||
|
||||
// Ensure directory exists
|
||||
const generatedDir = join(__dirname, '..', 'src', 'generated');
|
||||
mkdirSync(generatedDir, { recursive: true });
|
||||
|
||||
const outputPath = join(generatedDir, 'asset-manifest.ts');
|
||||
writeFileSync(outputPath, output, 'utf8');
|
||||
|
||||
console.log(`✅ Generated asset manifest with ${banners.length} banners and ${notFoundImages.length} not-found images`);
|
||||
@@ -12,17 +12,10 @@ import useIsSubplebbitOffline from '../../hooks/use-is-subplebbit-offline';
|
||||
import { shouldShowSnow } from '../../lib/snow';
|
||||
import Tooltip from '../tooltip';
|
||||
import _ from 'lodash';
|
||||
|
||||
// Dynamically import all banner images at build time
|
||||
const bannerModules = import.meta.glob('/public/assets/banners/banner-*.{jpg,jpeg,gif,png}', {
|
||||
eager: true,
|
||||
query: '?url',
|
||||
import: 'default',
|
||||
});
|
||||
const bannerPaths = Object.values(bannerModules) as string[];
|
||||
import { BANNERS } from '../../generated/asset-manifest';
|
||||
|
||||
const ImageBanner = () => {
|
||||
const [banner] = useState(() => bannerPaths[Math.floor(Math.random() * bannerPaths.length)]);
|
||||
const [banner] = useState(() => BANNERS[Math.floor(Math.random() * BANNERS.length)]);
|
||||
|
||||
return <img src={banner} alt='' />;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
# Generated Files
|
||||
|
||||
This directory contains auto-generated TypeScript files. Do not edit these files manually.
|
||||
|
||||
## asset-manifest.ts
|
||||
|
||||
Auto-generated manifest of all banner and not-found images from `public/assets/`.
|
||||
|
||||
**To regenerate:**
|
||||
```bash
|
||||
yarn generate:assets
|
||||
```
|
||||
|
||||
**Auto-regenerated:**
|
||||
- Before every build (`yarn build`)
|
||||
- Before dev server start (`yarn start`)
|
||||
|
||||
**To add new banners:**
|
||||
1. Add files to `public/assets/banners/` following the pattern `banner-*.{jpg,jpeg,gif,png}`
|
||||
2. Run `yarn generate:assets` (or it will auto-run on next build/start)
|
||||
|
||||
**To add new not-found images:**
|
||||
1. Add files to `public/assets/not-found/` following the pattern `not-found-*.{jpg,jpeg,gif,png}`
|
||||
2. Run `yarn generate:assets` (or it will auto-run on next build/start)
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
// Auto-generated file - do not edit manually
|
||||
// Run 'node scripts/generate-asset-manifest.js' to regenerate
|
||||
// This file is generated from public/assets/ directory
|
||||
|
||||
export const BANNERS = [
|
||||
'assets/banners/banner-1.jpg',
|
||||
'assets/banners/banner-2.jpg',
|
||||
'assets/banners/banner-3.gif',
|
||||
'assets/banners/banner-4.gif',
|
||||
'assets/banners/banner-5.png',
|
||||
] as const;
|
||||
|
||||
export const NOT_FOUND_IMAGES = ['assets/not-found/not-found-1.png'] as const;
|
||||
@@ -3,26 +3,10 @@ import { Link, useLocation } from 'react-router-dom';
|
||||
import useSubplebbitsStore from '@plebbit/plebbit-react-hooks/dist/stores/subplebbits';
|
||||
import { HomeLogo } from '../home';
|
||||
import styles from './not-found.module.css';
|
||||
|
||||
// Dynamically import all not-found images at build time
|
||||
const notFoundModules = import.meta.glob('/public/assets/not-found/not-found-*.{jpg,jpeg,gif,png}', {
|
||||
eager: true,
|
||||
query: '?url',
|
||||
import: 'default',
|
||||
});
|
||||
const notFoundPaths = Object.values(notFoundModules) as string[];
|
||||
import { NOT_FOUND_IMAGES } from '../../generated/asset-manifest';
|
||||
|
||||
const NotFoundImage = () => {
|
||||
const [imagePath] = useState(() => {
|
||||
if (notFoundPaths.length === 0) {
|
||||
return null;
|
||||
}
|
||||
return notFoundPaths[Math.floor(Math.random() * notFoundPaths.length)];
|
||||
});
|
||||
|
||||
if (!imagePath) {
|
||||
return null;
|
||||
}
|
||||
const [imagePath] = useState(() => NOT_FOUND_IMAGES[Math.floor(Math.random() * NOT_FOUND_IMAGES.length)]);
|
||||
|
||||
return <img src={imagePath} alt='' />;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user