meno-core 1.0.7 ā 1.0.9
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/build-static.ts +58 -5
- package/lib/shared/fontLoader.ts +4 -1
- package/package.json +1 -1
package/build-static.ts
CHANGED
|
@@ -150,6 +150,37 @@ function getDisplayPath(
|
|
|
150
150
|
return slug === "" ? `/${locale}` : `/${locale}/${slug}`;
|
|
151
151
|
}
|
|
152
152
|
|
|
153
|
+
/**
|
|
154
|
+
* Generate robots.txt with sensible defaults
|
|
155
|
+
*/
|
|
156
|
+
async function generateRobotsTxt(siteUrl: string, distDir: string): Promise<void> {
|
|
157
|
+
const content = `User-agent: *
|
|
158
|
+
Allow: /
|
|
159
|
+
|
|
160
|
+
Sitemap: ${siteUrl}/sitemap.xml
|
|
161
|
+
`;
|
|
162
|
+
await writeFile(join(distDir, 'robots.txt'), content, 'utf-8');
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Generate sitemap.xml from collected URLs
|
|
167
|
+
*/
|
|
168
|
+
async function generateSitemap(urls: string[], siteUrl: string, distDir: string): Promise<void> {
|
|
169
|
+
// Sort URLs for deterministic output
|
|
170
|
+
const sortedUrls = [...urls].sort();
|
|
171
|
+
|
|
172
|
+
const urlEntries = sortedUrls
|
|
173
|
+
.map(url => ` <url><loc>${siteUrl}${url}</loc></url>`)
|
|
174
|
+
.join('\n');
|
|
175
|
+
|
|
176
|
+
const content = `<?xml version="1.0" encoding="UTF-8"?>
|
|
177
|
+
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
|
178
|
+
${urlEntries}
|
|
179
|
+
</urlset>
|
|
180
|
+
`;
|
|
181
|
+
await writeFile(join(distDir, 'sitemap.xml'), content, 'utf-8');
|
|
182
|
+
}
|
|
183
|
+
|
|
153
184
|
/**
|
|
154
185
|
* Clean dist directory, keeping only production files
|
|
155
186
|
*/
|
|
@@ -232,7 +263,9 @@ async function buildCMSTemplates(
|
|
|
232
263
|
i18nConfig: I18nConfig,
|
|
233
264
|
slugMappings: SlugMap[],
|
|
234
265
|
distDir: string,
|
|
235
|
-
cmsService: CMSService
|
|
266
|
+
cmsService: CMSService,
|
|
267
|
+
generatedUrls: Set<string>,
|
|
268
|
+
siteUrl?: string
|
|
236
269
|
): Promise<{ success: number; errors: number }> {
|
|
237
270
|
let successCount = 0;
|
|
238
271
|
let errorCount = 0;
|
|
@@ -277,7 +310,7 @@ async function buildCMSTemplates(
|
|
|
277
310
|
for (const item of items) {
|
|
278
311
|
for (const localeConfig of i18nConfig.locales) {
|
|
279
312
|
const locale = localeConfig.code;
|
|
280
|
-
const baseUrl = "";
|
|
313
|
+
const baseUrl = siteUrl || "";
|
|
281
314
|
const itemPath = buildCMSItemPath(cmsSchema.urlPattern, item, cmsSchema.slugField, locale, i18nConfig);
|
|
282
315
|
|
|
283
316
|
// Generate HTML with JS returned separately (CSP-compliant)
|
|
@@ -313,6 +346,7 @@ async function buildCMSTemplates(
|
|
|
313
346
|
await writeFile(outputPath, finalHtml, 'utf-8');
|
|
314
347
|
|
|
315
348
|
const displayPath = locale === i18nConfig.defaultLocale ? itemPath : `/${locale}${itemPath}`;
|
|
349
|
+
generatedUrls.add(displayPath);
|
|
316
350
|
console.log(` ā
${displayPath}`);
|
|
317
351
|
successCount++;
|
|
318
352
|
}
|
|
@@ -333,7 +367,11 @@ async function buildStaticPages(): Promise<void> {
|
|
|
333
367
|
console.log("šļø Building static HTML files...\n");
|
|
334
368
|
|
|
335
369
|
// Load project config first
|
|
336
|
-
await loadProjectConfig();
|
|
370
|
+
const projectConfig = await loadProjectConfig();
|
|
371
|
+
const siteUrl = (projectConfig as { siteUrl?: string }).siteUrl?.replace(/\/$/, ''); // Remove trailing slash
|
|
372
|
+
|
|
373
|
+
// Track all generated URLs for sitemap
|
|
374
|
+
const generatedUrls = new Set<string>();
|
|
337
375
|
|
|
338
376
|
// Load i18n config for multi-locale build
|
|
339
377
|
const i18nConfig = await loadI18nConfig();
|
|
@@ -446,7 +484,7 @@ async function buildStaticPages(): Promise<void> {
|
|
|
446
484
|
// Generate HTML for each locale
|
|
447
485
|
for (const localeConfig of i18nConfig.locales) {
|
|
448
486
|
const locale = localeConfig.code;
|
|
449
|
-
const baseUrl = "";
|
|
487
|
+
const baseUrl = siteUrl || "";
|
|
450
488
|
|
|
451
489
|
// Build the URL path that will be used for this locale
|
|
452
490
|
const urlPath = getDisplayPath(basePath, locale, i18nConfig.defaultLocale, slugs);
|
|
@@ -483,6 +521,7 @@ async function buildStaticPages(): Promise<void> {
|
|
|
483
521
|
|
|
484
522
|
await writeFile(outputPath, finalHtml, "utf-8");
|
|
485
523
|
|
|
524
|
+
generatedUrls.add(urlPath);
|
|
486
525
|
console.log(`ā
Built: ${urlPath} ā ${outputPath}`);
|
|
487
526
|
successCount++;
|
|
488
527
|
}
|
|
@@ -501,11 +540,22 @@ async function buildStaticPages(): Promise<void> {
|
|
|
501
540
|
i18nConfig,
|
|
502
541
|
slugMappings,
|
|
503
542
|
distDir,
|
|
504
|
-
cmsService
|
|
543
|
+
cmsService,
|
|
544
|
+
generatedUrls,
|
|
545
|
+
siteUrl
|
|
505
546
|
);
|
|
506
547
|
successCount += cmsResult.success;
|
|
507
548
|
errorCount += cmsResult.errors;
|
|
508
549
|
|
|
550
|
+
// Generate SEO files (robots.txt and sitemap.xml)
|
|
551
|
+
if (siteUrl) {
|
|
552
|
+
await generateRobotsTxt(siteUrl, distDir);
|
|
553
|
+
await generateSitemap([...generatedUrls], siteUrl, distDir);
|
|
554
|
+
console.log(`\nš SEO files generated (robots.txt, sitemap.xml)`);
|
|
555
|
+
} else {
|
|
556
|
+
console.warn(`\nā ļø Skipping SEO files: siteUrl not configured in project.config.json`);
|
|
557
|
+
}
|
|
558
|
+
|
|
509
559
|
console.log("\n" + "=".repeat(50));
|
|
510
560
|
console.log(`⨠Build complete!`);
|
|
511
561
|
console.log(` ā
Success: ${successCount}`);
|
|
@@ -520,6 +570,9 @@ async function buildStaticPages(): Promise<void> {
|
|
|
520
570
|
if (existsSync(functionsDir)) {
|
|
521
571
|
console.log(` - functions/ (Cloudflare Pages Functions)`);
|
|
522
572
|
}
|
|
573
|
+
if (siteUrl) {
|
|
574
|
+
console.log(` - robots.txt, sitemap.xml (SEO)`);
|
|
575
|
+
}
|
|
523
576
|
console.log(` - No React, no client-router ā`);
|
|
524
577
|
}
|
|
525
578
|
|
package/lib/shared/fontLoader.ts
CHANGED
|
@@ -6,10 +6,12 @@ export interface FontConfig {
|
|
|
6
6
|
weight?: number;
|
|
7
7
|
weightMax?: number; // If set, font is variable with weight range [weight, weightMax]
|
|
8
8
|
style?: 'normal' | 'italic';
|
|
9
|
+
fontDisplay?: 'auto' | 'block' | 'swap' | 'fallback' | 'optional';
|
|
9
10
|
}
|
|
10
11
|
|
|
11
12
|
interface ProjectConfig {
|
|
12
13
|
fonts?: FontConfig[];
|
|
14
|
+
siteUrl?: string;
|
|
13
15
|
[key: string]: unknown;
|
|
14
16
|
}
|
|
15
17
|
|
|
@@ -67,6 +69,7 @@ export function generateFontCSS(): string {
|
|
|
67
69
|
const weight = font.weight ?? 400;
|
|
68
70
|
const weightMax = font.weightMax;
|
|
69
71
|
const style = font.style ?? 'normal';
|
|
72
|
+
const fontDisplay = font.fontDisplay;
|
|
70
73
|
|
|
71
74
|
// Variable fonts use weight range syntax: "100 900"
|
|
72
75
|
const fontWeight = weightMax != null ? `${weight} ${weightMax}` : weight;
|
|
@@ -75,7 +78,7 @@ export function generateFontCSS(): string {
|
|
|
75
78
|
font-family: '${family}';
|
|
76
79
|
src: url('${font.path}') format('${format}');
|
|
77
80
|
font-weight: ${fontWeight};
|
|
78
|
-
font-style: ${style}
|
|
81
|
+
font-style: ${style};${fontDisplay ? `\n font-display: ${fontDisplay};` : ''}
|
|
79
82
|
}`;
|
|
80
83
|
})
|
|
81
84
|
.join('\n\n');
|