mirror of
https://github.com/LemmyNet/lemmy-ui.git
synced 2024-11-26 06:11:15 +00:00
Store manifest in memory so it does not need to be generated for every page request (#1433)
Co-authored-by: Dessalines <dessalines@users.noreply.github.com>
This commit is contained in:
parent
638ab2c462
commit
3db4fdddcd
4 changed files with 72 additions and 56 deletions
28
src/server/handlers/manifest-handler.ts
Normal file
28
src/server/handlers/manifest-handler.ts
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import type { Request, Response } from "express";
|
||||||
|
import { LemmyHttp } from "lemmy-js-client";
|
||||||
|
import { getHttpBaseInternal } from "../../shared/env";
|
||||||
|
import { wrapClient } from "../../shared/services/HttpService";
|
||||||
|
import generateManifestJson from "../utils/generate-manifest-json";
|
||||||
|
import { setForwardedHeaders } from "../utils/set-forwarded-headers";
|
||||||
|
|
||||||
|
let manifest: Awaited<ReturnType<typeof generateManifestJson>> | undefined =
|
||||||
|
undefined;
|
||||||
|
|
||||||
|
export default async (req: Request, res: Response) => {
|
||||||
|
if (!manifest) {
|
||||||
|
const headers = setForwardedHeaders(req.headers);
|
||||||
|
const client = wrapClient(new LemmyHttp(getHttpBaseInternal(), headers));
|
||||||
|
const site = await client.getSite({});
|
||||||
|
|
||||||
|
if (site.state === "success") {
|
||||||
|
manifest = await generateManifestJson(site.data);
|
||||||
|
} else {
|
||||||
|
res.sendStatus(500);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res.setHeader("content-type", "application/manifest+json");
|
||||||
|
|
||||||
|
res.send(manifest);
|
||||||
|
};
|
|
@ -2,6 +2,7 @@ import express from "express";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import process from "process";
|
import process from "process";
|
||||||
import CatchAllHandler from "./handlers/catch-all-handler";
|
import CatchAllHandler from "./handlers/catch-all-handler";
|
||||||
|
import ManifestHandler from "./handlers/manifest-handler";
|
||||||
import RobotsHandler from "./handlers/robots-handler";
|
import RobotsHandler from "./handlers/robots-handler";
|
||||||
import ServiceWorkerHandler from "./handlers/service-worker-handler";
|
import ServiceWorkerHandler from "./handlers/service-worker-handler";
|
||||||
import ThemeHandler from "./handlers/theme-handler";
|
import ThemeHandler from "./handlers/theme-handler";
|
||||||
|
@ -24,6 +25,7 @@ if (!process.env["LEMMY_UI_DISABLE_CSP"] && !process.env["LEMMY_UI_DEBUG"]) {
|
||||||
|
|
||||||
server.get("/robots.txt", RobotsHandler);
|
server.get("/robots.txt", RobotsHandler);
|
||||||
server.get("/service-worker.js", ServiceWorkerHandler);
|
server.get("/service-worker.js", ServiceWorkerHandler);
|
||||||
|
server.get("/manifest", ManifestHandler);
|
||||||
server.get("/css/themes/:name", ThemeHandler);
|
server.get("/css/themes/:name", ThemeHandler);
|
||||||
server.get("/css/themelist", ThemesListHandler);
|
server.get("/css/themelist", ThemesListHandler);
|
||||||
server.get("/*", CatchAllHandler);
|
server.get("/*", CatchAllHandler);
|
||||||
|
|
|
@ -5,17 +5,19 @@ import sharp from "sharp";
|
||||||
import { ILemmyConfig, IsoDataOptionalSite } from "../../shared/interfaces";
|
import { ILemmyConfig, IsoDataOptionalSite } from "../../shared/interfaces";
|
||||||
import { favIconPngUrl, favIconUrl } from "../../shared/utils";
|
import { favIconPngUrl, favIconUrl } from "../../shared/utils";
|
||||||
import { fetchIconPng } from "./fetch-icon-png";
|
import { fetchIconPng } from "./fetch-icon-png";
|
||||||
import { generateManifestBase64 } from "./generate-manifest-base64";
|
|
||||||
|
|
||||||
const customHtmlHeader = process.env["LEMMY_UI_CUSTOM_HTML_HEADER"] || "";
|
const customHtmlHeader = process.env["LEMMY_UI_CUSTOM_HTML_HEADER"] || "";
|
||||||
|
|
||||||
|
let appleTouchIcon: string | undefined = undefined;
|
||||||
|
|
||||||
export async function createSsrHtml(
|
export async function createSsrHtml(
|
||||||
root: string,
|
root: string,
|
||||||
isoData: IsoDataOptionalSite
|
isoData: IsoDataOptionalSite
|
||||||
) {
|
) {
|
||||||
const site = isoData.site_res;
|
const site = isoData.site_res;
|
||||||
|
|
||||||
const appleTouchIcon = site?.site_view.site.icon
|
if (!appleTouchIcon) {
|
||||||
|
appleTouchIcon = site?.site_view.site.icon
|
||||||
? `data:image/png;base64,${sharp(
|
? `data:image/png;base64,${sharp(
|
||||||
await fetchIconPng(site.site_view.site.icon)
|
await fetchIconPng(site.site_view.site.icon)
|
||||||
)
|
)
|
||||||
|
@ -31,6 +33,7 @@ export async function createSsrHtml(
|
||||||
.toBuffer()
|
.toBuffer()
|
||||||
.then(buf => buf.toString("base64"))}`
|
.then(buf => buf.toString("base64"))}`
|
||||||
: favIconPngUrl;
|
: favIconPngUrl;
|
||||||
|
}
|
||||||
|
|
||||||
const erudaStr =
|
const erudaStr =
|
||||||
process.env["LEMMY_UI_DEBUG"] === "true"
|
process.env["LEMMY_UI_DEBUG"] === "true"
|
||||||
|
@ -74,15 +77,7 @@ export async function createSsrHtml(
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- Web app manifest -->
|
<!-- Web app manifest -->
|
||||||
${
|
<link rel="manifest" href="/manifest" />
|
||||||
site &&
|
|
||||||
`<link
|
|
||||||
rel="manifest"
|
|
||||||
href=${`data:application/manifest+json;base64,${await generateManifestBase64(
|
|
||||||
site
|
|
||||||
)}`}
|
|
||||||
/>`
|
|
||||||
}
|
|
||||||
<link rel="apple-touch-icon" href=${appleTouchIcon} />
|
<link rel="apple-touch-icon" href=${appleTouchIcon} />
|
||||||
<link rel="apple-touch-startup-image" href=${appleTouchIcon} />
|
<link rel="apple-touch-startup-image" href=${appleTouchIcon} />
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ import sharp from "sharp";
|
||||||
import { getHttpBaseExternal } from "../../shared/env";
|
import { getHttpBaseExternal } from "../../shared/env";
|
||||||
import { fetchIconPng } from "./fetch-icon-png";
|
import { fetchIconPng } from "./fetch-icon-png";
|
||||||
|
|
||||||
const iconSizes = [72, 96, 144, 192, 512];
|
const iconSizes = [72, 96, 128, 144, 152, 192, 384, 512];
|
||||||
|
|
||||||
const defaultLogoPathDirectory = path.join(
|
const defaultLogoPathDirectory = path.join(
|
||||||
process.cwd(),
|
process.cwd(),
|
||||||
|
@ -14,7 +14,7 @@ const defaultLogoPathDirectory = path.join(
|
||||||
"icons"
|
"icons"
|
||||||
);
|
);
|
||||||
|
|
||||||
export async function generateManifestBase64({
|
export default async function ({
|
||||||
my_user,
|
my_user,
|
||||||
site_view: {
|
site_view: {
|
||||||
site,
|
site,
|
||||||
|
@ -25,7 +25,7 @@ export async function generateManifestBase64({
|
||||||
|
|
||||||
const icon = site.icon ? await fetchIconPng(site.icon) : null;
|
const icon = site.icon ? await fetchIconPng(site.icon) : null;
|
||||||
|
|
||||||
const manifest = {
|
return {
|
||||||
name: site.name,
|
name: site.name,
|
||||||
description: site.description ?? "A link aggregator for the fediverse",
|
description: site.description ?? "A link aggregator for the fediverse",
|
||||||
start_url: url,
|
start_url: url,
|
||||||
|
@ -69,20 +69,13 @@ export async function generateManifestBase64({
|
||||||
short_name: "Communities",
|
short_name: "Communities",
|
||||||
description: "Browse communities",
|
description: "Browse communities",
|
||||||
},
|
},
|
||||||
]
|
|
||||||
.concat(
|
|
||||||
my_user
|
|
||||||
? [
|
|
||||||
{
|
{
|
||||||
name: "Create Post",
|
name: "Create Post",
|
||||||
url: "/create_post",
|
url: "/create_post",
|
||||||
short_name: "Create Post",
|
short_name: "Create Post",
|
||||||
description: "Create a post.",
|
description: "Create a post.",
|
||||||
},
|
},
|
||||||
]
|
].concat(
|
||||||
: []
|
|
||||||
)
|
|
||||||
.concat(
|
|
||||||
my_user?.local_user_view.person.admin || !community_creation_admin_only
|
my_user?.local_user_view.person.admin || !community_creation_admin_only
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
|
@ -102,6 +95,4 @@ export async function generateManifestBase64({
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
return Buffer.from(JSON.stringify(manifest)).toString("base64");
|
|
||||||
}
|
}
|
Loading…
Reference in a new issue