]> Untitled Git - lemmy-ui.git/blob - src/server/utils/create-ssr-html.tsx
ba85228f2f9c1394241fe40acf63e3fd95880331
[lemmy-ui.git] / src / server / utils / create-ssr-html.tsx
1 import { getStaticDir } from "@utils/env";
2 import { Helmet } from "inferno-helmet";
3 import { renderToString } from "inferno-server";
4 import serialize from "serialize-javascript";
5 import sharp from "sharp";
6 import { favIconPngUrl, favIconUrl } from "../../shared/config";
7 import { ILemmyConfig, IsoDataOptionalSite } from "../../shared/interfaces";
8 import { buildThemeList } from "./build-themes-list";
9 import { fetchIconPng } from "./fetch-icon-png";
10
11 const customHtmlHeader = process.env["LEMMY_UI_CUSTOM_HTML_HEADER"] || "";
12
13 let appleTouchIcon: string | undefined = undefined;
14
15 export async function createSsrHtml(
16   root: string,
17   isoData: IsoDataOptionalSite
18 ) {
19   const site = isoData.site_res;
20
21   const fallbackTheme = `<link rel="stylesheet" type="text/css" href="/css/themes/${
22     (await buildThemeList())[0]
23   }.css" />`;
24
25   if (!appleTouchIcon) {
26     appleTouchIcon = site?.site_view.site.icon
27       ? `data:image/png;base64,${await sharp(
28           await fetchIconPng(site.site_view.site.icon)
29         )
30           .resize(180, 180)
31           .extend({
32             bottom: 20,
33             top: 20,
34             left: 20,
35             right: 20,
36             background: "#222222",
37           })
38           .png()
39           .toBuffer()
40           .then(buf => buf.toString("base64"))}`
41       : favIconPngUrl;
42   }
43
44   const erudaStr =
45     process.env["LEMMY_UI_DEBUG"] === "true"
46       ? renderToString(
47           <>
48             <script src="//cdn.jsdelivr.net/npm/eruda"></script>
49             <script>eruda.init();</script>
50           </>
51         )
52       : "";
53
54   const helmet = Helmet.renderStatic();
55
56   const config: ILemmyConfig = { wsHost: process.env.LEMMY_UI_LEMMY_WS_HOST };
57
58   return `
59     <!DOCTYPE html>
60     <html ${helmet.htmlAttributes.toString()}>
61     <head>
62     <script>window.isoData = ${serialize(isoData)}</script>
63     <script>window.lemmyConfig = ${serialize(config)}</script>
64   
65     <!-- A remote debugging utility for mobile -->
66     ${erudaStr}
67   
68     <!-- Custom injected script -->
69     ${customHtmlHeader}
70   
71     ${helmet.title.toString()}
72     ${helmet.meta.toString()}
73   
74     <!-- Required meta tags -->
75     <meta name="Description" content="Lemmy">
76     <meta charset="utf-8">
77     <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
78     <link
79        id="favicon"
80        rel="shortcut icon"
81        type="image/x-icon"
82        href=${site?.site_view.site.icon ?? favIconUrl}
83      />
84   
85     <!-- Web app manifest -->
86     <link rel="manifest" href="/manifest.webmanifest" />
87     <link rel="apple-touch-icon" href=${appleTouchIcon} />
88     <link rel="apple-touch-startup-image" href=${appleTouchIcon} />
89   
90     <!-- Styles -->
91     <link rel="stylesheet" type="text/css" href="${getStaticDir()}/styles/styles.css" />
92   
93     <!-- Current theme and more -->
94     ${helmet.link.toString() || fallbackTheme}
95     
96     </head>
97   
98     <body ${helmet.bodyAttributes.toString()}>
99       <noscript>
100         <div class="alert alert-danger rounded-0" role="alert">
101           <b>Javascript is disabled. Actions will not work.</b>
102         </div>
103       </noscript>
104   
105       <div id='root'>${root}</div>
106       <script defer src='${getStaticDir()}/js/client.js'></script>
107     </body>
108   </html>
109   `;
110 }