Refactor SSR implementation and update documentation. Replaced Static Site Generation (SSG) with Server-Side Rendering (SSR) using react-dom/server. Updated scripts for SSR rendering and removed deprecated prerender-multi.js. Enhanced terms.html generation from React components. Updated dependencies for Babel and added support for canvas in SSR.
All checks were successful
platform/bro-js/bro.landing/pipeline/head This commit looks good
All checks were successful
platform/bro-js/bro.landing/pipeline/head This commit looks good
This commit is contained in:
parent
9110e79d6b
commit
08ffd5a740
144
cloud.md
144
cloud.md
@ -19,11 +19,12 @@
|
||||
### Особенности:
|
||||
|
||||
✅ **React 18** с TypeScript
|
||||
✅ **Static Site Generation** - HTML вкомпилирован для SEO
|
||||
✅ **Server-Side Rendering (SSR)** - полноценный рендеринг React компонентов для SEO
|
||||
✅ **Chakra UI** - современный UI framework
|
||||
✅ **i18next** - мультиязычность (ru/en)
|
||||
✅ **React Router** - клиентский роутинг
|
||||
✅ **Hydration** - гидратация статического контента
|
||||
✅ **Hydration** - гидратация SSR контента
|
||||
✅ **jsdom + canvas** - полноценная DOM эмуляция для SSR
|
||||
|
||||
### Страницы:
|
||||
|
||||
@ -46,8 +47,7 @@ bro.landing/
|
||||
│ ├── index.tsx # Entry point + hydration
|
||||
│ └── index.ejs # HTML шаблон
|
||||
├── scripts/
|
||||
│ ├── prerender-multi.js # ⭐ Основной SSG скрипт
|
||||
│ └── ssr-prerender.js # Альтернативный SSR
|
||||
│ └── ssr-render.js # ⭐ SSR скрипт (react-dom/server)
|
||||
├── dist/ # Сборка (генерируется)
|
||||
│ ├── index.html # Главная (SSG)
|
||||
│ ├── terms.html # Соглашение (SSG)
|
||||
@ -58,23 +58,25 @@ bro.landing/
|
||||
|
||||
---
|
||||
|
||||
## Static Site Generation (SSG)
|
||||
## Server-Side Rendering (SSR)
|
||||
|
||||
### Как работает?
|
||||
|
||||
1. **Webpack** собирает React → `dist/index.js`
|
||||
2. **Скрипт `prerender-multi.js`** автоматически:
|
||||
- Читает `dist/index.html` (пустой шаблон)
|
||||
- Вставляет статический контент в `<div id="app"></div>`
|
||||
- Генерирует `dist/terms.html` из `terma.md`
|
||||
3. **React hydration** при загрузке оживляет статический HTML
|
||||
1. **Webpack** собирает React → `dist/index.js` + `dist/index.html` (шаблон)
|
||||
2. **Скрипт `ssr-render.js`** автоматически:
|
||||
- Настраивает окружение Node.js (jsdom + canvas)
|
||||
- Импортирует React компоненты из `src/pages/`
|
||||
- Рендерит компоненты через `react-dom/server`
|
||||
- Инжектит HTML в `dist/index.html` и `dist/terms.html`
|
||||
3. **React hydration** при загрузке оживляет SSR HTML
|
||||
|
||||
### Преимущества SSG:
|
||||
### Преимущества SSR:
|
||||
|
||||
- 🚀 **Быстрая загрузка** - контент виден до загрузки JS
|
||||
- 🔍 **SEO** - поисковики индексируют полный HTML
|
||||
- 🔍 **SEO** - поисковики индексируют полный HTML с Chakra UI
|
||||
- ♿ **Доступность** - работает без JavaScript
|
||||
- 📊 **Метрики** - улучшенные FCP и LCP
|
||||
- ✅ **Никакого хардкода** - рендер реальных компонентов
|
||||
|
||||
### Hydration в index.tsx:
|
||||
|
||||
@ -82,49 +84,37 @@ bro.landing/
|
||||
const hasPrerenderedContent = MOUNT_NODE.hasChildNodes();
|
||||
|
||||
if (hasPrerenderedContent) {
|
||||
hydrateRoot(MOUNT_NODE, <App />); // Оживляем статику
|
||||
hydrateRoot(MOUNT_NODE, <App />); // Оживляем SSR HTML
|
||||
} else {
|
||||
createRoot(MOUNT_NODE).render(<App />); // Обычный рендер
|
||||
}
|
||||
```
|
||||
|
||||
### Скрипт prerender-multi.js:
|
||||
### Скрипт ssr-render.js:
|
||||
|
||||
**Что делает**:
|
||||
1. Читает `terma.md` (исходник соглашения)
|
||||
2. Парсит markdown → HTML со стилями
|
||||
3. Создает `dist/index.html` с контентом главной
|
||||
4. Создает `dist/terms.html` с полным соглашением (~13KB)
|
||||
1. Настраивает Babel для транспиляции TSX → JS
|
||||
2. Настраивает jsdom для DOM эмуляции
|
||||
3. Настраивает canvas для Lottie анимаций
|
||||
4. Импортирует компоненты `UnderConstruction` и `Terms`
|
||||
5. Рендерит через `renderToString(React.createElement(Component))`
|
||||
6. Создает `dist/index.html` и `dist/terms.html` с полным HTML
|
||||
|
||||
**Автоматический запуск**:
|
||||
- `npm run build:prod` - после webpack сборки
|
||||
- `npm run build:prod:ssr` - альтернативный SSR
|
||||
|
||||
---
|
||||
|
||||
## Страница пользовательского соглашения
|
||||
|
||||
### Источник: `terma.md`
|
||||
### Источник: `Terms.tsx`
|
||||
|
||||
⚠️ **Важно**: `terma.md` - единственный источник правды для соглашения!
|
||||
⚠️ **Важно**: `src/pages/terms/Terms.tsx` - единственный источник правды для соглашения!
|
||||
|
||||
Чтобы обновить соглашение:
|
||||
1. Отредактируйте `terma.md`
|
||||
1. Отредактируйте `src/pages/terms/Terms.tsx`
|
||||
2. Запустите `npm run build:prod`
|
||||
3. `dist/terms.html` обновится автоматически
|
||||
|
||||
### Структура terma.md:
|
||||
|
||||
```markdown
|
||||
Пользовательское соглашение для BROJS.RU
|
||||
Последнее обновление: 25 мая 2025 г.
|
||||
|
||||
1. Термины
|
||||
...
|
||||
|
||||
10. Контакты
|
||||
Для обращений: primakov.pro@yandex.ru
|
||||
```
|
||||
3. `dist/terms.html` обновится автоматически через SSR
|
||||
|
||||
### React компонент: Terms.tsx
|
||||
|
||||
@ -132,21 +122,46 @@ if (hasPrerenderedContent) {
|
||||
- **Дизайн**: Chakra UI, официальный стиль документа
|
||||
- **SEO**: Helmet с meta-тегами
|
||||
- **Роут**: `/terms` в dashboard.tsx
|
||||
- **SSR**: Рендерится через `renderToString()` в `ssr-render.js`
|
||||
|
||||
### Структура компонента:
|
||||
|
||||
```tsx
|
||||
export const Terms = () => {
|
||||
return (
|
||||
<>
|
||||
<Helmet>
|
||||
<title>Пользовательское соглашение - BROJS.RU</title>
|
||||
<meta name="description" content="..." />
|
||||
</Helmet>
|
||||
|
||||
<Box bg="gray.50" minH="100vh" py={8}>
|
||||
<Container maxW="4xl" bg="white" shadow="lg" borderRadius="md" p={{ base: 6, md: 10 }}>
|
||||
<VStack spacing={6} align="stretch">
|
||||
<Heading as="h1">Пользовательское соглашение</Heading>
|
||||
{/* ... полный контент ... */}
|
||||
</VStack>
|
||||
</Container>
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
### SEO-версия: terms.html
|
||||
|
||||
Генерируется автоматически из `terma.md`:
|
||||
Генерируется автоматически через SSR из компонента `Terms.tsx`:
|
||||
|
||||
```html
|
||||
<title>Пользовательское соглашение - BROJS.RU</title>
|
||||
<meta name="description" content="Полное пользовательское соглашение..." />
|
||||
|
||||
<div id="app">
|
||||
<div style="...красивые стили...">
|
||||
<h1>Пользовательское соглашение для BROJS.RU</h1>
|
||||
<h2>1. Термины</h2>
|
||||
<ul>
|
||||
<li>Платформа — сайт https://brojs.ru ...</li>
|
||||
<div class="css-15jkess">
|
||||
<div class="chakra-container css-ilwlhp">
|
||||
<h1 class="chakra-heading css-s2s61i">Пользовательское соглашение</h1>
|
||||
<p class="chakra-text css-130t7v7">для BROJS.RU</p>
|
||||
<p class="chakra-text css-1pbebyg">Последнее обновление: 25 мая 2025 г.</p>
|
||||
...
|
||||
</ul>
|
||||
<!-- Все 10 разделов -->
|
||||
@ -174,8 +189,7 @@ if (hasPrerenderedContent) {
|
||||
{
|
||||
"start": "brojs server --port=8099 --with-open-browser",
|
||||
"build": "npm run clean && brojs build --dev",
|
||||
"build:prod": "npm run clean && brojs build && node scripts/prerender-multi.js",
|
||||
"build:prod:ssr": "npm run clean && brojs build && node scripts/ssr-prerender.js",
|
||||
"build:prod": "npm run clean && brojs build && node scripts/ssr-render.js",
|
||||
"clean": "rimraf dist",
|
||||
"eslint": "npx eslint src",
|
||||
"prettier": "prettier --write .",
|
||||
@ -204,35 +218,30 @@ npm run build
|
||||
# → Результат: dist/index.html (пустой шаблон)
|
||||
```
|
||||
|
||||
#### 🚀 Production сборка (с SSG):
|
||||
#### 🚀 Production сборка (с SSR):
|
||||
|
||||
```bash
|
||||
npm run build:prod
|
||||
# → Webpack в production режиме
|
||||
# → Минификация
|
||||
# → Автоматический SSG (prerender-multi.js)
|
||||
# → Автоматический SSR (ssr-render.js)
|
||||
# → Рендер реальных React компонентов через react-dom/server
|
||||
# → Результат:
|
||||
# - dist/index.html (со статическим контентом)
|
||||
# - dist/terms.html (полное соглашение для SEO)
|
||||
# - dist/index.html (UnderConstruction компонент)
|
||||
# - dist/terms.html (Terms компонент с Chakra UI)
|
||||
```
|
||||
|
||||
Вывод:
|
||||
```
|
||||
✅ Сборка успешно завершена!
|
||||
🚀 Начинаем мульти-страничный пре-рендеринг...
|
||||
✅ index.html обновлен
|
||||
📝 Генерируем полный HTML из terma.md...
|
||||
✅ terms.html создан с полным контентом
|
||||
🎉 Пре-рендеринг завершен успешно!
|
||||
```
|
||||
|
||||
#### 🔄 Production сборка (альтернативный SSR):
|
||||
|
||||
```bash
|
||||
npm run build:prod:ssr
|
||||
# → Использует ssr-prerender.js
|
||||
# → SSR с jsdom окружением
|
||||
# → Результат аналогичен build:prod
|
||||
🚀 Запуск SSR с рендерингом React компонентов...
|
||||
✅ Компоненты загружены
|
||||
✅ Компоненты отрендерены
|
||||
✅ index.html обновлен с SSR контентом
|
||||
✅ terms.html создан с SSR контентом
|
||||
🎉 SSR завершен успешно!
|
||||
📄 Созданы: index.html, terms.html
|
||||
💡 Весь контент отрендерен через React SSR
|
||||
```
|
||||
|
||||
### Другие команды:
|
||||
@ -267,12 +276,15 @@ npm run test # Запустить тесты
|
||||
|
||||
- **@brojs/cli 1.9.5** - сборщик (обертка над webpack)
|
||||
- **Webpack 5** - бандлер
|
||||
- **Babel** - транспиляция
|
||||
- **jsdom** - SSR окружение
|
||||
- **@babel/register** - транспиляция TSX в Node.js
|
||||
- **@babel/preset-react** - JSX поддержка
|
||||
- **@babel/preset-typescript** - TypeScript поддержка
|
||||
- **jsdom 25.x** - DOM эмуляция для SSR
|
||||
- **canvas 3.x** - Canvas API для Lottie в SSR
|
||||
|
||||
### Дополнительно:
|
||||
|
||||
- **Lottie React** - анимации
|
||||
- **Lottie React** - анимации (работает в SSR!)
|
||||
- **Day.js** - работа с датами
|
||||
- **ESLint** - линтинг
|
||||
- **Prettier** - форматирование
|
||||
|
||||
619
package-lock.json
generated
619
package-lock.json
generated
@ -33,9 +33,14 @@
|
||||
"redux": "^5.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.28.5",
|
||||
"@babel/preset-env": "^7.28.5",
|
||||
"@babel/preset-react": "^7.28.5",
|
||||
"@babel/register": "^7.28.3",
|
||||
"@eslint/js": "^9.9.0",
|
||||
"@types/jest": "^29.5.12",
|
||||
"babel-jest": "^29.7.0",
|
||||
"canvas": "^3.2.0",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-plugin-react": "^7.35.0",
|
||||
"eslint-plugin-react-hooks": "^4.6.2",
|
||||
@ -48,19 +53,6 @@
|
||||
"typescript-eslint": "^8.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@ampproject/remapping": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
|
||||
"integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@jridgewell/gen-mapping": "^0.3.5",
|
||||
"@jridgewell/trace-mapping": "^0.3.24"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@asamuzakjp/css-color": {
|
||||
"version": "4.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-4.0.5.tgz",
|
||||
@ -161,21 +153,21 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/core": {
|
||||
"version": "7.25.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz",
|
||||
"integrity": "sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==",
|
||||
"version": "7.28.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz",
|
||||
"integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@ampproject/remapping": "^2.2.0",
|
||||
"@babel/code-frame": "^7.24.7",
|
||||
"@babel/generator": "^7.25.0",
|
||||
"@babel/helper-compilation-targets": "^7.25.2",
|
||||
"@babel/helper-module-transforms": "^7.25.2",
|
||||
"@babel/helpers": "^7.25.0",
|
||||
"@babel/parser": "^7.25.0",
|
||||
"@babel/template": "^7.25.0",
|
||||
"@babel/traverse": "^7.25.2",
|
||||
"@babel/types": "^7.25.2",
|
||||
"@babel/code-frame": "^7.27.1",
|
||||
"@babel/generator": "^7.28.5",
|
||||
"@babel/helper-compilation-targets": "^7.27.2",
|
||||
"@babel/helper-module-transforms": "^7.28.3",
|
||||
"@babel/helpers": "^7.28.4",
|
||||
"@babel/parser": "^7.28.5",
|
||||
"@babel/template": "^7.27.2",
|
||||
"@babel/traverse": "^7.28.5",
|
||||
"@babel/types": "^7.28.5",
|
||||
"@jridgewell/remapping": "^2.3.5",
|
||||
"convert-source-map": "^2.0.0",
|
||||
"debug": "^4.1.0",
|
||||
"gensync": "^1.0.0-beta.2",
|
||||
@ -450,13 +442,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helpers": {
|
||||
"version": "7.25.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.6.tgz",
|
||||
"integrity": "sha512-Xg0tn4HcfTijTwfDwYlvVCl43V6h4KyVVX2aEm4qdO/PC6L2YvzLHFdmxhoeSA3eslcE6+ZVXHgWwopXYLNq4Q==",
|
||||
"version": "7.28.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz",
|
||||
"integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/template": "^7.25.0",
|
||||
"@babel/types": "^7.25.6"
|
||||
"@babel/template": "^7.27.2",
|
||||
"@babel/types": "^7.28.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@ -1861,6 +1853,165 @@
|
||||
"@babel/core": "^7.0.0-0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/register": {
|
||||
"version": "7.28.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/register/-/register-7.28.3.tgz",
|
||||
"integrity": "sha512-CieDOtd8u208eI49bYl4z1J22ySFw87IGwE+IswFEExH7e3rLgKb0WNQeumnacQ1+VoDJLYI5QFA3AJZuyZQfA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"clone-deep": "^4.0.1",
|
||||
"find-cache-dir": "^2.0.0",
|
||||
"make-dir": "^2.1.0",
|
||||
"pirates": "^4.0.6",
|
||||
"source-map-support": "^0.5.16"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@babel/core": "^7.0.0-0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/register/node_modules/find-cache-dir": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz",
|
||||
"integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"commondir": "^1.0.1",
|
||||
"make-dir": "^2.0.0",
|
||||
"pkg-dir": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/register/node_modules/find-up": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
|
||||
"integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"locate-path": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/register/node_modules/locate-path": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
|
||||
"integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"p-locate": "^3.0.0",
|
||||
"path-exists": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/register/node_modules/make-dir": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
|
||||
"integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"pify": "^4.0.1",
|
||||
"semver": "^5.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/register/node_modules/p-limit": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
|
||||
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"p-try": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/register/node_modules/p-locate": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
|
||||
"integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"p-limit": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/register/node_modules/path-exists": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
|
||||
"integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/register/node_modules/pkg-dir": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz",
|
||||
"integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"find-up": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/register/node_modules/semver": {
|
||||
"version": "5.7.2",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
|
||||
"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
"semver": "bin/semver"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/register/node_modules/source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/register/node_modules/source-map-support": {
|
||||
"version": "0.5.21",
|
||||
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
|
||||
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"buffer-from": "^1.0.0",
|
||||
"source-map": "^0.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/runtime": {
|
||||
"version": "7.28.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz",
|
||||
@ -4267,6 +4418,16 @@
|
||||
"@jridgewell/trace-mapping": "^0.3.24"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/remapping": {
|
||||
"version": "2.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
|
||||
"integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@jridgewell/gen-mapping": "^0.3.5",
|
||||
"@jridgewell/trace-mapping": "^0.3.24"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/resolve-uri": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
|
||||
@ -5906,6 +6067,27 @@
|
||||
"bare-path": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/base64-js": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/baseline-browser-mapping": {
|
||||
"version": "2.8.20",
|
||||
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.20.tgz",
|
||||
@ -5947,6 +6129,18 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/bl": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
|
||||
"integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"buffer": "^5.5.0",
|
||||
"inherits": "^2.0.4",
|
||||
"readable-stream": "^3.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/body-parser": {
|
||||
"version": "1.20.3",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
|
||||
@ -6071,6 +6265,31 @@
|
||||
"node-int64": "^0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/buffer": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
|
||||
"integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"base64-js": "^1.3.1",
|
||||
"ieee754": "^1.1.13"
|
||||
}
|
||||
},
|
||||
"node_modules/buffer-crc32": {
|
||||
"version": "0.2.13",
|
||||
"resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
|
||||
@ -6165,6 +6384,21 @@
|
||||
],
|
||||
"license": "CC-BY-4.0"
|
||||
},
|
||||
"node_modules/canvas": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/canvas/-/canvas-3.2.0.tgz",
|
||||
"integrity": "sha512-jk0GxrLtUEmW/TmFsk2WghvgHe8B0pxGilqCL21y8lHkPUGa6FTsnCNtHPOzT8O3y+N+m3espawV80bbBlgfTA==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"node-addon-api": "^7.0.0",
|
||||
"prebuild-install": "^7.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.12.0 || >= 20.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/chalk": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
|
||||
@ -6227,6 +6461,13 @@
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/chownr": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
|
||||
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/chrome-trace-event": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz",
|
||||
@ -6415,6 +6656,13 @@
|
||||
"integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/commondir": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
|
||||
"integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/compute-scroll-into-view": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-3.0.3.tgz",
|
||||
@ -6911,6 +7159,22 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/decompress-response": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
|
||||
"integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mimic-response": "^3.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/dedent": {
|
||||
"version": "1.5.3",
|
||||
"resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz",
|
||||
@ -6926,6 +7190,16 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/deep-extend": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
|
||||
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/deep-is": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
|
||||
@ -7072,6 +7346,16 @@
|
||||
"npm": "1.2.8000 || >= 1.4.16"
|
||||
}
|
||||
},
|
||||
"node_modules/detect-libc": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
|
||||
"integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/detect-newline": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz",
|
||||
@ -8024,6 +8308,16 @@
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/expand-template": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
|
||||
"integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==",
|
||||
"dev": true,
|
||||
"license": "(MIT OR WTFPL)",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/expect": {
|
||||
"version": "29.7.0",
|
||||
"resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz",
|
||||
@ -8743,6 +9037,13 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/fs-constants": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
|
||||
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/fs-extra": {
|
||||
"version": "9.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
|
||||
@ -8925,6 +9226,13 @@
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/github-from-package": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
|
||||
"integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/glob": {
|
||||
"version": "7.2.3",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
|
||||
@ -9533,6 +9841,27 @@
|
||||
"postcss": "^8.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ieee754": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
|
||||
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/ignore": {
|
||||
"version": "5.3.2",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
|
||||
@ -11485,6 +11814,19 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/mimic-response": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
|
||||
"integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
@ -11522,6 +11864,13 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/mkdirp-classic": {
|
||||
"version": "0.5.3",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
|
||||
"integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
@ -11546,6 +11895,13 @@
|
||||
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/napi-build-utils": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz",
|
||||
"integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/natural-compare": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
|
||||
@ -11589,6 +11945,39 @@
|
||||
"tslib": "^2.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/node-abi": {
|
||||
"version": "3.78.0",
|
||||
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.78.0.tgz",
|
||||
"integrity": "sha512-E2wEyrgX/CqvicaQYU3Ze1PFGjc4QYPGsjUrlYkqAE0WjHEZwgOsGMPMzkMse4LjJbDmaEuDX3CM036j5K2DSQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"semver": "^7.3.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/node-abi/node_modules/semver": {
|
||||
"version": "7.7.3",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
|
||||
"integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/node-addon-api": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz",
|
||||
"integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/node-fetch": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
|
||||
@ -12386,6 +12775,63 @@
|
||||
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/prebuild-install": {
|
||||
"version": "7.1.3",
|
||||
"resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz",
|
||||
"integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"detect-libc": "^2.0.0",
|
||||
"expand-template": "^2.0.3",
|
||||
"github-from-package": "0.0.0",
|
||||
"minimist": "^1.2.3",
|
||||
"mkdirp-classic": "^0.5.3",
|
||||
"napi-build-utils": "^2.0.0",
|
||||
"node-abi": "^3.3.0",
|
||||
"pump": "^3.0.0",
|
||||
"rc": "^1.2.7",
|
||||
"simple-get": "^4.0.0",
|
||||
"tar-fs": "^2.0.0",
|
||||
"tunnel-agent": "^0.6.0"
|
||||
},
|
||||
"bin": {
|
||||
"prebuild-install": "bin.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/prebuild-install/node_modules/tar-fs": {
|
||||
"version": "2.1.4",
|
||||
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz",
|
||||
"integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"chownr": "^1.1.1",
|
||||
"mkdirp-classic": "^0.5.2",
|
||||
"pump": "^3.0.0",
|
||||
"tar-stream": "^2.1.4"
|
||||
}
|
||||
},
|
||||
"node_modules/prebuild-install/node_modules/tar-stream": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
|
||||
"integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"bl": "^4.0.3",
|
||||
"end-of-stream": "^1.4.1",
|
||||
"fs-constants": "^1.0.0",
|
||||
"inherits": "^2.0.3",
|
||||
"readable-stream": "^3.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/prelude-ls": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
|
||||
@ -12742,6 +13188,32 @@
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/rc": {
|
||||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
|
||||
"integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
|
||||
"dev": true,
|
||||
"license": "(BSD-2-Clause OR MIT OR Apache-2.0)",
|
||||
"dependencies": {
|
||||
"deep-extend": "^0.6.0",
|
||||
"ini": "~1.3.0",
|
||||
"minimist": "^1.2.0",
|
||||
"strip-json-comments": "~2.0.1"
|
||||
},
|
||||
"bin": {
|
||||
"rc": "cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/rc/node_modules/strip-json-comments": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
|
||||
"integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react": {
|
||||
"version": "18.3.1",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
|
||||
@ -13115,6 +13587,21 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/readable-stream": {
|
||||
"version": "3.6.2",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
|
||||
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/readdirp": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
||||
@ -13743,6 +14230,53 @@
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/simple-concat": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz",
|
||||
"integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/simple-get": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz",
|
||||
"integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"decompress-response": "^6.0.0",
|
||||
"once": "^1.3.1",
|
||||
"simple-concat": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/sisteransi": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
|
||||
@ -13889,6 +14423,16 @@
|
||||
"text-decoder": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/string_decoder": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"safe-buffer": "~5.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/string-length": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz",
|
||||
@ -14561,6 +15105,19 @@
|
||||
"integrity": "sha512-+bGy9iDAqg3WSfc2ZrprToSPJhZjqy7vUv9wupQzsiv+BVPVx1T2a6G4T0290SpQj+56Toaw9BiLO5j5Bd7QzA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tunnel-agent": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
|
||||
"integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"safe-buffer": "^5.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/type-check": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
|
||||
|
||||
@ -13,8 +13,7 @@
|
||||
"test": "jest --coverage",
|
||||
"start": "brojs server --port=8099 --with-open-browser",
|
||||
"build": "npm run clean && brojs build --dev",
|
||||
"build:prod": "npm run clean && brojs build && node scripts/prerender-multi.js",
|
||||
"build:prod:ssr": "npm run clean && brojs build && node scripts/ssr-prerender.js"
|
||||
"build:prod": "npm run clean && brojs build && node scripts/ssr-render.js"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
@ -44,9 +43,14 @@
|
||||
"redux": "^5.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.28.5",
|
||||
"@babel/preset-env": "^7.28.5",
|
||||
"@babel/preset-react": "^7.28.5",
|
||||
"@babel/register": "^7.28.3",
|
||||
"@eslint/js": "^9.9.0",
|
||||
"@types/jest": "^29.5.12",
|
||||
"babel-jest": "^29.7.0",
|
||||
"canvas": "^3.2.0",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-plugin-react": "^7.35.0",
|
||||
"eslint-plugin-react-hooks": "^4.6.2",
|
||||
|
||||
@ -1,169 +0,0 @@
|
||||
/* eslint-disable @typescript-eslint/no-require-imports */
|
||||
/* eslint-disable no-undef */
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
// Контент для главной страницы
|
||||
const homeContent = `
|
||||
<div>
|
||||
<div style="max-height: 250px;">
|
||||
<div>Loading...</div>
|
||||
</div>
|
||||
<h3><center>Сайт в разработке</center></h3>
|
||||
</div>
|
||||
`.trim();
|
||||
|
||||
// Функция для генерации полного HTML из terma.md
|
||||
const generateTermsContent = () => {
|
||||
const termaPath = path.resolve(__dirname, '../terma.md');
|
||||
const termaText = fs.readFileSync(termaPath, 'utf-8');
|
||||
|
||||
// Парсим markdown в HTML с сохранением структуры
|
||||
let html = '<div style="background: #f7fafc; min-height: 100vh; padding: 32px 0;">';
|
||||
html += '<div style="max-width: 1200px; margin: 0 auto; background: white; box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1); border-radius: 8px; padding: 60px 80px; font-family: -apple-system, BlinkMacSystemFont, \'Segoe UI\', Roboto, sans-serif;">';
|
||||
|
||||
const lines = termaText.split('\n');
|
||||
let inList = false;
|
||||
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const line = lines[i].trim();
|
||||
|
||||
if (!line) {
|
||||
if (inList) {
|
||||
html += '</ul>';
|
||||
inList = false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Заголовок H1
|
||||
if (i === 0) {
|
||||
html += '<div style="text-align: center; margin-bottom: 40px;">';
|
||||
html += `<h1 style="font-size: 2.5em; color: #2563eb; margin-bottom: 8px; font-weight: 700;">${line}</h1>`;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Дата обновления
|
||||
if (line.includes('Последнее обновление')) {
|
||||
html += `<p style="color: #6b7280; font-size: 0.875em;">${line}</p>`;
|
||||
html += '</div><hr style="border: 0; border-top: 1px solid #e5e7eb; margin: 24px 0;">';
|
||||
continue;
|
||||
}
|
||||
|
||||
// Основные разделы (начинаются с цифры и точки без подразделов)
|
||||
if (/^\d+\.\s+[А-Яа-я]/.test(line)) {
|
||||
if (inList) {
|
||||
html += '</ul>';
|
||||
inList = false;
|
||||
}
|
||||
const text = line.replace(/^\d+\.\s+/, '');
|
||||
html += `<h2 style="font-size: 1.875em; color: #1e40af; margin-top: 40px; margin-bottom: 16px; font-weight: 600;">${line}</h2>`;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Подразделы (например, 2.1., 3.2.)
|
||||
if (/^\d+\.\d+\.\s+/.test(line)) {
|
||||
if (inList) {
|
||||
html += '</ul>';
|
||||
inList = false;
|
||||
}
|
||||
html += `<h3 style="font-size: 1.25em; color: #374151; margin-top: 24px; margin-bottom: 12px; font-weight: 600;">${line}</h3>`;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Списки (начинаются с заглавной буквы или содержат "—")
|
||||
if (line.includes('—') || (i > 0 && lines[i-1].includes('через:')) || (i > 0 && lines[i-1].includes('обязуется:')) || (i > 0 && lines[i-1].includes('собирает:')) || (i > 0 && lines[i-1].includes('ответственности за:'))) {
|
||||
if (!inList) {
|
||||
html += '<ul style="list-style-type: disc; padding-left: 32px; margin: 12px 0;">';
|
||||
inList = true;
|
||||
}
|
||||
|
||||
// Обработка ссылок
|
||||
let processedLine = line
|
||||
.replace(/https?:\/\/[^\s,)]+/g, (url) => {
|
||||
const cleanUrl = url.replace(/\s*,?\s*$/, '');
|
||||
return `<a href="${cleanUrl}" style="color: #3b82f6; text-decoration: underline;">${cleanUrl}</a>`;
|
||||
})
|
||||
.replace(/([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})/g,
|
||||
'<a href="mailto:$1" style="color: #3b82f6; text-decoration: underline;">$1</a>');
|
||||
|
||||
html += `<li style="margin: 8px 0; line-height: 1.75;">${processedLine}</li>`;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Обычные параграфы
|
||||
if (inList && !line.includes('—')) {
|
||||
html += '</ul>';
|
||||
inList = false;
|
||||
}
|
||||
|
||||
// Обработка жирного текста и ссылок
|
||||
let processedLine = line
|
||||
.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>')
|
||||
.replace(/https?:\/\/[^\s,)]+/g, (url) => {
|
||||
const cleanUrl = url.replace(/\s*,?\s*$/, '');
|
||||
return `<a href="${cleanUrl}" style="color: #3b82f6; text-decoration: underline;">${cleanUrl}</a>`;
|
||||
})
|
||||
.replace(/([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})/g,
|
||||
'<a href="mailto:$1" style="color: #3b82f6; text-decoration: underline;">$1</a>');
|
||||
|
||||
html += `<p style="margin: 12px 0; line-height: 1.75; color: #374151;">${processedLine}</p>`;
|
||||
}
|
||||
|
||||
if (inList) {
|
||||
html += '</ul>';
|
||||
}
|
||||
|
||||
// Footer
|
||||
html += '<hr style="border: 0; border-top: 1px solid #e5e7eb; margin: 48px 0 24px 0;">';
|
||||
html += '<p style="text-align: center; color: #6b7280; font-size: 0.875em;">© 2025 BROJS.RU. Все права защищены.</p>';
|
||||
html += '</div></div>';
|
||||
|
||||
return html;
|
||||
};
|
||||
|
||||
const prerender = () => {
|
||||
try {
|
||||
console.log('🚀 Начинаем мульти-страничный пре-рендеринг...');
|
||||
|
||||
const distPath = path.resolve(__dirname, '../dist');
|
||||
const indexPath = path.join(distPath, 'index.html');
|
||||
|
||||
// Читаем основной 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>`);
|
||||
fs.writeFileSync(indexPath, indexHtml, 'utf-8');
|
||||
console.log('✅ index.html обновлен');
|
||||
}
|
||||
|
||||
// 2. Генерируем полный контент для terms.html из terma.md
|
||||
console.log('📝 Генерируем полный HTML из terma.md...');
|
||||
const termsContent = generateTermsContent();
|
||||
|
||||
// 3. Создаем terms.html на основе index.html
|
||||
let termsHtml = indexHtml
|
||||
.replace(homeContent, termsContent)
|
||||
.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 создан с полным контентом');
|
||||
|
||||
console.log('🎉 Пре-рендеринг завершен успешно!');
|
||||
console.log('📄 Созданы файлы: index.html, terms.html');
|
||||
console.log('💡 terms.html содержит полный текст соглашения для SEO');
|
||||
} catch (error) {
|
||||
console.error('❌ Ошибка при пре-рендеринге:', error);
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
prerender();
|
||||
@ -1,79 +0,0 @@
|
||||
/* eslint-disable @typescript-eslint/no-require-imports */
|
||||
/* eslint-disable no-undef */
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { JSDOM } = require('jsdom');
|
||||
|
||||
// Настройка окружения для SSR
|
||||
const setupDOM = () => {
|
||||
const dom = new JSDOM('<!DOCTYPE html><html><body></body></html>', {
|
||||
url: 'http://localhost',
|
||||
pretendToBeVisual: true,
|
||||
resources: 'usable'
|
||||
});
|
||||
|
||||
global.window = dom.window;
|
||||
global.document = dom.window.document;
|
||||
global.navigator = dom.window.navigator;
|
||||
global.HTMLElement = dom.window.HTMLElement;
|
||||
global.HTMLDivElement = dom.window.HTMLDivElement;
|
||||
global.requestAnimationFrame = (callback) => setTimeout(callback, 0);
|
||||
global.cancelAnimationFrame = clearTimeout;
|
||||
};
|
||||
|
||||
const cleanupRender = () => {
|
||||
delete global.window;
|
||||
delete global.document;
|
||||
delete global.navigator;
|
||||
delete global.HTMLElement;
|
||||
delete global.HTMLDivElement;
|
||||
delete global.requestAnimationFrame;
|
||||
delete global.cancelAnimationFrame;
|
||||
};
|
||||
|
||||
const prerender = async () => {
|
||||
try {
|
||||
console.log('🚀 Начинаем SSR пре-рендеринг...');
|
||||
|
||||
setupDOM();
|
||||
|
||||
// Читаем HTML шаблон
|
||||
const indexPath = path.resolve(__dirname, '../dist/index.html');
|
||||
let html = fs.readFileSync(indexPath, 'utf-8');
|
||||
|
||||
// Рендерим статический контент страницы "в разработке"
|
||||
const prerenderContent = `
|
||||
<div style="text-align: center; padding: 20px;">
|
||||
<div style="max-height: 250px; margin: 0 auto;">
|
||||
<div>⚙️</div>
|
||||
</div>
|
||||
<h3><center>Сайт в разработке</center></h3>
|
||||
<p style="color: #666;">Страница загружается...</p>
|
||||
</div>
|
||||
`.trim();
|
||||
|
||||
// Вставляем пре-рендеренный контент в div#app
|
||||
const searchString = '<div id="app"></div>';
|
||||
if (html.includes(searchString)) {
|
||||
html = html.replace(searchString, `<div id="app">${prerenderContent}</div>`);
|
||||
|
||||
// Сохраняем результат
|
||||
fs.writeFileSync(indexPath, html, 'utf-8');
|
||||
console.log('✅ SSR пре-рендеринг завершен успешно!');
|
||||
console.log('📄 HTML обновлен с серверным контентом');
|
||||
} else {
|
||||
console.log('⚠️ Не найден <div id="app"></div>');
|
||||
console.log('Возможно, HTML уже содержит пре-рендеренный контент');
|
||||
}
|
||||
|
||||
cleanupRender();
|
||||
} catch (error) {
|
||||
console.error('❌ Ошибка при SSR пре-рендеринге:', error);
|
||||
cleanupRender();
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
prerender();
|
||||
|
||||
93
scripts/ssr-render.js
Normal file
93
scripts/ssr-render.js
Normal file
@ -0,0 +1,93 @@
|
||||
/* 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 { JSDOM } = require('jsdom');
|
||||
const { createCanvas } = require('canvas');
|
||||
|
||||
// Настройка полноценного DOM окружения через jsdom
|
||||
const dom = new JSDOM('<!DOCTYPE html><html><body></body></html>', {
|
||||
url: 'http://localhost',
|
||||
pretendToBeVisual: true,
|
||||
resources: 'usable'
|
||||
});
|
||||
|
||||
const canvas = createCanvas(200, 200);
|
||||
|
||||
// Расширяем jsdom canvas поддержкой
|
||||
dom.window.HTMLCanvasElement.prototype.getContext = function() {
|
||||
return createCanvas(200, 200).getContext('2d');
|
||||
};
|
||||
|
||||
global.window = dom.window;
|
||||
global.document = dom.window.document;
|
||||
global.navigator = dom.window.navigator;
|
||||
global.HTMLElement = dom.window.HTMLElement;
|
||||
global.SVGElement = dom.window.SVGElement;
|
||||
|
||||
console.log('🚀 Запуск SSR с рендерингом React компонентов...');
|
||||
|
||||
try {
|
||||
// Импортируем компоненты
|
||||
const { UnderConstruction } = require('../src/pages/under-construction/underConstruction.tsx');
|
||||
const { Terms } = require('../src/pages/terms/Terms.tsx');
|
||||
|
||||
console.log('✅ Компоненты загружены');
|
||||
|
||||
// Рендерим компоненты в HTML
|
||||
const homeContent = renderToString(React.createElement(UnderConstruction));
|
||||
const termsContent = renderToString(React.createElement(Terms));
|
||||
|
||||
console.log('✅ Компоненты отрендерены');
|
||||
|
||||
// Читаем 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>`);
|
||||
fs.writeFileSync(indexPath, indexHtml, 'utf-8');
|
||||
console.log('✅ index.html обновлен с SSR контентом');
|
||||
}
|
||||
|
||||
// 2. Страница terms
|
||||
let termsHtml = indexHtml
|
||||
.replace(homeContent, termsContent)
|
||||
.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');
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Ошибка при SSR:', error.message);
|
||||
console.error(error.stack);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user