bertui 0.4.4 → 0.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/build/image-optimizer.js +88 -13
- package/src/build.js +21 -4
package/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// bertui/src/build/image-optimizer.js -
|
|
1
|
+
// bertui/src/build/image-optimizer.js - FIXED VERSION
|
|
2
2
|
import { join, extname } from 'path';
|
|
3
3
|
import { existsSync, mkdirSync, readdirSync, cpSync } from 'fs';
|
|
4
4
|
import logger from '../logger/logger.js';
|
|
@@ -46,7 +46,18 @@ export async function optimizeImages(srcDir, outDir) {
|
|
|
46
46
|
let optimized = 0;
|
|
47
47
|
let totalSaved = 0;
|
|
48
48
|
|
|
49
|
-
logger.info(
|
|
49
|
+
logger.info(`🖼️ Optimizing images from ${srcDir} to ${outDir}...`);
|
|
50
|
+
|
|
51
|
+
// Check if source directory exists
|
|
52
|
+
if (!existsSync(srcDir)) {
|
|
53
|
+
logger.warn(`⚠️ Source directory not found: ${srcDir}`);
|
|
54
|
+
return { optimized: 0, saved: 0 };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Create output directory if it doesn't exist
|
|
58
|
+
if (!existsSync(outDir)) {
|
|
59
|
+
mkdirSync(outDir, { recursive: true });
|
|
60
|
+
}
|
|
50
61
|
|
|
51
62
|
async function processDirectory(dir, targetDir) {
|
|
52
63
|
const entries = readdirSync(dir, { withFileTypes: true });
|
|
@@ -56,10 +67,12 @@ export async function optimizeImages(srcDir, outDir) {
|
|
|
56
67
|
const destPath = join(targetDir, entry.name);
|
|
57
68
|
|
|
58
69
|
if (entry.isDirectory()) {
|
|
59
|
-
|
|
60
|
-
|
|
70
|
+
// Create subdirectory in target
|
|
71
|
+
const subDestPath = join(targetDir, entry.name);
|
|
72
|
+
if (!existsSync(subDestPath)) {
|
|
73
|
+
mkdirSync(subDestPath, { recursive: true });
|
|
61
74
|
}
|
|
62
|
-
await processDirectory(srcPath,
|
|
75
|
+
await processDirectory(srcPath, subDestPath);
|
|
63
76
|
} else if (entry.isFile()) {
|
|
64
77
|
const ext = extname(entry.name).toLowerCase();
|
|
65
78
|
|
|
@@ -77,7 +90,12 @@ export async function optimizeImages(srcDir, outDir) {
|
|
|
77
90
|
} catch (error) {
|
|
78
91
|
logger.warn(`⚠️ Failed to optimize ${entry.name}: ${error.message}`);
|
|
79
92
|
// Fallback: just copy the file
|
|
80
|
-
|
|
93
|
+
try {
|
|
94
|
+
cpSync(srcPath, destPath);
|
|
95
|
+
logger.debug(`📋 Copied ${entry.name} (fallback)`);
|
|
96
|
+
} catch (copyError) {
|
|
97
|
+
logger.error(`❌ Failed to copy ${entry.name}: ${copyError.message}`);
|
|
98
|
+
}
|
|
81
99
|
}
|
|
82
100
|
}
|
|
83
101
|
}
|
|
@@ -90,17 +108,45 @@ export async function optimizeImages(srcDir, outDir) {
|
|
|
90
108
|
logger.success(
|
|
91
109
|
`✅ Optimized ${optimized} images (saved ${(totalSaved / 1024).toFixed(2)}KB total)`
|
|
92
110
|
);
|
|
111
|
+
} else {
|
|
112
|
+
logger.info(`📋 No images optimized (copied ${countFilesInDir(outDir)} files)`);
|
|
93
113
|
}
|
|
94
114
|
|
|
95
115
|
return { optimized, saved: totalSaved };
|
|
96
116
|
}
|
|
97
117
|
|
|
118
|
+
/**
|
|
119
|
+
* Count files in directory (for logging)
|
|
120
|
+
*/
|
|
121
|
+
function countFilesInDir(dir) {
|
|
122
|
+
if (!existsSync(dir)) return 0;
|
|
123
|
+
|
|
124
|
+
let count = 0;
|
|
125
|
+
const entries = readdirSync(dir, { withFileTypes: true });
|
|
126
|
+
|
|
127
|
+
for (const entry of entries) {
|
|
128
|
+
if (entry.isFile()) {
|
|
129
|
+
count++;
|
|
130
|
+
} else if (entry.isDirectory()) {
|
|
131
|
+
count += countFilesInDir(join(dir, entry.name));
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return count;
|
|
136
|
+
}
|
|
137
|
+
|
|
98
138
|
/**
|
|
99
139
|
* Optimize a single image using WASM codecs
|
|
100
140
|
*/
|
|
101
141
|
async function optimizeImage(srcPath, destPath) {
|
|
102
142
|
const ext = extname(srcPath).toLowerCase();
|
|
103
143
|
const originalFile = Bun.file(srcPath);
|
|
144
|
+
|
|
145
|
+
// Check if file exists
|
|
146
|
+
if (!await originalFile.exists()) {
|
|
147
|
+
throw new Error(`File not found: ${srcPath}`);
|
|
148
|
+
}
|
|
149
|
+
|
|
104
150
|
const originalSize = originalFile.size;
|
|
105
151
|
|
|
106
152
|
try {
|
|
@@ -140,6 +186,10 @@ async function optimizeImage(srcPath, destPath) {
|
|
|
140
186
|
// WebP optimization
|
|
141
187
|
const imageData = await webpDecode(originalBuffer);
|
|
142
188
|
optimizedBuffer = await webpEncode(imageData, { quality: 85 });
|
|
189
|
+
} else {
|
|
190
|
+
// Unsupported format, just copy
|
|
191
|
+
cpSync(srcPath, destPath);
|
|
192
|
+
return null;
|
|
143
193
|
}
|
|
144
194
|
|
|
145
195
|
// Only save if we actually reduced the size
|
|
@@ -184,9 +234,20 @@ export async function checkOptimizationTools() {
|
|
|
184
234
|
* Copy images without optimization (fallback)
|
|
185
235
|
*/
|
|
186
236
|
export function copyImages(srcDir, outDir) {
|
|
187
|
-
const imageExtensions = ['.png', '.jpg', '.jpeg', '.webp', '.gif', '.svg', '.avif'];
|
|
237
|
+
const imageExtensions = ['.png', '.jpg', '.jpeg', '.webp', '.gif', '.svg', '.avif', '.ico'];
|
|
188
238
|
let copied = 0;
|
|
189
239
|
|
|
240
|
+
// Check if source directory exists
|
|
241
|
+
if (!existsSync(srcDir)) {
|
|
242
|
+
logger.warn(`⚠️ Source directory not found: ${srcDir}`);
|
|
243
|
+
return 0;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Create output directory if it doesn't exist
|
|
247
|
+
if (!existsSync(outDir)) {
|
|
248
|
+
mkdirSync(outDir, { recursive: true });
|
|
249
|
+
}
|
|
250
|
+
|
|
190
251
|
function processDirectory(dir, targetDir) {
|
|
191
252
|
const entries = readdirSync(dir, { withFileTypes: true });
|
|
192
253
|
|
|
@@ -195,22 +256,36 @@ export function copyImages(srcDir, outDir) {
|
|
|
195
256
|
const destPath = join(targetDir, entry.name);
|
|
196
257
|
|
|
197
258
|
if (entry.isDirectory()) {
|
|
198
|
-
|
|
199
|
-
|
|
259
|
+
// Create subdirectory in target
|
|
260
|
+
const subDestPath = join(targetDir, entry.name);
|
|
261
|
+
if (!existsSync(subDestPath)) {
|
|
262
|
+
mkdirSync(subDestPath, { recursive: true });
|
|
200
263
|
}
|
|
201
|
-
|
|
264
|
+
// FIXED: Use destPath, not targetDir
|
|
265
|
+
processDirectory(srcPath, subDestPath);
|
|
202
266
|
} else if (entry.isFile()) {
|
|
203
267
|
const ext = extname(entry.name).toLowerCase();
|
|
204
268
|
|
|
205
269
|
if (imageExtensions.includes(ext)) {
|
|
206
|
-
|
|
207
|
-
|
|
270
|
+
try {
|
|
271
|
+
cpSync(srcPath, destPath);
|
|
272
|
+
copied++;
|
|
273
|
+
logger.debug(`📋 Copied ${entry.name}`);
|
|
274
|
+
} catch (error) {
|
|
275
|
+
logger.warn(`Failed to copy ${entry.name}: ${error.message}`);
|
|
276
|
+
}
|
|
208
277
|
}
|
|
209
278
|
}
|
|
210
279
|
}
|
|
211
280
|
}
|
|
212
281
|
|
|
213
282
|
processDirectory(srcDir, outDir);
|
|
214
|
-
|
|
283
|
+
|
|
284
|
+
if (copied > 0) {
|
|
285
|
+
logger.info(`📋 Copied ${copied} images without optimization`);
|
|
286
|
+
} else {
|
|
287
|
+
logger.warn(`⚠️ No images found in ${srcDir}`);
|
|
288
|
+
}
|
|
289
|
+
|
|
215
290
|
return copied;
|
|
216
291
|
}
|
package/src/build.js
CHANGED
|
@@ -124,6 +124,7 @@ export async function buildProduction(options = {}) {
|
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
+
// ✅ FIX 3: Enhanced asset copying with proper directory structure
|
|
127
128
|
// ✅ FIX 3: Enhanced asset copying with proper directory structure
|
|
128
129
|
async function copyAllStaticAssets(root, outDir, optimize = true) {
|
|
129
130
|
const publicDir = join(root, 'public');
|
|
@@ -132,9 +133,15 @@ async function copyAllStaticAssets(root, outDir, optimize = true) {
|
|
|
132
133
|
let assetsCopied = 0;
|
|
133
134
|
let assetsOptimized = 0;
|
|
134
135
|
|
|
136
|
+
logger.info(`🔍 Checking source directories...`);
|
|
137
|
+
logger.info(` public/: ${existsSync(publicDir) ? '✅ exists' : '❌ not found'}`);
|
|
138
|
+
logger.info(` src/images/: ${existsSync(srcImagesDir) ? '✅ exists' : '❌ not found'}`);
|
|
139
|
+
|
|
135
140
|
// Create images directory in dist/
|
|
136
141
|
const distImagesDir = join(outDir, 'images');
|
|
137
|
-
|
|
142
|
+
if (!existsSync(distImagesDir)) {
|
|
143
|
+
mkdirSync(distImagesDir, { recursive: true });
|
|
144
|
+
}
|
|
138
145
|
|
|
139
146
|
// Copy from public/ to root of dist/
|
|
140
147
|
if (existsSync(publicDir)) {
|
|
@@ -145,26 +152,36 @@ async function copyAllStaticAssets(root, outDir, optimize = true) {
|
|
|
145
152
|
} else {
|
|
146
153
|
assetsCopied += copyImages(publicDir, outDir);
|
|
147
154
|
}
|
|
155
|
+
} else {
|
|
156
|
+
logger.info('No public/ directory found, skipping...');
|
|
148
157
|
}
|
|
149
158
|
|
|
150
159
|
// ✅ FIX: Copy from src/images/ to dist/images/
|
|
151
160
|
if (existsSync(srcImagesDir)) {
|
|
152
|
-
logger.info(
|
|
161
|
+
logger.info(`Copying src/images/ to dist/images/...`);
|
|
162
|
+
|
|
163
|
+
// Debug: List files in src/images/
|
|
164
|
+
const files = readdirSync(srcImagesDir);
|
|
165
|
+
logger.info(`Found ${files.length} items in src/images/: ${files.join(', ')}`);
|
|
166
|
+
|
|
153
167
|
if (optimize) {
|
|
154
168
|
const result = await optimizeImages(srcImagesDir, distImagesDir);
|
|
155
169
|
assetsOptimized += result.optimized;
|
|
156
170
|
} else {
|
|
157
171
|
assetsCopied += copyImages(srcImagesDir, distImagesDir);
|
|
158
172
|
}
|
|
173
|
+
} else {
|
|
174
|
+
logger.info('No src/images/ directory found, skipping...');
|
|
159
175
|
}
|
|
160
176
|
|
|
161
177
|
if (optimize && assetsOptimized > 0) {
|
|
162
178
|
logger.success(`🎨 Optimized ${assetsOptimized} images with WASM codecs`);
|
|
163
|
-
} else {
|
|
179
|
+
} else if (assetsCopied > 0) {
|
|
164
180
|
logger.success(`📋 Copied ${assetsCopied} static assets`);
|
|
181
|
+
} else {
|
|
182
|
+
logger.warn(`⚠️ No static assets found or copied`);
|
|
165
183
|
}
|
|
166
184
|
}
|
|
167
|
-
|
|
168
185
|
async function buildAllCSS(root, outDir) {
|
|
169
186
|
const srcStylesDir = join(root, 'src', 'styles');
|
|
170
187
|
const stylesOutDir = join(outDir, 'styles');
|