aboutsummaryrefslogtreecommitdiff
path: root/vnext/server
diff options
context:
space:
mode:
authorGravatar Vitaly Takmazov2022-10-28 00:14:01 +0300
committerGravatar Vitaly Takmazov2023-01-13 10:37:58 +0300
commit40d411e516efee5531404725b45ab89d97172ce8 (patch)
treed675e93fc52ef50a40343219e1b992867964d3bf /vnext/server
parent2146a98bd98b7e275a0ee7bc7a243981b597f34c (diff)
Initial SSR
Diffstat (limited to 'vnext/server')
-rw-r--r--vnext/server/bootstrap.js11
-rw-r--r--vnext/server/index.js32
-rw-r--r--vnext/server/middleware/renderer.js48
-rw-r--r--vnext/server/sape.js38
4 files changed, 129 insertions, 0 deletions
diff --git a/vnext/server/bootstrap.js b/vnext/server/bootstrap.js
new file mode 100644
index 00000000..0f920886
--- /dev/null
+++ b/vnext/server/bootstrap.js
@@ -0,0 +1,11 @@
+require('ignore-styles');
+require('url-loader');
+require('file-loader');
+require('@babel/register')({
+ ignore: [/(node_modules)/],
+ presets: [
+ '@babel/preset-env',
+ ['@babel/preset-react', { 'runtime': 'automatic' }]
+ ]
+});
+require('./index');
diff --git a/vnext/server/index.js b/vnext/server/index.js
new file mode 100644
index 00000000..2b696977
--- /dev/null
+++ b/vnext/server/index.js
@@ -0,0 +1,32 @@
+import express from 'express';
+
+// we'll talk about this in a minute:
+import serverRenderer from './middleware/renderer';
+
+const PORT = 3000;
+const path = require('path');
+
+// initialize the application and create the routes
+const app = express();
+const router = express.Router();
+
+router.use('^/$', serverRenderer);
+
+// other static resources should just be served as they are
+router.use(express.static(
+ path.resolve(__dirname, '..', 'dist'),
+ { maxAge: '30d' },
+));
+
+router.use('*', serverRenderer);
+
+app.use(router);
+
+// start the app
+app.listen(PORT, (error) => {
+ if (error) {
+ return console.log('something bad happened', error);
+ }
+
+ console.log('listening on ' + PORT + '...');
+});
diff --git a/vnext/server/middleware/renderer.js b/vnext/server/middleware/renderer.js
new file mode 100644
index 00000000..8edb5f57
--- /dev/null
+++ b/vnext/server/middleware/renderer.js
@@ -0,0 +1,48 @@
+import ReactDOMServer from 'react-dom/server';
+import cookie from 'cookie';
+
+// import our main App component
+import App from '../../src/App';
+
+import { getLinks } from '../sape';
+import { StaticRouter } from 'react-router-dom';
+
+const path = require('path');
+const fs = require('fs');
+
+const serverRenderer = async (req, res, next) => {
+
+ // point to the html file created by CRA's build tool
+ const filePath = path.resolve(__dirname, '..', '..', 'dist', 'index.html');
+
+ // links
+ const cookies = cookie.parse(req.headers.cookie || '');
+
+ const links = await getLinks(req.originalUrl, cookies['sape_cookie']);
+ console.log(`URL: ${req.originalUrl} LINKS: ${links.join(' ')}`);
+ fs.readFile(filePath, 'utf8', (err, htmlData) => {
+ if (err) {
+ console.error('err', err);
+ return res.status(404).end();
+ }
+
+ const routerContext = {};
+
+ // render the app as a string
+ const html = ReactDOMServer.renderToString(
+ <StaticRouter location={req.baseUrl} context={routerContext}>
+ <App footer={links.join(' ')}/>
+ </StaticRouter>
+ );
+
+ // inject the rendered app into our html and send it
+ return res.send(
+ htmlData.replace(
+ '<div id="app"></div>',
+ `<div id="app">${html}</div>`
+ )
+ );
+ });
+};
+
+export default serverRenderer;
diff --git a/vnext/server/sape.js b/vnext/server/sape.js
new file mode 100644
index 00000000..d8c9e2ed
--- /dev/null
+++ b/vnext/server/sape.js
@@ -0,0 +1,38 @@
+import { parseStringPromise } from 'xml2js';
+import axios from 'axios';
+import { setupCache } from 'axios-cache-interceptor';
+
+const token = process.env.SAPE_TOKEN;
+
+/** @external Promise */
+
+/**
+ * @param { string } uri
+ * @param { string } sapeCookie
+ * @returns { Promise<string[]>} links
+ */
+export const getLinks = async (uri, sapeCookie) => {
+ if (!token) {
+ console.warn('Sape is not configured');
+ return [];
+ }
+ const response = await sape.get(`http://dispencer-01.sape.ru/code.php?user=${token}&host=juick.com&charset=UTF-8&as_xml=true`);
+ const data = await parseStringPromise(response.data);
+ const showCode = token === sapeCookie;
+ const requestURI = showCode ? '*' : uri;
+ const page = data.sape.page.filter(page => {
+ const uri = page['$']['uri'];
+ return uri === requestURI;
+ });
+ return page.length > 0 ? showCode ? [page[0]._] : page[0].link : [];
+};
+
+/** @type { import('axios-cache-interceptor').AxiosCacheInstance } */
+let sape = setupCache(
+ axios.create({
+ headers: {
+ 'User-Agent': 'SAPE_Client PHP 1.0.3'
+ }
+ }),
+ { ttl: 3600 * 1000 }
+);