stop using React for server-side-rendering

This commit is contained in:
HF 2022-06-29 22:02:02 +02:00
parent abeeccda88
commit 2575e54ba0
13 changed files with 253 additions and 318 deletions

View File

@ -25,7 +25,7 @@ import change_mail from './change_mail';
// eslint-disable-next-line camelcase
import restore_password from './restore_password';
import getHtml from '../../../ssr-components/RedirectionPage';
import getHtml from '../../../ssr/RedirectionPage';
import getMe from '../../../core/me';

View File

@ -3,7 +3,7 @@
*/
import socketEvents from '../../../socket/SocketEvents';
import getHtml from '../../../ssr-components/RedirectionPage';
import getHtml from '../../../ssr/RedirectionPage';
import { getHostFromRequest } from '../../../utils/ip';
import mailProvider from '../../../core/mail';

View File

@ -17,8 +17,8 @@ import api from './api';
import assets from './assets.json'; // eslint-disable-line import/no-unresolved
import { expressTTag } from '../core/ttag';
import generateGlobePage from '../ssr-components/Globe';
import generateMainPage from '../ssr-components/Main';
import generateGlobePage from '../ssr/Globe';
import generateMainPage from '../ssr/Main';
import { MONTH } from '../core/constants';
import { GUILDED_INVITE } from '../core/config';

View File

@ -9,7 +9,7 @@ import express from 'express';
import type { Request, Response } from 'express';
import logger from '../core/logger';
import getPasswordResetHtml from '../ssr-components/PasswordReset';
import getPasswordResetHtml from '../ssr/PasswordReset';
import mailProvider from '../core/mail';
import { RegUser } from '../data/sql';

View File

@ -1,62 +0,0 @@
/*
* react html for 3D globe page
*
* @flow
*/
import React from 'react';
import ReactDOM from 'react-dom/server';
import { getTTag } from '../core/ttag';
import Html from './Html';
/* this will be set by webpack */
// eslint-disable-next-line import/no-unresolved
import assets from './assets.json';
import { ASSET_SERVER } from '../core/config';
import globeCss from '../styles/globe.css';
const styles = [{
id: 'globe',
cssText: globeCss,
}];
const defaultScripts = assets.globe.js.map(
(s) => ASSET_SERVER + s,
);
/*
* generates string with html of globe page
* @param lang language code
* @return html of mainpage
*/
function generateGlobePage(lang: string): string {
const scripts = (assets[`globe-${lang}`])
? assets[`globe-${lang}`].js.map((s) => ASSET_SERVER + s)
: defaultScripts;
const { t } = getTTag(lang);
const Globe = () => (
<div>
<div id="webgl" />
<div id="coorbox">(0, 0)</div>
<div id="info">{t`Double click on globe to go back.`}</div>
<div id="loading">{t`Loading...`}</div>
</div>
);
const html = ReactDOM.renderToStaticMarkup(
<Html
title={t`PixelPlanet.Fun 3DGlobe`}
description={t`A 3D globe of our whole map`}
scripts={scripts}
body={<Globe />}
styles={styles}
/>,
);
return `<!doctype html>${html}`;
}
export default generateGlobePage;

View File

@ -1,70 +0,0 @@
/* @flow */
/**
* React Starter Kit (https://www.reactstarterkit.com/)
*
* Copyright © 2014-present Kriasoft, LLC. All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE.txt file in the root directory of this source tree.
*/
/* eslint-disable max-len */
import React from 'react';
const Html = ({
title,
description,
body,
// array of css stylesheet urls
css,
// array of script urls
scripts,
// style as string
styles,
// code as string
code,
}) => (
<html className="no-js" lang="en">
<head>
<meta charSet="utf-8" />
<meta httpEquiv="x-ua-compatible" content="ie=edge" />
<meta name="google" content="nopagereadaloud" />
<meta name="theme-color" content="#cae3ff" />
<title>{title}</title>
<meta name="description" content={description} />
<link rel="icon" href="/favicon.ico" type="image/x-icon" />
<meta
name="viewport"
content="user-scalable=no, width=device-width, initial-scale=1.0, maximum-scale=1.0"
/>
<link rel="apple-touch-icon" href="apple-touch-icon.png" />
{styles && styles.map((style) => (
<style
key={style.id}
id={style.id}
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{ __html: style.cssText }}
/>
))}
{code && (
<script
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{ __html: code }}
/>
)}
{css && css.map((stylesheet) => (
<link rel="stylesheet" type="text/css" id={stylesheet.id} href={stylesheet.uri} />
))}
</head>
<body>
<div id="app">
{body}
</div>
{scripts && scripts.map((script) => <script key={script} src={script} />)}
</body>
</html>
);
export default Html;

