perf: self-host fonts, drop unused generated code and add swf tests
- Self-host Nunito and Pixelify Sans via next/font instead of Google Fonts CDN (removes render-blocking external stylesheets and preconnects) - Remove stale mariadb entry from serverExternalPackages (app uses mysql2) - Exclude unused src/generated Prisma client from typecheck and remove it - Add unit tests for swf-parser, effectmap and figuremap (0% coverage -> 90%+)
This commit is contained in:
1 parent
ae1393d3e3
commit
4993b75608
7 files changed
+330
-23
No files matched your search
+1
-1
@@ -36,7 +36,7 @@ const securityHeaders = [
|
|||||||
const nextConfig: NextConfig = {
|
const nextConfig: NextConfig = {
|
||||||
cacheComponents: true, // <-- Dit activeert Cache Components en lost de 'instant' build-fout op!
|
cacheComponents: true, // <-- Dit activeert Cache Components en lost de 'instant' build-fout op!
|
||||||
deploymentId: resolveDeploymentId(),
|
deploymentId: resolveDeploymentId(),
|
||||||
serverExternalPackages: ["mariadb", "lzma", "sharp", "pino", "pino-pretty"],
|
serverExternalPackages: ["lzma", "sharp", "pino", "pino-pretty"],
|
||||||
|
|
||||||
// Onderdruk de specifieke Turbopack waarschuwingen voor brede bestandspatronen in de lib-map
|
// Onderdruk de specifieke Turbopack waarschuwingen voor brede bestandspatronen in de lib-map
|
||||||
turbopack: {
|
turbopack: {
|
||||||
|
|||||||
@@ -4,12 +4,6 @@
|
|||||||
@plugin "tailwindcss-animate";
|
@plugin "tailwindcss-animate";
|
||||||
@custom-variant dark (&:where(.dark, .dark *));
|
@custom-variant dark (&:where(.dark, .dark *));
|
||||||
|
|
||||||
:root {
|
|
||||||
--font-nunito:
|
|
||||||
"Nunito", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
|
|
||||||
--font-pixel: "Pixelify Sans", monospace;
|
|
||||||
}
|
|
||||||
|
|
||||||
@theme {
|
@theme {
|
||||||
--font-sans:
|
--font-sans:
|
||||||
var(--font-nunito), "Nunito", ui-sans-serif, system-ui, -apple-system,
|
var(--font-nunito), "Nunito", ui-sans-serif, system-ui, -apple-system,
|
||||||
|
|||||||
+20
-15
@@ -1,4 +1,5 @@
|
|||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
|
import { Nunito, Pixelify_Sans } from "next/font/google";
|
||||||
import { headers } from "next/headers";
|
import { headers } from "next/headers";
|
||||||
import Script from "next/script";
|
import Script from "next/script";
|
||||||
import { NextIntlClientProvider } from "next-intl";
|
import { NextIntlClientProvider } from "next-intl";
|
||||||
@@ -14,6 +15,20 @@ import { resolveHotelName } from "@/lib/hotel-name";
|
|||||||
import { siteSettings } from "@/lib/services/site-settings";
|
import { siteSettings } from "@/lib/services/site-settings";
|
||||||
import "./globals.css";
|
import "./globals.css";
|
||||||
|
|
||||||
|
const nunito = Nunito({
|
||||||
|
subsets: ["latin"],
|
||||||
|
weight: ["400", "600", "700", "800"],
|
||||||
|
variable: "--font-nunito",
|
||||||
|
display: "swap",
|
||||||
|
});
|
||||||
|
|
||||||
|
const pixelify = Pixelify_Sans({
|
||||||
|
subsets: ["latin"],
|
||||||
|
weight: ["400", "700"],
|
||||||
|
variable: "--font-pixel",
|
||||||
|
display: "swap",
|
||||||
|
});
|
||||||
|
|
||||||
// The root layout reads runtime data (locale cookie, request headers via
|
// The root layout reads runtime data (locale cookie, request headers via
|
||||||
// enforceSiteAccess, DB-backed site settings) to render the <html> element,
|
// enforceSiteAccess, DB-backed site settings) to render the <html> element,
|
||||||
// which cannot be wrapped in <Suspense>. Child pages inherit this opt-out,
|
// which cannot be wrapped in <Suspense>. Child pages inherit this opt-out,
|
||||||
@@ -58,23 +73,13 @@ export default async function RootLayout({
|
|||||||
const nonce = (await headers()).get("x-nonce") ?? undefined;
|
const nonce = (await headers()).get("x-nonce") ?? undefined;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<html lang={locale} className="app" suppressHydrationWarning>
|
<html
|
||||||
|
lang={locale}
|
||||||
|
className={`app ${nunito.variable} ${pixelify.variable}`}
|
||||||
|
suppressHydrationWarning
|
||||||
|
>
|
||||||
<head>
|
<head>
|
||||||
<meta name="theme-default-dark" content={String(defaultDark)} />
|
<meta name="theme-default-dark" content={String(defaultDark)} />
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
||||||
<link
|
|
||||||
rel="preconnect"
|
|
||||||
href="https://fonts.gstatic.com"
|
|
||||||
crossOrigin="anonymous"
|
|
||||||
/>
|
|
||||||
<link
|
|
||||||
rel="stylesheet"
|
|
||||||
href="https://fonts.googleapis.com/css2?family=Nunito:wght@400;600;700;800&display=swap"
|
|
||||||
/>
|
|
||||||
<link
|
|
||||||
rel="stylesheet"
|
|
||||||
href="https://fonts.googleapis.com/css2?family=Pixelify+Sans:wght@400;700&display=swap"
|
|
||||||
/>
|
|
||||||
<Script
|
<Script
|
||||||
src="/scripts/theme-init.js"
|
src="/scripts/theme-init.js"
|
||||||
strategy="beforeInteractive"
|
strategy="beforeInteractive"
|
||||||
|
|||||||
@@ -0,0 +1,85 @@
|
|||||||
|
import { promises as fs } from "node:fs";
|
||||||
|
import os from "node:os";
|
||||||
|
import path from "node:path";
|
||||||
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
import type { EffectMapEntry } from "@/types/effects";
|
||||||
|
import {
|
||||||
|
__setEffectMapPathForTests,
|
||||||
|
listLocalEffects,
|
||||||
|
mergeEffect,
|
||||||
|
readEffectMap,
|
||||||
|
removeEffect,
|
||||||
|
} from "./effectmap";
|
||||||
|
|
||||||
|
vi.mock("@/lib/services/site-settings", () => ({
|
||||||
|
siteSettings: { get: vi.fn(async () => "") },
|
||||||
|
}));
|
||||||
|
|
||||||
|
let dir: string;
|
||||||
|
let file: string;
|
||||||
|
|
||||||
|
const ENTRY: EffectMapEntry = {
|
||||||
|
id: "fx_1",
|
||||||
|
lib: "fx_1",
|
||||||
|
type: "fx",
|
||||||
|
revision: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
dir = await fs.mkdtemp(path.join(os.tmpdir(), "effectmap-"));
|
||||||
|
file = path.join(dir, "EffectMap.json");
|
||||||
|
await fs.writeFile(file, JSON.stringify({ effects: [ENTRY] }));
|
||||||
|
__setEffectMapPathForTests(file);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
__setEffectMapPathForTests(null);
|
||||||
|
await fs.rm(dir, { recursive: true, force: true });
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("lib/services/effectmap", () => {
|
||||||
|
it("lists local effects from the map", async () => {
|
||||||
|
const effects = await listLocalEffects();
|
||||||
|
expect(effects).toEqual([ENTRY]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns an empty list when the file has no effects array", async () => {
|
||||||
|
await fs.writeFile(file, JSON.stringify({}));
|
||||||
|
expect(await readEffectMap()).toEqual({ effects: [] });
|
||||||
|
});
|
||||||
|
|
||||||
|
it("adds a new effect via mergeEffect", async () => {
|
||||||
|
const added: EffectMapEntry = {
|
||||||
|
id: "fx_2",
|
||||||
|
lib: "fx_2",
|
||||||
|
type: "fx",
|
||||||
|
revision: 2,
|
||||||
|
};
|
||||||
|
await mergeEffect(added);
|
||||||
|
const effects = await listLocalEffects();
|
||||||
|
expect(effects).toHaveLength(2);
|
||||||
|
expect(effects).toContainEqual(added);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("updates an existing effect in place via mergeEffect", async () => {
|
||||||
|
await mergeEffect({ ...ENTRY, revision: 5 });
|
||||||
|
const effects = await listLocalEffects();
|
||||||
|
expect(effects).toHaveLength(1);
|
||||||
|
expect(effects[0].revision).toBe(5);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("removes an effect by id", async () => {
|
||||||
|
expect(await removeEffect("fx_1")).toBe(true);
|
||||||
|
expect(await listLocalEffects()).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("removes an effect by lib name", async () => {
|
||||||
|
expect(await removeEffect("fx_1")).toBe(true);
|
||||||
|
expect(await listLocalEffects()).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("reports false when nothing was removed", async () => {
|
||||||
|
expect(await removeEffect("missing")).toBe(false);
|
||||||
|
expect(await listLocalEffects()).toHaveLength(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
import { promises as fs } from "node:fs";
|
||||||
|
import os from "node:os";
|
||||||
|
import path from "node:path";
|
||||||
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
import type { FigureLibrary } from "./figuremap";
|
||||||
|
import {
|
||||||
|
__setFigureMapPathForTests,
|
||||||
|
listFigureLibraries,
|
||||||
|
mergeLibrary,
|
||||||
|
} from "./figuremap";
|
||||||
|
|
||||||
|
vi.mock("@/lib/services/site-settings", () => ({
|
||||||
|
siteSettings: { get: vi.fn(async () => "") },
|
||||||
|
}));
|
||||||
|
|
||||||
|
let dir: string;
|
||||||
|
let file: string;
|
||||||
|
|
||||||
|
const LIB: FigureLibrary = {
|
||||||
|
id: "h_human",
|
||||||
|
revision: 1,
|
||||||
|
parts: [{ id: 1, type: "hd" }],
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
dir = await fs.mkdtemp(path.join(os.tmpdir(), "figuremap-"));
|
||||||
|
file = path.join(dir, "FigureMap.json");
|
||||||
|
await fs.writeFile(file, JSON.stringify({ libraries: [LIB] }));
|
||||||
|
__setFigureMapPathForTests(file);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
__setFigureMapPathForTests(null);
|
||||||
|
await fs.rm(dir, { recursive: true, force: true });
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("lib/services/figuremap", () => {
|
||||||
|
it("lists figure libraries from the map", async () => {
|
||||||
|
const libraries = await listFigureLibraries();
|
||||||
|
expect(libraries).toEqual([LIB]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns an empty list when the file has no libraries array", async () => {
|
||||||
|
await fs.writeFile(file, JSON.stringify({}));
|
||||||
|
expect(await listFigureLibraries()).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("adds a new library via mergeLibrary", async () => {
|
||||||
|
const added: FigureLibrary = { id: "hh_human", revision: 2 };
|
||||||
|
await mergeLibrary(added);
|
||||||
|
const libraries = await listFigureLibraries();
|
||||||
|
expect(libraries).toHaveLength(2);
|
||||||
|
expect(libraries).toContainEqual(added);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("updates an existing library in place via mergeLibrary", async () => {
|
||||||
|
await mergeLibrary({ ...LIB, revision: 9 });
|
||||||
|
const libraries = await listFigureLibraries();
|
||||||
|
expect(libraries).toHaveLength(1);
|
||||||
|
expect(libraries[0].revision).toBe(9);
|
||||||
|
});
|
||||||
|
});
|
||||||
File diff suppressed because it is too large.
Load diff
+1
-1
@@ -32,5 +32,5 @@
|
|||||||
".next/types/**/*.ts",
|
".next/types/**/*.ts",
|
||||||
".next/dev/types/**/*.ts"
|
".next/dev/types/**/*.ts"
|
||||||
],
|
],
|
||||||
"exclude": ["node_modules", "e2e", "playwright.config.ts"]
|
"exclude": ["node_modules", "e2e", "playwright.config.ts", "src/generated"]
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user