Compare commits
No commits in common. "0d1e4910fb7f9c1466ff2acb004c173559ea9eb3" and "7b88376057da80444164f6f33d7a1ac8698dd145" have entirely different histories.
0d1e4910fb
...
7b88376057
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,5 +2,4 @@
|
||||
app/.pnpm-store
|
||||
app/node_modules
|
||||
app/dist
|
||||
app/public/sitemap.xml
|
||||
**/*~lock*
|
||||
@ -70,7 +70,7 @@ export function PrevNextLinks() {
|
||||
|
||||
// In case the next page is the same as the current page (in subitems),
|
||||
// we need to skip it to get the correct next page.
|
||||
if (nextPage?.href === urlPathname) {
|
||||
if (nextPage.href === urlPathname) {
|
||||
nextPage = allLinks[linkIndex + 2] || null;
|
||||
}
|
||||
|
||||
|
||||
@ -3,7 +3,6 @@ import type { Theme } from "@/contexts/ThemeContext";
|
||||
import { createHandler } from "@universal-middleware/fastify";
|
||||
import { telefuncHandler } from "./server/telefunc-handler";
|
||||
import { vikeHandler } from "./server/vike-handler";
|
||||
import { sitemap } from "./services/Sitemap";
|
||||
import fastifyCookie from "@fastify/cookie";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { dirname } from "node:path";
|
||||
@ -35,8 +34,6 @@ declare global {
|
||||
async function startServer() {
|
||||
const app = Fastify();
|
||||
|
||||
sitemap.generateSitemap();
|
||||
|
||||
app.register(fastifyCookie, {
|
||||
secret: "todo",
|
||||
hook: "onRequest",
|
||||
|
||||
@ -133,7 +133,7 @@ export function doesLinkSubitemExist(link: NavigationLink, subitemHref: string):
|
||||
return link.subitems.some((subitem) => subitem.href === subitemHref);
|
||||
}
|
||||
|
||||
export function findNavigationLink(namespace: string, href?: string): NavigationLink | undefined {
|
||||
export function findNavigationLink(namespace: string, href: string): NavigationLink | undefined {
|
||||
const currentUrl = `/${namespace}/${href}`.replace(/\/+/g, "/").replace(/\/$/, "");
|
||||
|
||||
const foundLink = navigation
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
{
|
||||
"scripts": {
|
||||
"dev": "tsx ./fastify-entry.ts",
|
||||
"dev:sitemap": "tsx --watch ./sitemap.ts",
|
||||
"build": "vike build",
|
||||
"preview": "cross-env NODE_ENV=production tsx ./fastify-entry.ts",
|
||||
"lint": "eslint .",
|
||||
|
||||
@ -4,7 +4,7 @@ const routeRegex = /^\/docs\/(.*)$/;
|
||||
|
||||
export function route(pageContext: PageContext) {
|
||||
if (pageContext.urlPathname === "/docs") {
|
||||
return { routeParams: { key: "index" } };
|
||||
return { routeParams: { key: "documentations" } };
|
||||
}
|
||||
|
||||
const match = pageContext.urlPathname.match(routeRegex);
|
||||
|
||||
@ -12,8 +12,11 @@ export type Data = Awaited<ReturnType<typeof data>>;
|
||||
export async function data(_pageContext: PageContext) {
|
||||
const config = useConfig();
|
||||
|
||||
const doc = await docsService.getDoc("root");
|
||||
if (!doc) throw render(404);
|
||||
const doc = await docsService.getDoc("docs", "index");
|
||||
|
||||
if (!doc) {
|
||||
throw render(404);
|
||||
}
|
||||
|
||||
const readingTimeObject = readingTime(doc.content, 300, "fr");
|
||||
|
||||
|
||||
@ -109,19 +109,16 @@ class DocsService {
|
||||
|
||||
public async fetchDocs() {
|
||||
const docs = glob.sync(DocsService.DOCS_PATH + `/**/*.{${DocsService.DOCS_EXTS.join(",")}}`);
|
||||
|
||||
const data = await Promise.all(
|
||||
docs.map((doc) => {
|
||||
const content = fs.readFileSync(doc, "utf-8");
|
||||
const extension = path.extname(doc).slice(1) as DocExtension;
|
||||
let key = doc
|
||||
const key = doc
|
||||
.replace(DocsService.DOCS_PATH, "")
|
||||
.replace(`page.${extension}`, "")
|
||||
.replace(`.${extension}`, "")
|
||||
.replace(/\/$/g, "");
|
||||
|
||||
if (key === "") key = "/root";
|
||||
|
||||
const ast = Markdoc.parse(content);
|
||||
const title = ast.attributes?.frontmatter?.match(/^title:\s*(.*?)\s*$/m)?.[1];
|
||||
const description = ast.attributes?.frontmatter?.match(/^description:\s*(.*?)\s*$/m)?.[1]?.replaceAll('"', "");
|
||||
@ -152,28 +149,23 @@ class DocsService {
|
||||
};
|
||||
}
|
||||
|
||||
public async getDoc(namespace: "root" | "docs" | "certifications", key?: string): Promise<DocData | undefined> {
|
||||
public async getDoc(namespace: "docs" | "certifications", key: string) {
|
||||
try {
|
||||
await this.fetchDocs();
|
||||
let doc: DocData | undefined;
|
||||
const doc = this.getFromCache(`/${namespace}/${key}`);
|
||||
|
||||
if (namespace === "root" || key === "index") {
|
||||
doc = this.getFromCache(`/${namespace}`);
|
||||
} else {
|
||||
doc = this.getFromCache(`/${namespace}/${key}`);
|
||||
if (!doc) {
|
||||
throw new Error("Doc not found");
|
||||
}
|
||||
|
||||
if (!doc) throw new Error("Doc not found");
|
||||
|
||||
return doc;
|
||||
} catch (error) {
|
||||
console.error("Error fetching docs:", error);
|
||||
|
||||
return undefined;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public async getUrls(namespace: "root" | "docs" | "certifications") {
|
||||
public async getUrls(namespace: "docs" | "certifications") {
|
||||
try {
|
||||
await this.fetchDocs();
|
||||
const docs = Array.from(this.cache.keys()).filter((key) => key.startsWith(`/${namespace}`));
|
||||
|
||||
@ -1,166 +0,0 @@
|
||||
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(stat?: fs.Stats): string {
|
||||
return stat ? stat.mtime.toISOString() : 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.dataPath, href.replace("/", ""), "page.md");
|
||||
}
|
||||
|
||||
private loadSubitems(subitems: (typeof navigation)[number]["links"][number]["subitems"]): void {
|
||||
subitems.forEach((subitem) => {
|
||||
const fileLocation = this.getFileServerLocation(subitem.href);
|
||||
let fileDetails: fs.Stats | undefined;
|
||||
try {
|
||||
fileDetails = fs.statSync(fileLocation);
|
||||
} catch (error) {
|
||||
console.error(`Error loading file for ${subitem.href}:`, error);
|
||||
}
|
||||
|
||||
const priority = this.loadPriority(subitem.href);
|
||||
const lastmod = this.loadLastModified(fileDetails);
|
||||
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 fileLocation = this.getFileServerLocation(link.href);
|
||||
let fileDetails: fs.Stats | undefined;
|
||||
|
||||
try {
|
||||
fileDetails = fs.statSync(fileLocation);
|
||||
} catch (error) {
|
||||
console.error(`Error loading file for ${link.href}:`, error);
|
||||
}
|
||||
|
||||
const priority = this.loadPriority(link.href);
|
||||
const lastmod = this.loadLastModified(fileDetails);
|
||||
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);
|
||||
});
|
||||
}
|
||||
|
||||
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();
|
||||
@ -1,3 +0,0 @@
|
||||
import { sitemap } from "./services/Sitemap";
|
||||
|
||||
sitemap.generateSitemap();
|
||||
Loading…
Reference in New Issue
Block a user