View File

@ -1,82 +0,0 @@
/*
* Html for mainpage
*
* @flow
*/
import React from 'react';
import ReactDOM from 'react-dom/server';
import { langCodeToCC } from '../utils/location';
import ttags, { getTTag } from '../core/ttag';
import Html from './Html';
/* this one is set by webpack */
// eslint-disable-next-line import/no-unresolved
import assets from './assets.json';
// eslint-disable-next-line import/no-unresolved
import styleassets from './styleassets.json';
import { ASSET_SERVER, BACKUP_URL } from '../core/config';
/*
* generate language list
*/
const langs = Object.keys(ttags)
.map((l) => (l === 'default' ? 'en' : l))
.map((l) => [l, langCodeToCC(l)]);
/*
* values that we pass to client scripts
*/
const ssv = {
assetserver: ASSET_SERVER,
availableStyles: styleassets,
langs,
};
if (BACKUP_URL) {
ssv.backupurl = BACKUP_URL;
}
const defaultScripts = assets.client.js.map(
(s) => ASSET_SERVER + s,
);
const css = [
{
id: 'globcss',
uri: styleassets.default,
},
];
/*
* Generates string with html of main page
* @param countryCoords Cell with coordinates of client country
* @param lang language code
* @return html of mainpage
*/
function generateMainPage(lang: string): string {
const ssvR = {
...ssv,
lang: lang === 'default' ? 'en' : lang,
};
const scripts = (assets[`client-${lang}`])
? assets[`client-${lang}`].js.map((s) => ASSET_SERVER + s)
: defaultScripts;
const { t } = getTTag(lang);
// eslint-disable-next-line
const html = ReactDOM.renderToStaticMarkup(
<Html
title={t`PixelPlanet.fun`}
// eslint-disable-next-line max-len
description={t`Place color pixels on an map styled canvas with other players online`}
scripts={scripts}
css={css}
// eslint-disable-next-line max-len
code={`window.ssv=JSON.parse('${JSON.stringify(ssvR)}');`}
/>,
);
return `<!doctype html>${html}`;
}
export default generateMainPage;

View File

@ -1,62 +0,0 @@
/*
* Make basic reset_password forms
*/
import React from 'react';
import ReactDOM from 'react-dom/server';
import Html from './Html';
import { getTTag } from '../core/ttag';
export default function getPasswordResetHtml(name, code, lang, message = null) {
const { t } = getTTag(lang);
let body = '';
if (message) {
body = (
<div>
<h3>{t`Reset Password`}</h3>
<p>{message}</p>
<p><a href="./">{t`Click here`}</a>&nbsp;
{t`to go back to pixelplanet`}</p>
</div>
);
} else {
body = (
<form method="post" action="reset_password">
<h3>{t`Reset Password`}</h3>
<p>{t`Hello ${name}, you can set your new password here:`}</p>
<input
type="password"
name="pass"
placeholder={t`New Password`}
style={{
maxWidth: '35em',
}}
/>
<input
type="password"
name="passconf"
placeholder={t`Confirm New Password`}
style={{
maxWidth: '35em',
}}
/>
<input type="hidden" name="code" value={code} />
<button type="submit" name="submit">{t`Submit`}</button>
</form>
);
}
const title = t`PixelPlanet.fun Password Reset`;
const description = t`Reset your password here`;
const index = `<!doctype html>${
ReactDOM.renderToStaticMarkup(<Html
title={title}
description={description}
body={body}
/>)}`;
return index;
}

View File

