Обновлен .gitignore для исключения новых артефактов сборки и временных файлов. Изменен тип в конфигурации Vite на "classic" с добавлением navigateFallback. Добавлены новые маршруты для обработки сервисного рабочего скрипта в dev режиме, включая поддержку dev-sw.js и registerSW.js. Обновлен index.html для улучшения пользовательского опыта с индикатором загрузки. Обновлен манифест и сервисный рабочий скрипт для улучшения кэширования и обработки запросов.
This commit is contained in:
parent
4d91b2227d
commit
d1a3853449
35
.gitignore
vendored
35
.gitignore
vendored
@ -14,8 +14,20 @@ backend/node_modules
|
||||
# Build outputs
|
||||
dist
|
||||
dist-ssr
|
||||
dev-dist
|
||||
*.local
|
||||
|
||||
# Vite
|
||||
.vite
|
||||
vite.config.*.timestamp-*
|
||||
|
||||
# Build artifacts in backend/public
|
||||
backend/public/assets/
|
||||
backend/public/workbox-*.js
|
||||
backend/public/registerSW.js
|
||||
backend/public/sw.js
|
||||
backend/public/index.html
|
||||
|
||||
# Environment variables
|
||||
.env
|
||||
.env.local
|
||||
@ -26,6 +38,7 @@ backend/.env
|
||||
backend/database/*.db
|
||||
backend/database/*.db-shm
|
||||
backend/database/*.db-wal
|
||||
backend/database/*.db-journal
|
||||
|
||||
# Uploads
|
||||
backend/public/uploads/*
|
||||
@ -35,7 +48,6 @@ backend/public/uploads/*
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
@ -47,4 +59,25 @@ public/sw.js.map
|
||||
|
||||
# OS
|
||||
Thumbs.db
|
||||
.DS_Store
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
|
||||
# TypeScript
|
||||
*.tsbuildinfo
|
||||
.tsbuildinfo
|
||||
|
||||
# Coverage
|
||||
coverage
|
||||
*.lcov
|
||||
.nyc_output
|
||||
|
||||
# Testing
|
||||
.jest
|
||||
|
||||
# Misc
|
||||
.cache
|
||||
.parcel-cache
|
||||
.turbo
|
||||
|
||||
|
||||
@ -1,69 +1,69 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ru">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
|
||||
/>
|
||||
<title>NoteJS - Система заметок</title>
|
||||
|
||||
<!-- Предотвращение мерцания темы -->
|
||||
<script>
|
||||
(function () {
|
||||
try {
|
||||
// Получаем сохраненную тему
|
||||
const savedTheme = localStorage.getItem("theme");
|
||||
// Получаем системные предпочтения
|
||||
const systemPrefersDark = window.matchMedia(
|
||||
"(prefers-color-scheme: dark)"
|
||||
).matches;
|
||||
|
||||
// Определяем тему: сохраненная или системная
|
||||
const theme = savedTheme || (systemPrefersDark ? "dark" : "light");
|
||||
|
||||
// Функция для конвертации hex в RGB
|
||||
function hexToRgb(hex) {
|
||||
const cleanHex = hex.replace("#", "");
|
||||
const r = parseInt(cleanHex.substring(0, 2), 16);
|
||||
const g = parseInt(cleanHex.substring(2, 4), 16);
|
||||
const b = parseInt(cleanHex.substring(4, 6), 16);
|
||||
return `${r}, ${g}, ${b}`;
|
||||
}
|
||||
|
||||
// Получаем и устанавливаем accentColor
|
||||
const savedAccentColor = localStorage.getItem("accentColor");
|
||||
const accentColor = savedAccentColor || "#007bff";
|
||||
|
||||
// Устанавливаем тему и переменные до загрузки CSS
|
||||
if (theme === "dark") {
|
||||
document.documentElement.setAttribute("data-theme", "dark");
|
||||
} else {
|
||||
document.documentElement.setAttribute("data-theme", "light");
|
||||
}
|
||||
|
||||
// Устанавливаем CSS переменные для accent цвета
|
||||
document.documentElement.style.setProperty("--accent-color", accentColor);
|
||||
document.documentElement.style.setProperty("--accent-color-rgb", hexToRgb(accentColor));
|
||||
|
||||
// Устанавливаем цвет для meta theme-color
|
||||
const themeColorMeta = document.querySelector('meta[name="theme-color"]');
|
||||
if (themeColorMeta) {
|
||||
themeColorMeta.setAttribute(
|
||||
"content",
|
||||
theme === "dark" ? "#1a1a1a" : accentColor
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
// В случае ошибки устанавливаем светлую тему по умолчанию
|
||||
document.documentElement.setAttribute("data-theme", "light");
|
||||
document.documentElement.style.setProperty("--accent-color", "#007bff");
|
||||
document.documentElement.style.setProperty("--accent-color-rgb", "0, 123, 255");
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
|
||||
<!-- Критические стили темы для предотвращения flash эффекта -->
|
||||
<!DOCTYPE html>
|
||||
<html lang="ru">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
|
||||
/>
|
||||
<title>NoteJS - Система заметок</title>
|
||||
|
||||
<!-- Предотвращение мерцания темы -->
|
||||
<script>
|
||||
(function () {
|
||||
try {
|
||||
// Получаем сохраненную тему
|
||||
const savedTheme = localStorage.getItem("theme");
|
||||
// Получаем системные предпочтения
|
||||
const systemPrefersDark = window.matchMedia(
|
||||
"(prefers-color-scheme: dark)"
|
||||
).matches;
|
||||
|
||||
// Определяем тему: сохраненная или системная
|
||||
const theme = savedTheme || (systemPrefersDark ? "dark" : "light");
|
||||
|
||||
// Функция для конвертации hex в RGB
|
||||
function hexToRgb(hex) {
|
||||
const cleanHex = hex.replace("#", "");
|
||||
const r = parseInt(cleanHex.substring(0, 2), 16);
|
||||
const g = parseInt(cleanHex.substring(2, 4), 16);
|
||||
const b = parseInt(cleanHex.substring(4, 6), 16);
|
||||
return `${r}, ${g}, ${b}`;
|
||||
}
|
||||
|
||||
// Получаем и устанавливаем accentColor
|
||||
const savedAccentColor = localStorage.getItem("accentColor");
|
||||
const accentColor = savedAccentColor || "#007bff";
|
||||
|
||||
// Устанавливаем тему и переменные до загрузки CSS
|
||||
if (theme === "dark") {
|
||||
document.documentElement.setAttribute("data-theme", "dark");
|
||||
} else {
|
||||
document.documentElement.setAttribute("data-theme", "light");
|
||||
}
|
||||
|
||||
// Устанавливаем CSS переменные для accent цвета
|
||||
document.documentElement.style.setProperty("--accent-color", accentColor);
|
||||
document.documentElement.style.setProperty("--accent-color-rgb", hexToRgb(accentColor));
|
||||
|
||||
// Устанавливаем цвет для meta theme-color
|
||||
const themeColorMeta = document.querySelector('meta[name="theme-color"]');
|
||||
if (themeColorMeta) {
|
||||
themeColorMeta.setAttribute(
|
||||
"content",
|
||||
theme === "dark" ? "#1a1a1a" : accentColor
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
// В случае ошибки устанавливаем светлую тему по умолчанию
|
||||
document.documentElement.setAttribute("data-theme", "light");
|
||||
document.documentElement.style.setProperty("--accent-color", "#007bff");
|
||||
document.documentElement.style.setProperty("--accent-color-rgb", "0, 123, 255");
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
|
||||
<!-- Критические стили темы для предотвращения flash эффекта -->
|
||||
<style>
|
||||
:root {
|
||||
--accent-color: #007bff;
|
||||
@ -89,79 +89,147 @@
|
||||
color: var(--text-primary);
|
||||
transition: background-color 0.3s ease, color 0.3s ease;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- PWA Meta Tags -->
|
||||
<meta
|
||||
name="description"
|
||||
content="NoteJS - современная система заметок с поддержкой Markdown, изображений, тегов и календаря"
|
||||
/>
|
||||
<meta name="theme-color" content="#007bff" />
|
||||
<meta name="mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta
|
||||
name="apple-mobile-web-app-status-bar-style"
|
||||
content="black-translucent"
|
||||
/>
|
||||
<meta name="apple-mobile-web-app-title" content="NoteJS" />
|
||||
<meta name="apple-touch-fullscreen" content="yes" />
|
||||
<meta name="msapplication-TileColor" content="#007bff" />
|
||||
<meta name="msapplication-config" content="/browserconfig.xml" />
|
||||
<meta name="msapplication-TileImage" content="/icons/icon-144x144.png" />
|
||||
<meta name="application-name" content="NoteJS" />
|
||||
<meta name="format-detection" content="telephone=no" />
|
||||
|
||||
<!-- Icons -->
|
||||
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/png"
|
||||
sizes="32x32"
|
||||
href="/icons/icon-32x32.png"
|
||||
/>
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/png"
|
||||
sizes="16x16"
|
||||
href="/icons/icon-16x16.png"
|
||||
/>
|
||||
<link rel="apple-touch-icon" sizes="57x57" href="/icons/icon-48x48.png" />
|
||||
<link rel="apple-touch-icon" sizes="60x60" href="/icons/icon-48x48.png" />
|
||||
<link rel="apple-touch-icon" sizes="72x72" href="/icons/icon-72x72.png" />
|
||||
<link rel="apple-touch-icon" sizes="76x76" href="/icons/icon-72x72.png" />
|
||||
<link
|
||||
rel="apple-touch-icon"
|
||||
sizes="114x114"
|
||||
href="/icons/icon-128x128.png"
|
||||
/>
|
||||
<link
|
||||
rel="apple-touch-icon"
|
||||
sizes="120x120"
|
||||
href="/icons/icon-128x128.png"
|
||||
/>
|
||||
<link
|
||||
rel="apple-touch-icon"
|
||||
sizes="144x144"
|
||||
href="/icons/icon-144x144.png"
|
||||
/>
|
||||
<link
|
||||
rel="apple-touch-icon"
|
||||
sizes="152x152"
|
||||
href="/icons/icon-152x152.png"
|
||||
/>
|
||||
<link
|
||||
rel="apple-touch-icon"
|
||||
sizes="180x180"
|
||||
href="/icons/icon-192x192.png"
|
||||
/>
|
||||
<link rel="mask-icon" href="/icon.svg" color="#007bff" />
|
||||
|
||||
<!-- Manifest -->
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
<script type="module" crossorigin src="/assets/index-CRKRzJj1.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-QEK5TGz3.css">
|
||||
<link rel="manifest" href="/manifest.webmanifest"></head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
</body>
|
||||
</html>
|
||||
</style>
|
||||
|
||||
<!-- PWA Meta Tags -->
|
||||
<meta
|
||||
name="description"
|
||||
content="NoteJS - современная система заметок с поддержкой Markdown, изображений, тегов и календаря"
|
||||
/>
|
||||
<meta name="theme-color" content="#007bff" />
|
||||
<meta name="mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta
|
||||
name="apple-mobile-web-app-status-bar-style"
|
||||
content="black-translucent"
|
||||
/>
|
||||
<meta name="apple-mobile-web-app-title" content="NoteJS" />
|
||||
<meta name="apple-touch-fullscreen" content="yes" />
|
||||
<meta name="msapplication-TileColor" content="#007bff" />
|
||||
<meta name="msapplication-config" content="/browserconfig.xml" />
|
||||
<meta name="msapplication-TileImage" content="/icons/icon-144x144.png" />
|
||||
<meta name="application-name" content="NoteJS" />
|
||||
<meta name="format-detection" content="telephone=no" />
|
||||
|
||||
<!-- Icons -->
|
||||
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/png"
|
||||
sizes="32x32"
|
||||
href="/icons/icon-32x32.png"
|
||||
/>
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/png"
|
||||
sizes="16x16"
|
||||
href="/icons/icon-16x16.png"
|
||||
/>
|
||||
<link rel="apple-touch-icon" sizes="57x57" href="/icons/icon-48x48.png" />
|
||||
<link rel="apple-touch-icon" sizes="60x60" href="/icons/icon-48x48.png" />
|
||||
<link rel="apple-touch-icon" sizes="72x72" href="/icons/icon-72x72.png" />
|
||||
<link rel="apple-touch-icon" sizes="76x76" href="/icons/icon-72x72.png" />
|
||||
<link
|
||||
rel="apple-touch-icon"
|
||||
sizes="114x114"
|
||||
href="/icons/icon-128x128.png"
|
||||
/>
|
||||
<link
|
||||
rel="apple-touch-icon"
|
||||
sizes="120x120"
|
||||
href="/icons/icon-128x128.png"
|
||||
/>
|
||||
<link
|
||||
rel="apple-touch-icon"
|
||||
sizes="144x144"
|
||||
href="/icons/icon-144x144.png"
|
||||
/>
|
||||
<link
|
||||
rel="apple-touch-icon"
|
||||
sizes="152x152"
|
||||
href="/icons/icon-152x152.png"
|
||||
/>
|
||||
<link
|
||||
rel="apple-touch-icon"
|
||||
sizes="180x180"
|
||||
href="/icons/icon-192x192.png"
|
||||
/>
|
||||
<link rel="mask-icon" href="/icon.svg" color="#007bff" />
|
||||
|
||||
<!-- Manifest -->
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
<script type="module" crossorigin src="/assets/index-Czo9BXMw.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-d4V1QKN4.css">
|
||||
<link rel="manifest" href="/manifest.webmanifest"><script id="vite-plugin-pwa:register-sw" src="/registerSW.js"></script></head>
|
||||
<body>
|
||||
<div id="root">
|
||||
<!-- Индикатор загрузки до монтирования React -->
|
||||
<div id="initial-loading" style="
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: var(--bg-primary);
|
||||
color: var(--text-primary);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 9999;
|
||||
">
|
||||
<style>
|
||||
#initial-loading-spinner {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border: 4px solid transparent;
|
||||
border-top: 4px solid var(--accent-color, #007bff);
|
||||
border-right: 4px solid var(--accent-color, #007bff);
|
||||
border-bottom: 4px solid transparent;
|
||||
border-left: 4px solid transparent;
|
||||
border-radius: 50%;
|
||||
animation: initial-loading-spin 0.8s linear infinite;
|
||||
opacity: 0.8;
|
||||
}
|
||||
@keyframes initial-loading-spin {
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
</style>
|
||||
<div id="initial-loading-spinner"></div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
// Скрываем индикатор загрузки сразу после загрузки DOM
|
||||
// React удалит этот элемент при первом рендере через createRoot
|
||||
(function() {
|
||||
// Используем MutationObserver для отслеживания изменений в #root
|
||||
const observer = new MutationObserver(function(mutations) {
|
||||
mutations.forEach(function(mutation) {
|
||||
// Если React начал добавлять элементы в #root, удаляем индикатор
|
||||
if (mutation.addedNodes.length > 0) {
|
||||
const loadingEl = document.getElementById('initial-loading');
|
||||
if (loadingEl && loadingEl.parentNode) {
|
||||
loadingEl.parentNode.removeChild(loadingEl);
|
||||
}
|
||||
observer.disconnect();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Начинаем наблюдение за изменениями в #root
|
||||
const root = document.getElementById('root');
|
||||
if (root) {
|
||||
observer.observe(root, { childList: true, subtree: true });
|
||||
|
||||
// Фолбэк: если через 2 секунды элемент все еще есть, удаляем вручную
|
||||
setTimeout(function() {
|
||||
const loadingEl = document.getElementById('initial-loading');
|
||||
if (loadingEl && loadingEl.parentNode) {
|
||||
loadingEl.parentNode.removeChild(loadingEl);
|
||||
}
|
||||
observer.disconnect();
|
||||
}, 2000);
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -9,27 +9,10 @@
|
||||
"orientation": "portrait-primary",
|
||||
"scope": "/",
|
||||
"lang": "ru",
|
||||
"id": "/",
|
||||
"categories": ["productivity", "utilities"],
|
||||
"prefer_related_applications": false,
|
||||
"display_override": ["window-controls-overlay", "standalone"],
|
||||
"dir": "ltr",
|
||||
"shortcuts": [
|
||||
{
|
||||
"name": "Новая заметка",
|
||||
"short_name": "Новая",
|
||||
"description": "Создать новую заметку",
|
||||
"url": "/notes?new=true",
|
||||
"icons": [{ "src": "/icons/icon-192x192.png", "sizes": "192x192" }]
|
||||
},
|
||||
{
|
||||
"name": "Мой профиль",
|
||||
"short_name": "Профиль",
|
||||
"description": "Открыть профиль",
|
||||
"url": "/profile",
|
||||
"icons": [{ "src": "/icons/icon-192x192.png", "sizes": "192x192" }]
|
||||
}
|
||||
],
|
||||
"screenshots": [
|
||||
{
|
||||
"src": "/icons/icon-512x512.png",
|
||||
|
||||
@ -1 +1 @@
|
||||
if(!self.define){let e,i={};const n=(n,c)=>(n=new URL(n+".js",c).href,i[n]||new Promise(i=>{if("document"in self){const e=document.createElement("script");e.src=n,e.onload=i,document.head.appendChild(e)}else e=n,importScripts(n),i()}).then(()=>{let e=i[n];if(!e)throw new Error(`Module ${n} didn’t register its module`);return e}));self.define=(c,o)=>{const s=e||("document"in self?document.currentScript.src:"")||location.href;if(i[s])return;let r={};const d=e=>n(e,s),a={module:{uri:s},exports:r,require:d};i[s]=Promise.all(c.map(e=>a[e]||d(e))).then(e=>(o(...e),r))}}define(["./workbox-57555046"],function(e){"use strict";self.addEventListener("message",e=>{e.data&&"SKIP_WAITING"===e.data.type&&self.skipWaiting()}),e.precacheAndRoute([{url:"assets/index-CRKRzJj1.js",revision:null},{url:"assets/index-QEK5TGz3.css",revision:null},{url:"assets/workbox-window.prod.es5-B9K5rw8f.js",revision:null},{url:"icon.svg",revision:"537ae73d8f9e90e6a01816aa6d527d16"},{url:"icons/icon-128x128.png",revision:"fa71db17e345406d5f7d847f88c65ac4"},{url:"icons/icon-144x144.png",revision:"e790ff42758ea1a2a46eb84201630757"},{url:"icons/icon-152x152.png",revision:"88f2400f6617a32cc9cd62c70fb49a05"},{url:"icons/icon-16x16.png",revision:"101c13808e9fd0956f247bc446a8ac1e"},{url:"icons/icon-192x192.png",revision:"7d86d2d2ada99d7cee015dff0fdcb497"},{url:"icons/icon-32x32.png",revision:"22ee5d42535bc339ab0e19cb496378a5"},{url:"icons/icon-384x384.png",revision:"c601fa602952a903389e5e8f8a699617"},{url:"icons/icon-48x48.png",revision:"cfdd3bebd931375f2e0277d638ec8781"},{url:"icons/icon-512x512.png",revision:"8731edef999b9e7deba310d72a739925"},{url:"icons/icon-72x72.png",revision:"6b3cb1b2537ec91921698260a9c2f47c"},{url:"icons/icon-96x96.png",revision:"7efd757a81217207d981de88ef199d86"},{url:"index.html",revision:"52c85beb0841c0c7c8ddf774370cff39"},{url:"logo.svg",revision:"11616ede8898b4c24203e331b3ec6dc3"},{url:"icons/icon-72x72.png",revision:"6b3cb1b2537ec91921698260a9c2f47c"},{url:"icons/icon-96x96.png",revision:"7efd757a81217207d981de88ef199d86"},{url:"icons/icon-128x128.png",revision:"fa71db17e345406d5f7d847f88c65ac4"},{url:"icons/icon-144x144.png",revision:"e790ff42758ea1a2a46eb84201630757"},{url:"icons/icon-152x152.png",revision:"88f2400f6617a32cc9cd62c70fb49a05"},{url:"icons/icon-192x192.png",revision:"7d86d2d2ada99d7cee015dff0fdcb497"},{url:"icons/icon-384x384.png",revision:"c601fa602952a903389e5e8f8a699617"},{url:"icons/icon-512x512.png",revision:"8731edef999b9e7deba310d72a739925"},{url:"manifest.webmanifest",revision:"1c071cadebd7a1b0dc1eeb0270e73fb8"}],{}),e.cleanupOutdatedCaches(),e.registerRoute(new e.NavigationRoute(e.createHandlerBoundToURL("index.html"))),e.registerRoute(/^https:\/\/api\./i,new e.NetworkFirst({cacheName:"api-cache",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:50,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:png|jpg|jpeg|svg|gif|webp)$/i,new e.CacheFirst({cacheName:"image-cache",plugins:[new e.ExpirationPlugin({maxEntries:100,maxAgeSeconds:2592e3})]}),"GET")});
|
||||
if(!self.define){let e,n={};const i=(i,c)=>(i=new URL(i+".js",c).href,n[i]||new Promise(n=>{if("document"in self){const e=document.createElement("script");e.src=i,e.onload=n,document.head.appendChild(e)}else e=i,importScripts(i),n()}).then(()=>{let e=n[i];if(!e)throw new Error(`Module ${i} didn’t register its module`);return e}));self.define=(c,o)=>{const s=e||("document"in self?document.currentScript.src:"")||location.href;if(n[s])return;let a={};const r=e=>i(e,s),d={module:{uri:s},exports:a,require:r};n[s]=Promise.all(c.map(e=>d[e]||r(e))).then(e=>(o(...e),a))}}define(["./workbox-e20531c6"],function(e){"use strict";self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"assets/index-Czo9BXMw.js",revision:null},{url:"assets/index-d4V1QKN4.css",revision:null},{url:"icon.svg",revision:"0ec61aab261526d4c491e887a6f3374e"},{url:"icons/icon-128x128.png",revision:"fa71db17e345406d5f7d847f88c65ac4"},{url:"icons/icon-144x144.png",revision:"e790ff42758ea1a2a46eb84201630757"},{url:"icons/icon-152x152.png",revision:"88f2400f6617a32cc9cd62c70fb49a05"},{url:"icons/icon-16x16.png",revision:"101c13808e9fd0956f247bc446a8ac1e"},{url:"icons/icon-192x192.png",revision:"7d86d2d2ada99d7cee015dff0fdcb497"},{url:"icons/icon-32x32.png",revision:"22ee5d42535bc339ab0e19cb496378a5"},{url:"icons/icon-384x384.png",revision:"c601fa602952a903389e5e8f8a699617"},{url:"icons/icon-48x48.png",revision:"cfdd3bebd931375f2e0277d638ec8781"},{url:"icons/icon-512x512.png",revision:"8731edef999b9e7deba310d72a739925"},{url:"icons/icon-72x72.png",revision:"6b3cb1b2537ec91921698260a9c2f47c"},{url:"icons/icon-96x96.png",revision:"7efd757a81217207d981de88ef199d86"},{url:"index.html",revision:"b8f278b7bd4e55f30369e5de187d6eaa"},{url:"logo.svg",revision:"5962d0d24d9cd26cd8aaff9cb6f54a5a"},{url:"registerSW.js",revision:"1872c500de691dce40960bb85481de07"},{url:"icon.svg",revision:"0ec61aab261526d4c491e887a6f3374e"},{url:"icons/icon-192x192.png",revision:"7d86d2d2ada99d7cee015dff0fdcb497"},{url:"icons/icon-512x512.png",revision:"8731edef999b9e7deba310d72a739925"},{url:"icons/icon-72x72.png",revision:"6b3cb1b2537ec91921698260a9c2f47c"},{url:"icons/icon-96x96.png",revision:"7efd757a81217207d981de88ef199d86"},{url:"icons/icon-128x128.png",revision:"fa71db17e345406d5f7d847f88c65ac4"},{url:"icons/icon-144x144.png",revision:"e790ff42758ea1a2a46eb84201630757"},{url:"icons/icon-152x152.png",revision:"88f2400f6617a32cc9cd62c70fb49a05"},{url:"icons/icon-384x384.png",revision:"c601fa602952a903389e5e8f8a699617"},{url:"manifest.webmanifest",revision:"1c071cadebd7a1b0dc1eeb0270e73fb8"}],{}),e.cleanupOutdatedCaches(),e.registerRoute(new e.NavigationRoute(e.createHandlerBoundToURL("index.html"))),e.registerRoute(/^https:\/\/api\./,new e.NetworkFirst({cacheName:"api-cache",plugins:[new e.ExpirationPlugin({maxEntries:50,maxAgeSeconds:3600})]}),"GET"),e.registerRoute(/\/api\//,new e.NetworkFirst({cacheName:"api-cache-local",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:100,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\/uploads\//,new e.CacheFirst({cacheName:"uploads-cache",plugins:[new e.ExpirationPlugin({maxEntries:200,maxAgeSeconds:2592e3})]}),"GET"),e.registerRoute(/\.(?:png|jpg|jpeg|svg|gif|webp)$/,new e.CacheFirst({cacheName:"images-cache",plugins:[new e.ExpirationPlugin({maxEntries:100,maxAgeSeconds:2592e3})]}),"GET")});
|
||||
|
||||
@ -203,6 +203,43 @@ app.get("/sw.js", (req, res) => {
|
||||
res.sendFile(path.join(__dirname, "public", "sw.js"));
|
||||
});
|
||||
|
||||
// Service worker для dev режима
|
||||
const devDistPath = path.join(__dirname, "..", "dev-dist");
|
||||
app.get("/dev-sw.js", (req, res) => {
|
||||
res.setHeader("Content-Type", "application/javascript");
|
||||
res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
|
||||
const swPath = path.join(devDistPath, "sw.js");
|
||||
if (fs.existsSync(swPath)) {
|
||||
res.sendFile(swPath);
|
||||
} else {
|
||||
res.status(404).send("Service worker not found");
|
||||
}
|
||||
});
|
||||
|
||||
// RegisterSW для dev режима
|
||||
app.get("/registerSW.js", (req, res) => {
|
||||
res.setHeader("Content-Type", "application/javascript");
|
||||
res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
|
||||
const registerSWPath = path.join(devDistPath, "registerSW.js");
|
||||
if (fs.existsSync(registerSWPath)) {
|
||||
res.sendFile(registerSWPath);
|
||||
} else {
|
||||
res.status(404).send("registerSW.js not found");
|
||||
}
|
||||
});
|
||||
|
||||
// Workbox файлы для dev режима
|
||||
app.get("/workbox-:hash.js", (req, res) => {
|
||||
res.setHeader("Content-Type", "application/javascript");
|
||||
res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
|
||||
const workboxPath = path.join(devDistPath, `workbox-${req.params.hash}.js`);
|
||||
if (fs.existsSync(workboxPath)) {
|
||||
res.sendFile(workboxPath);
|
||||
} else {
|
||||
res.status(404).send("Workbox file not found");
|
||||
}
|
||||
});
|
||||
|
||||
app.get("/browserconfig.xml", (req, res) => {
|
||||
res.setHeader("Content-Type", "application/xml");
|
||||
res.setHeader("Cache-Control", "public, max-age=86400"); // 24 часа
|
||||
@ -793,19 +830,19 @@ app.get("/notes", requireAuth, (req, res) => {
|
||||
db.get(sql, [req.session.userId], (err, user) => {
|
||||
if (err) {
|
||||
console.error("Ошибка получения цвета пользователя:", err.message);
|
||||
return res.sendFile(path.join(__dirname, "public", "notes.html"));
|
||||
return res.sendFile(path.join(__dirname, "public", "index.html"));
|
||||
}
|
||||
|
||||
const accentColor = user?.accent_color || "#007bff";
|
||||
|
||||
// Читаем HTML файл
|
||||
fs.readFile(
|
||||
path.join(__dirname, "public", "notes.html"),
|
||||
path.join(__dirname, "public", "index.html"),
|
||||
"utf8",
|
||||
(err, html) => {
|
||||
if (err) {
|
||||
console.error("Ошибка чтения файла notes.html:", err.message);
|
||||
return res.sendFile(path.join(__dirname, "public", "notes.html"));
|
||||
console.error("Ошибка чтения файла index.html:", err.message);
|
||||
return res.sendFile(path.join(__dirname, "public", "index.html"));
|
||||
}
|
||||
|
||||
// Вставляем inline CSS с правильным цветом в самое начало head для предотвращения FOUC
|
||||
@ -1559,19 +1596,19 @@ app.get("/profile", requireAuth, (req, res) => {
|
||||
db.get(sql, [req.session.userId], (err, user) => {
|
||||
if (err) {
|
||||
console.error("Ошибка получения цвета пользователя:", err.message);
|
||||
return res.sendFile(path.join(__dirname, "public", "profile.html"));
|
||||
return res.sendFile(path.join(__dirname, "public", "index.html"));
|
||||
}
|
||||
|
||||
const accentColor = user?.accent_color || "#007bff";
|
||||
|
||||
// Читаем HTML файл
|
||||
fs.readFile(
|
||||
path.join(__dirname, "public", "profile.html"),
|
||||
path.join(__dirname, "public", "index.html"),
|
||||
"utf8",
|
||||
(err, html) => {
|
||||
if (err) {
|
||||
console.error("Ошибка чтения файла profile.html:", err.message);
|
||||
return res.sendFile(path.join(__dirname, "public", "profile.html"));
|
||||
console.error("Ошибка чтения файла index.html:", err.message);
|
||||
return res.sendFile(path.join(__dirname, "public", "index.html"));
|
||||
}
|
||||
|
||||
// Вставляем inline CSS с правильным цветом в самое начало head для предотвращения FOUC
|
||||
@ -2243,19 +2280,19 @@ app.get("/settings", requireAuth, (req, res) => {
|
||||
db.get(sql, [req.session.userId], (err, user) => {
|
||||
if (err) {
|
||||
console.error("Ошибка получения цвета пользователя:", err.message);
|
||||
return res.sendFile(path.join(__dirname, "public", "settings.html"));
|
||||
return res.sendFile(path.join(__dirname, "public", "index.html"));
|
||||
}
|
||||
|
||||
const accentColor = user?.accent_color || "#007bff";
|
||||
|
||||
// Читаем HTML файл
|
||||
fs.readFile(
|
||||
path.join(__dirname, "public", "settings.html"),
|
||||
path.join(__dirname, "public", "index.html"),
|
||||
"utf8",
|
||||
(err, html) => {
|
||||
if (err) {
|
||||
console.error("Ошибка чтения файла settings.html:", err.message);
|
||||
return res.sendFile(path.join(__dirname, "public", "settings.html"));
|
||||
console.error("Ошибка чтения файла index.html:", err.message);
|
||||
return res.sendFile(path.join(__dirname, "public", "index.html"));
|
||||
}
|
||||
|
||||
// Вставляем inline CSS с правильным цветом
|
||||
|
||||
@ -82,7 +82,7 @@ define(['./workbox-9dc17825'], (function (workbox) { 'use strict';
|
||||
"revision": "3ca0b8505b4bec776b69afdba2768812"
|
||||
}, {
|
||||
"url": "index.html",
|
||||
"revision": "0.fijdulj6fg"
|
||||
"revision": "0.q31tuubm2tg"
|
||||
}], {});
|
||||
workbox.cleanupOutdatedCaches();
|
||||
workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), {
|
||||
|
||||
@ -143,7 +143,8 @@ export default defineConfig({
|
||||
registerType: "prompt",
|
||||
devOptions: {
|
||||
enabled: true,
|
||||
type: "module",
|
||||
type: "classic",
|
||||
navigateFallback: "index.html",
|
||||
},
|
||||
}),
|
||||
],
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user