bro.landing/scripts/ssr-render.js
Primakov Alexandr Alexandrovich 3b997a18e2
All checks were successful
platform/bro-js/bro.landing/pipeline/head This commit looks good
Update package dependencies for Emotion and Chakra UI. Enhance SSR rendering to include Chakra UI styles and improve HTML output for index.html and terms.html.
2025-10-24 13:08:02 +03:00

141 lines
5.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* eslint-disable @typescript-eslint/no-require-imports */
/* eslint-disable no-undef */
// Настройка Babel для транспиляции TSX/JSX в Node.js
require('@babel/register')({
extensions: ['.ts', '.tsx', '.js', '.jsx'],
presets: [
'@babel/preset-env',
'@babel/preset-react',
'@babel/preset-typescript'
],
ignore: [/node_modules/],
cache: false
});
const fs = require('fs');
const path = require('path');
const React = require('react');
const { renderToString } = require('react-dom/server');
const { Window } = require('happy-dom');
const { createCanvas } = require('canvas');
// Читаем index.ejs как основу для SSR
const ejsTemplatePath = path.resolve(__dirname, '../src/index.ejs');
const ejsTemplate = fs.readFileSync(ejsTemplatePath, 'utf-8');
// Настройка полноценного DOM окружения через happy-dom на основе index.ejs
const window = new Window({
url: 'http://localhost',
width: 1024,
height: 768
});
const document = window.document;
document.write(ejsTemplate);
// Расширяем happy-dom canvas поддержкой
window.HTMLCanvasElement.prototype.getContext = function() {
return createCanvas(200, 200).getContext('2d');
};
global.window = window;
global.document = document;
global.navigator = window.navigator;
global.HTMLElement = window.HTMLElement;
global.SVGElement = window.SVGElement;
console.log('🚀 Запуск SSR с рендерингом React компонентов...');
try {
// Импортируем компоненты
const { UnderConstruction } = require('../src/pages/under-construction/underConstruction.tsx');
const { Terms } = require('../src/pages/terms/Terms.tsx');
const { ChakraProvider, extendTheme } = require('@chakra-ui/react');
console.log('✅ Компоненты загружены');
// Функция для рендера с Chakra UI + базовыми стилями
function renderWithStyles(Component) {
// Chakra theme с базовыми стилями
const theme = extendTheme({});
// Генерируем базовые CSS переменные и стили Chakra
const baseStyles = `
<style data-emotion="chakra-global">
:root,:host{--chakra-vh:100vh}@supports(height:100dvh){:root,:host{--chakra-vh:100dvh}}
:root{color-scheme:light;--chakra-colors-chakra-body-text:#1A202C;--chakra-colors-chakra-body-bg:#fff;
--chakra-colors-chakra-border-color:#E2E8F0;--chakra-colors-chakra-placeholder-color:#A0AEC0}
body{background:var(--chakra-colors-chakra-body-bg);color:var(--chakra-colors-chakra-body-text);
font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif;line-height:1.5}
.chakra-container{width:100%;max-width:1200px;margin-left:auto;margin-right:auto;padding-left:16px;padding-right:16px}
.chakra-stack>*:not(style)~*:not(style){margin-top:1.5rem;margin-inline-start:0}
.chakra-heading{font-weight:700;font-size:1.875rem;line-height:2.25rem;margin-bottom:0.5rem}
.chakra-text{margin:0;margin-bottom:0.5rem}
.chakra-link{color:#3182ce;text-decoration:none}
.chakra-link:hover{text-decoration:underline}
.chakra-divider{border-color:var(--chakra-colors-chakra-border-color);border-style:solid;
border-width:0;border-bottom-width:1px;margin-top:1rem;margin-bottom:1rem}
ul,ol{margin-left:1.5rem;margin-bottom:1rem}
li{margin-bottom:0.5rem}
hr{border-top-width:1px;border-color:#E2E8F0}
</style>`;
const html = renderToString(
React.createElement(
ChakraProvider,
{ theme, cssVarsRoot: 'body' },
React.createElement(Component)
)
);
return { html, styles: baseStyles };
}
// Рендерим компоненты с извлечением стилей
const { html: homeContent, styles: homeStyles } = renderWithStyles(UnderConstruction);
const { html: termsContent, styles: termsStyles } = renderWithStyles(Terms);
console.log('✅ Компоненты отрендерены с Chakra UI + Emotion стилями');
// Читаем dist/index.html
const distPath = path.resolve(__dirname, '../dist');
const indexPath = path.join(distPath, 'index.html');
let indexHtml = fs.readFileSync(indexPath, 'utf-8');
// 1. Главная страница
const searchString = '<div id="app"></div>';
if (indexHtml.includes(searchString)) {
indexHtml = indexHtml
.replace(searchString, `<div id="app">${homeContent}</div>`)
.replace('</head>', `${homeStyles}</head>`);
fs.writeFileSync(indexPath, indexHtml, 'utf-8');
console.log('✅ index.html обновлен с SSR контентом и стилями');
}
// 2. Страница terms
let termsHtml = indexHtml
.replace(homeContent, termsContent)
.replace(homeStyles, termsStyles)
.replace('<title>bro-js admin</title>', '<title>Пользовательское соглашение - BROJS.RU</title>')
.replace(
'</head>',
'<meta name="description" content="Пользовательское соглашение для платформы обучения фронтенд-разработке BROJS.RU. Условия использования, обработка персональных данных, права и обязанности сторон." /></head>'
);
const termsPath = path.join(distPath, 'terms.html');
fs.writeFileSync(termsPath, termsHtml, 'utf-8');
console.log('✅ terms.html создан с SSR контентом и стилями');
console.log('🎉 SSR завершен успешно!');
console.log('📄 Созданы: index.html, terms.html');
console.log('💡 Весь контент отрендерен через React SSR');
console.log('🎨 Критические стили Emotion встроены в HTML');
} catch (error) {
console.error('❌ Ошибка при SSR:', error.message);
console.error(error.stack);
process.exit(1);
}