@ -1,37 +0,0 @@
/*
* Make basic redirection page
* @flow
*/
import React from 'react';
import ReactDOM from 'react-dom/server';
import Html from './Html';
import { getTTag } from '../core/ttag';
function getHtml(description, text, host, lang) {
const { jt, t } = getTTag(lang);
const clickHere = <a href={host}>{t`Click here`}</a>;
const body = (
<div>
<h3>{text}</h3>
<p>{t`You will be automatically redirected after 15s`}</p>
<p>{jt`Or ${clickHere} to go back to pixelplanet`}</p>
</div>
);
const title = t`PixelPlanet.fun Accounts`;
// eslint-disable-next-line max-len
const code = `window.setTimeout(function(){window.location.href="${host}";},15000)`;
const index = `<!doctype html>${
ReactDOM.renderToStaticMarkup(
<Html title={title} description={description} body={body} code={code} />,
)
}`;
return index;
}
export default getHtml;

58
src/ssr/Globe.jsx Normal file
View File

@ -0,0 +1,58 @@
/*
* react html for 3D globe page
*
*/
/* eslint-disable max-len */
import { getTTag } from '../core/ttag';
/* this will be set by webpack */
// eslint-disable-next-line import/no-unresolved
import assets from './assets.json';
import { ASSET_SERVER } from '../core/config';
import globeCss from '../styles/globe.css';
/*
* generates string with html of globe page
* @param lang language code
* @return html of mainpage
*/
function generateGlobePage(lang) {
const scripts = (assets[`globe-${lang}`])
? assets[`globe-${lang}`].js
: assets.globe.js;
const { t } = getTTag(lang);
const html = `
<!doctype html>
<html lang="${lang}">
<head>
<meta charset="UTF-8" />
<title>${t`PixelPlanet.Fun 3DGlobe`}</title>
<meta name="description" content="${t`A 3D globe of our whole map`}" />
<meta name="google" content="nopagereadaloud" />
<meta name="theme-color" content="#cae3ff" />
<meta name="viewport"
content="user-scalable=no, width=device-width, initial-scale=1.0, maximum-scale=1.0"
/>
<link rel="icon" href="/favicon.ico" type="image/x-icon" />
<link rel="apple-touch-icon" href="apple-touch-icon.png" />
<style key="globe" id="globe">${globeCss}</style>
</head>
<body>
<div id="webgl" />
<div id="coorbox">(0, 0)</div>
<div id="info">${t`Double click on globe to go back.`}</div>
<div id="loading">${t`Loading...`}</div>
${scripts.map((script) => `<script src="${ASSET_SERVER + script}"></script>`).join('')}
</body>
</html>
`;
return html;
}
export default generateGlobePage;

80
src/ssr/Main.jsx Normal file
View File

@ -0,0 +1,80 @@
/*
* Html for mainpage
*/
/* eslint-disable max-len */
import { langCodeToCC } from '../utils/location';
import ttags, { getTTag } from '../core/ttag';
/* this one is set by webpack */
// eslint-disable-next-line import/no-unresolved
import assets from './assets.json';
// eslint-disable-next-line import/no-unresolved
import styleassets from './styleassets.json';
import { ASSET_SERVER, BACKUP_URL } from '../core/config';
/*
* generate language list
*/
const langs = Object.keys(ttags)
.map((l) => (l === 'default' ? 'en' : l))
.map((l) => [l, langCodeToCC(l)]);
/*
* values that we pass to client scripts
*/
const ssv = {
assetserver: ASSET_SERVER,
availableStyles: styleassets,
langs,
};
if (BACKUP_URL) {
ssv.backupurl = BACKUP_URL;
}
/*
* Generates string with html of main page
* @param countryCoords Cell with coordinates of client country
* @param lang language code
* @return html of mainpage
*/
function generateMainPage(lang) {
const ssvR = {
...ssv,
lang: lang === 'default' ? 'en' : lang,
};
const scripts = (assets[`client-${lang}`])
? assets[`client-${lang}`].js
: assets.client.js;
const { t } = getTTag(lang);
const html = `
<!doctype html>
<html lang="${lang}">
<head>
<meta charset="UTF-8" />
<title>${t`PixelPlanet.Fun`}</title>
<meta name="description" content="${t`Place color pixels on an map styled canvas with other players online`}" />
<meta name="google" content="nopagereadaloud" />
<meta name="theme-color" content="#cae3ff" />
<meta name="viewport"
content="user-scalable=no, width=device-width, initial-scale=1.0, maximum-scale=1.0"
/>
<link rel="icon" href="/favicon.ico" type="image/x-icon" />
<link rel="apple-touch-icon" href="apple-touch-icon.png" />
<script>window.ssv=JSON.parse('${JSON.stringify(ssvR)}')</script>
<link rel="stylesheet" type="text/css" id="globcss" href="${styleassets.default}" />
</head>
<body>
<div id="app">
</div>
${scripts.map((script) => `<script src="${ASSET_SERVER + script}"></script>`).join('')}
</body>
</html>
`;
return html;
}
export default generateMainPage;

