Compare commits
5 Commits
7b88376057
...
9aeaec0821
| Author | SHA1 | Date | |
|---|---|---|---|
| 9aeaec0821 | |||
| 42089a1b7b | |||
| 4a4d867ab9 | |||
| 3a84a78c43 | |||
| a77cd5d5c9 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,4 +2,5 @@
|
|||||||
app/.pnpm-store
|
app/.pnpm-store
|
||||||
app/node_modules
|
app/node_modules
|
||||||
app/dist
|
app/dist
|
||||||
|
app/public/sitemap.xml
|
||||||
**/*~lock*
|
**/*~lock*
|
||||||
@ -3,6 +3,7 @@ import type { Theme } from "@/contexts/ThemeContext";
|
|||||||
import { createHandler } from "@universal-middleware/fastify";
|
import { createHandler } from "@universal-middleware/fastify";
|
||||||
import { telefuncHandler } from "./server/telefunc-handler";
|
import { telefuncHandler } from "./server/telefunc-handler";
|
||||||
import { vikeHandler } from "./server/vike-handler";
|
import { vikeHandler } from "./server/vike-handler";
|
||||||
|
import { sitemap } from "./services/Sitemap";
|
||||||
import fastifyCookie from "@fastify/cookie";
|
import fastifyCookie from "@fastify/cookie";
|
||||||
import { fileURLToPath } from "node:url";
|
import { fileURLToPath } from "node:url";
|
||||||
import { dirname } from "node:path";
|
import { dirname } from "node:path";
|
||||||
@ -34,6 +35,8 @@ declare global {
|
|||||||
async function startServer() {
|
async function startServer() {
|
||||||
const app = Fastify();
|
const app = Fastify();
|
||||||
|
|
||||||
|
sitemap.generateSitemap();
|
||||||
|
|
||||||
app.register(fastifyCookie, {
|
app.register(fastifyCookie, {
|
||||||
secret: "todo",
|
secret: "todo",
|
||||||
hook: "onRequest",
|
hook: "onRequest",
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "tsx ./fastify-entry.ts",
|
"dev": "tsx ./fastify-entry.ts",
|
||||||
|
"dev:sitemap": "tsx --watch ./sitemap.ts",
|
||||||
"build": "vike build",
|
"build": "vike build",
|
||||||
"preview": "cross-env NODE_ENV=production tsx ./fastify-entry.ts",
|
"preview": "cross-env NODE_ENV=production tsx ./fastify-entry.ts",
|
||||||
"lint": "eslint .",
|
"lint": "eslint .",
|
||||||
|
|||||||
154
app/services/Sitemap.ts
Normal file
154
app/services/Sitemap.ts
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
import { navigation } from "@/lib/navigation";
|
||||||
|
import path from "path";
|
||||||
|
import fs from "fs";
|
||||||
|
|
||||||
|
const __dirname = path.resolve();
|
||||||
|
|
||||||
|
const getBaseUrl = () => {
|
||||||
|
if (process.env.NODE_ENV === "production") {
|
||||||
|
return "https://memento-dev.fr";
|
||||||
|
}
|
||||||
|
|
||||||
|
return `http://localhost:${process.env.PORT || 3000}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
type SitemapElement = {
|
||||||
|
location: string;
|
||||||
|
lastmod: string;
|
||||||
|
priority: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Sitemap {
|
||||||
|
private readonly pagesPath = path.join(__dirname, "pages");
|
||||||
|
private readonly dataPath = path.join(__dirname, "data");
|
||||||
|
private readonly sitemapPath = path.join(__dirname, "public", "sitemap.xml");
|
||||||
|
private readonly lastModified = new Date().toISOString();
|
||||||
|
private readonly baseUrl = getBaseUrl();
|
||||||
|
|
||||||
|
private urls: SitemapElement[] = [];
|
||||||
|
private sitemap: string = "";
|
||||||
|
|
||||||
|
private static instance: Sitemap;
|
||||||
|
|
||||||
|
private constructor() {}
|
||||||
|
|
||||||
|
public static getInstance(): Sitemap {
|
||||||
|
if (!Sitemap.instance) {
|
||||||
|
Sitemap.instance = new Sitemap();
|
||||||
|
}
|
||||||
|
return Sitemap.instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private resetMemory(): void {
|
||||||
|
this.sitemap = "";
|
||||||
|
this.urls = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
private prependSitemap(): void {
|
||||||
|
this.sitemap = `<?xml version="1.0" encoding="UTF-8"?>`;
|
||||||
|
this.sitemap += `<urlset xmlns="http://www.sitemaps.org/schemas/sitemap-image/1.1">`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private appendSitemap(): void {
|
||||||
|
this.sitemap += `</urlset>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private addSitemapElement(url: SitemapElement): void {
|
||||||
|
this.sitemap += `<url>`;
|
||||||
|
this.sitemap += `<loc>${url.location}</loc>`;
|
||||||
|
this.sitemap += `<lastmod>${url.lastmod || this.lastModified}</lastmod>`;
|
||||||
|
this.sitemap += `<priority>${url.priority}</priority>`;
|
||||||
|
this.sitemap += `</url>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private buildSitemap(): void {
|
||||||
|
this.prependSitemap();
|
||||||
|
this.urls.forEach(this.addSitemapElement.bind(this));
|
||||||
|
this.appendSitemap();
|
||||||
|
}
|
||||||
|
|
||||||
|
private saveSitemap(): void {
|
||||||
|
fs.writeFileSync(this.sitemapPath, this.sitemap, "utf8");
|
||||||
|
}
|
||||||
|
|
||||||
|
private loadPriority(href: string): string {
|
||||||
|
const isRootUrl = ["/", ""].includes(href);
|
||||||
|
|
||||||
|
if (isRootUrl) return "1.0";
|
||||||
|
const countOfSlashes = (href.match(/\//g) || []).length;
|
||||||
|
return (1 - countOfSlashes * 0.1).toFixed(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private loadLastModified(href: string): string {
|
||||||
|
return this.lastModified;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getFileServerLocation(href: string) {
|
||||||
|
const jsxHref = ["/politique-de-confidentialite", "/mentions-legales"];
|
||||||
|
const isJsxFile = jsxHref.includes(href);
|
||||||
|
|
||||||
|
if (isJsxFile) {
|
||||||
|
return path.join(this.pagesPath, href.replace("/", ""), "+Page.tsx");
|
||||||
|
}
|
||||||
|
|
||||||
|
return path.join(this.pagesPath, href.replace("/", ""), "page.md");
|
||||||
|
}
|
||||||
|
|
||||||
|
private loadSubitems(subitems: (typeof navigation)[number]["links"][number]["subitems"]): void {
|
||||||
|
subitems.forEach((subitem) => {
|
||||||
|
const fileLocation = this.getFileServerLocation(subitem.href);
|
||||||
|
console.log("File location:", fileLocation);
|
||||||
|
|
||||||
|
const priority = this.loadPriority(subitem.href);
|
||||||
|
const lastmod = this.loadLastModified(subitem.href);
|
||||||
|
const location = `${this.baseUrl}${subitem.href}`;
|
||||||
|
|
||||||
|
this.urls.push({
|
||||||
|
location,
|
||||||
|
lastmod,
|
||||||
|
priority,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private loadSection(section: (typeof navigation)[number]): void {
|
||||||
|
section.links.forEach((link) => {
|
||||||
|
if (link.subitems.length > 0) {
|
||||||
|
return this.loadSubitems(link.subitems);
|
||||||
|
}
|
||||||
|
|
||||||
|
const priority = this.loadPriority(link.href);
|
||||||
|
const lastmod = this.loadLastModified(link.href);
|
||||||
|
const location = `${this.baseUrl}${link.href}`;
|
||||||
|
|
||||||
|
this.urls.push({
|
||||||
|
location,
|
||||||
|
lastmod,
|
||||||
|
priority,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private loadUrls(): void {
|
||||||
|
navigation.forEach(this.loadSection.bind(this));
|
||||||
|
|
||||||
|
this.urls = Array.from(new Set(this.urls)).sort((a, b) => {
|
||||||
|
return a.location.localeCompare(b.location);
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("Loaded URLs:", this.urls);
|
||||||
|
}
|
||||||
|
|
||||||
|
public generateSitemap(): void {
|
||||||
|
console.log("Generating sitemap...");
|
||||||
|
|
||||||
|
this.resetMemory();
|
||||||
|
this.loadUrls();
|
||||||
|
this.buildSitemap();
|
||||||
|
this.saveSitemap();
|
||||||
|
|
||||||
|
console.log("Sitemap generated successfully.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const sitemap = Sitemap.getInstance();
|
||||||
3
app/sitemap.ts
Normal file
3
app/sitemap.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import { sitemap } from "./services/Sitemap";
|
||||||
|
|
||||||
|
sitemap.generateSitemap();
|
||||||
Loading…
Reference in New Issue
Block a user