72
src/ssr/PasswordReset.jsx Normal file
View File

@ -0,0 +1,72 @@
/*
* Make basic reset_password forms
*/
/* eslint-disable max-len */
import { getTTag } from '../core/ttag';
export default function getPasswordResetHtml(name, code, lang, message = null) {
const { t } = getTTag(lang);
let html = '';
if (message) {
html = `
<!doctype html>
<html lang="${lang}">
<head>
<meta charset="UTF-8" />
<title>${t`PixelPlanet.fun Password Reset`}</title>
<meta name="description" content="${t`Reset your password here`}" />
<meta name="google" content="nopagereadaloud" />
<meta name="theme-color" content="#cae3ff" />
<link rel="icon" href="/favicon.ico" type="image/x-icon" />
<link rel="apple-touch-icon" href="apple-touch-icon.png" />
</head>
<body>
<h3>${t`Reset Password`}</h3>
<p>${message}</p>
<p><a href="./">${t`Click here`}</a> ${t`to go back to pixelplanet`}</p>
</body>
</html>
`;
} else {
html = `
<!doctype html>
<html lang="${lang}">
<head>
<meta charset="UTF-8" />
<title>${t`PixelPlanet.fun Password Reset`}</title>
<meta name="description" content="${t`Reset your password here`}" />
<meta name="google" content="nopagereadaloud" />
<meta name="theme-color" content="#cae3ff" />
<link rel="icon" href="/favicon.ico" type="image/x-icon" />
<link rel="apple-touch-icon" href="apple-touch-icon.png" />
</head>
<body>
<form method="post" action="reset_password">
<h3>${t`Reset Password`}</h3>
<p>${t`Hello ${name}, you can set your new password here:`}</p>
<input
type="password"
name="pass"
placeholder="${t`New Password`}"
style="max-width:35em"
/>
<input
type="password"
name="passconf"
placeholder="${t`Confirm New Password`}"
style="max-width:35em"
/>
<input type="hidden" name="code" value=${code} />
<button type="submit" name="submit">${t`Submit`}</button>
</form>
</body>
</html>
`;
}
return html;
}

View File

@ -0,0 +1,38 @@
/*
* Make basic redirection page
*/
/* eslint-disable max-len */
import { getTTag } from '../core/ttag';
function getHtml(description, text, host, lang) {
const { jt, t } = getTTag(lang);
const clickHere = `<a href="${host}">${t`Click here`}</a>`;
const html = `
<!doctype html>
<html lang="${lang}">
<head>
<meta charset="UTF-8" />
<title>${t`PixelPlanet.fun Accounts`}</title>
<meta name="description" content="${description}" />
<meta name="google" content="nopagereadaloud" />
<meta name="theme-color" content="#cae3ff" />
<link rel="icon" href="/favicon.ico" type="image/x-icon" />
<link rel="apple-touch-icon" href="apple-touch-icon.png" />
<script>window.setTimeout(function(){window.location.href="${host}";},15000)</script>
</head>
<body>
<h3>${text}</h3>
<p>${t`You will be automatically redirected after 15s`}</p>
<p>${jt`Or ${clickHere} to go back to pixelplanet`}</p>
</body>
</html>
`;
return html;
}
export default getHtml;