Добавлены улучшения в конфигурацию Vite для PWA, включая обработку ошибок при кэшировании и фильтрацию манифеста. Обновлен серверный код для корректного возврата статуса аутентификации. Внесены изменения в клиентскую логику Axios для исключения определенных запросов из автоматического разлогинивания. Обновлен HTML-шаблон с улучшениями в загрузке и отображении темы.
This commit is contained in:
parent
e6ebf2cbff
commit
2c23044ea4
@ -1,69 +1,69 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="ru">
|
<html lang="ru">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta
|
<meta
|
||||||
name="viewport"
|
name="viewport"
|
||||||
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
|
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
|
||||||
/>
|
/>
|
||||||
<title>NoteJS - Система заметок</title>
|
<title>NoteJS - Система заметок</title>
|
||||||
|
|
||||||
<!-- Предотвращение мерцания темы -->
|
<!-- Предотвращение мерцания темы -->
|
||||||
<script>
|
<script>
|
||||||
(function () {
|
(function () {
|
||||||
try {
|
try {
|
||||||
// Получаем сохраненную тему
|
// Получаем сохраненную тему
|
||||||
const savedTheme = localStorage.getItem("theme");
|
const savedTheme = localStorage.getItem("theme");
|
||||||
// Получаем системные предпочтения
|
// Получаем системные предпочтения
|
||||||
const systemPrefersDark = window.matchMedia(
|
const systemPrefersDark = window.matchMedia(
|
||||||
"(prefers-color-scheme: dark)"
|
"(prefers-color-scheme: dark)"
|
||||||
).matches;
|
).matches;
|
||||||
|
|
||||||
// Определяем тему: сохраненная или системная
|
// Определяем тему: сохраненная или системная
|
||||||
const theme = savedTheme || (systemPrefersDark ? "dark" : "light");
|
const theme = savedTheme || (systemPrefersDark ? "dark" : "light");
|
||||||
|
|
||||||
// Функция для конвертации hex в RGB
|
// Функция для конвертации hex в RGB
|
||||||
function hexToRgb(hex) {
|
function hexToRgb(hex) {
|
||||||
const cleanHex = hex.replace("#", "");
|
const cleanHex = hex.replace("#", "");
|
||||||
const r = parseInt(cleanHex.substring(0, 2), 16);
|
const r = parseInt(cleanHex.substring(0, 2), 16);
|
||||||
const g = parseInt(cleanHex.substring(2, 4), 16);
|
const g = parseInt(cleanHex.substring(2, 4), 16);
|
||||||
const b = parseInt(cleanHex.substring(4, 6), 16);
|
const b = parseInt(cleanHex.substring(4, 6), 16);
|
||||||
return `${r}, ${g}, ${b}`;
|
return `${r}, ${g}, ${b}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Получаем и устанавливаем accentColor
|
// Получаем и устанавливаем accentColor
|
||||||
const savedAccentColor = localStorage.getItem("accentColor");
|
const savedAccentColor = localStorage.getItem("accentColor");
|
||||||
const accentColor = savedAccentColor || "#007bff";
|
const accentColor = savedAccentColor || "#007bff";
|
||||||
|
|
||||||
// Устанавливаем тему и переменные до загрузки CSS
|
// Устанавливаем тему и переменные до загрузки CSS
|
||||||
if (theme === "dark") {
|
if (theme === "dark") {
|
||||||
document.documentElement.setAttribute("data-theme", "dark");
|
document.documentElement.setAttribute("data-theme", "dark");
|
||||||
} else {
|
} else {
|
||||||
document.documentElement.setAttribute("data-theme", "light");
|
document.documentElement.setAttribute("data-theme", "light");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Устанавливаем CSS переменные для accent цвета
|
// Устанавливаем CSS переменные для accent цвета
|
||||||
document.documentElement.style.setProperty("--accent-color", accentColor);
|
document.documentElement.style.setProperty("--accent-color", accentColor);
|
||||||
document.documentElement.style.setProperty("--accent-color-rgb", hexToRgb(accentColor));
|
document.documentElement.style.setProperty("--accent-color-rgb", hexToRgb(accentColor));
|
||||||
|
|
||||||
// Устанавливаем цвет для meta theme-color
|
// Устанавливаем цвет для meta theme-color
|
||||||
const themeColorMeta = document.querySelector('meta[name="theme-color"]');
|
const themeColorMeta = document.querySelector('meta[name="theme-color"]');
|
||||||
if (themeColorMeta) {
|
if (themeColorMeta) {
|
||||||
themeColorMeta.setAttribute(
|
themeColorMeta.setAttribute(
|
||||||
"content",
|
"content",
|
||||||
theme === "dark" ? "#1a1a1a" : accentColor
|
theme === "dark" ? "#1a1a1a" : accentColor
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// В случае ошибки устанавливаем светлую тему по умолчанию
|
// В случае ошибки устанавливаем светлую тему по умолчанию
|
||||||
document.documentElement.setAttribute("data-theme", "light");
|
document.documentElement.setAttribute("data-theme", "light");
|
||||||
document.documentElement.style.setProperty("--accent-color", "#007bff");
|
document.documentElement.style.setProperty("--accent-color", "#007bff");
|
||||||
document.documentElement.style.setProperty("--accent-color-rgb", "0, 123, 255");
|
document.documentElement.style.setProperty("--accent-color-rgb", "0, 123, 255");
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- Критические стили темы для предотвращения flash эффекта -->
|
<!-- Критические стили темы для предотвращения flash эффекта -->
|
||||||
<style>
|
<style>
|
||||||
:root {
|
:root {
|
||||||
--accent-color: #007bff;
|
--accent-color: #007bff;
|
||||||
@ -89,94 +89,94 @@
|
|||||||
color: var(--text-primary);
|
color: var(--text-primary);
|
||||||
transition: background-color 0.3s ease, color 0.3s ease;
|
transition: background-color 0.3s ease, color 0.3s ease;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<!-- PWA Meta Tags -->
|
<!-- PWA Meta Tags -->
|
||||||
<meta
|
<meta
|
||||||
name="description"
|
name="description"
|
||||||
content="NoteJS - современная система заметок с поддержкой Markdown, изображений, тегов и календаря"
|
content="NoteJS - современная система заметок с поддержкой Markdown, изображений, тегов и календаря"
|
||||||
/>
|
/>
|
||||||
<meta name="theme-color" content="#007bff" />
|
<meta name="theme-color" content="#007bff" />
|
||||||
<meta name="mobile-web-app-capable" content="yes" />
|
<meta name="mobile-web-app-capable" content="yes" />
|
||||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||||
<meta
|
<meta
|
||||||
name="apple-mobile-web-app-status-bar-style"
|
name="apple-mobile-web-app-status-bar-style"
|
||||||
content="black-translucent"
|
content="black-translucent"
|
||||||
/>
|
/>
|
||||||
<meta name="apple-mobile-web-app-title" content="NoteJS" />
|
<meta name="apple-mobile-web-app-title" content="NoteJS" />
|
||||||
<meta name="apple-touch-fullscreen" content="yes" />
|
<meta name="apple-touch-fullscreen" content="yes" />
|
||||||
<meta name="msapplication-TileColor" content="#007bff" />
|
<meta name="msapplication-TileColor" content="#007bff" />
|
||||||
<meta name="msapplication-config" content="/browserconfig.xml" />
|
<meta name="msapplication-config" content="/browserconfig.xml" />
|
||||||
<meta name="msapplication-TileImage" content="/icons/icon-144x144.png" />
|
<meta name="msapplication-TileImage" content="/icons/icon-144x144.png" />
|
||||||
<meta name="application-name" content="NoteJS" />
|
<meta name="application-name" content="NoteJS" />
|
||||||
<meta name="format-detection" content="telephone=no" />
|
<meta name="format-detection" content="telephone=no" />
|
||||||
|
|
||||||
<!-- Icons -->
|
<!-- Icons -->
|
||||||
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
|
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
|
||||||
<link
|
<link
|
||||||
rel="icon"
|
rel="icon"
|
||||||
type="image/png"
|
type="image/png"
|
||||||
sizes="32x32"
|
sizes="32x32"
|
||||||
href="/icons/icon-32x32.png"
|
href="/icons/icon-32x32.png"
|
||||||
/>
|
/>
|
||||||
<link
|
<link
|
||||||
rel="icon"
|
rel="icon"
|
||||||
type="image/png"
|
type="image/png"
|
||||||
sizes="16x16"
|
sizes="16x16"
|
||||||
href="/icons/icon-16x16.png"
|
href="/icons/icon-16x16.png"
|
||||||
/>
|
/>
|
||||||
<link rel="apple-touch-icon" sizes="57x57" href="/icons/icon-48x48.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="60x60" href="/icons/icon-48x48.png" />
|
||||||
<link rel="apple-touch-icon" sizes="72x72" href="/icons/icon-72x72.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="76x76" href="/icons/icon-72x72.png" />
|
||||||
<link
|
<link
|
||||||
rel="apple-touch-icon"
|
rel="apple-touch-icon"
|
||||||
sizes="114x114"
|
sizes="114x114"
|
||||||
href="/icons/icon-128x128.png"
|
href="/icons/icon-128x128.png"
|
||||||
/>
|
/>
|
||||||
<link
|
<link
|
||||||
rel="apple-touch-icon"
|
rel="apple-touch-icon"
|
||||||
sizes="120x120"
|
sizes="120x120"
|
||||||
href="/icons/icon-128x128.png"
|
href="/icons/icon-128x128.png"
|
||||||
/>
|
/>
|
||||||
<link
|
<link
|
||||||
rel="apple-touch-icon"
|
rel="apple-touch-icon"
|
||||||
sizes="144x144"
|
sizes="144x144"
|
||||||
href="/icons/icon-144x144.png"
|
href="/icons/icon-144x144.png"
|
||||||
/>
|
/>
|
||||||
<link
|
<link
|
||||||
rel="apple-touch-icon"
|
rel="apple-touch-icon"
|
||||||
sizes="152x152"
|
sizes="152x152"
|
||||||
href="/icons/icon-152x152.png"
|
href="/icons/icon-152x152.png"
|
||||||
/>
|
/>
|
||||||
<link
|
<link
|
||||||
rel="apple-touch-icon"
|
rel="apple-touch-icon"
|
||||||
sizes="180x180"
|
sizes="180x180"
|
||||||
href="/icons/icon-192x192.png"
|
href="/icons/icon-192x192.png"
|
||||||
/>
|
/>
|
||||||
<link rel="mask-icon" href="/icon.svg" color="#007bff" />
|
<link rel="mask-icon" href="/icon.svg" color="#007bff" />
|
||||||
|
|
||||||
<!-- Manifest -->
|
<!-- Manifest -->
|
||||||
<link rel="manifest" href="/manifest.json" />
|
<link rel="manifest" href="/manifest.json" />
|
||||||
<script type="module" crossorigin src="/assets/index-42KwbWCP.js"></script>
|
<script type="module" crossorigin src="/assets/index-42KwbWCP.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/assets/index-DK8OUj6L.css">
|
<link rel="stylesheet" crossorigin href="/assets/index-DK8OUj6L.css">
|
||||||
<link rel="manifest" href="/manifest.webmanifest"><script id="vite-plugin-pwa:register-sw" src="/registerSW.js"></script></head>
|
<link rel="manifest" href="/manifest.webmanifest"><script id="vite-plugin-pwa:register-sw" src="/registerSW.js"></script></head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root">
|
<div id="root">
|
||||||
<!-- Индикатор загрузки до монтирования React -->
|
<!-- Индикатор загрузки до монтирования React -->
|
||||||
<div id="initial-loading" style="
|
<div id="initial-loading" style="
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background-color: var(--bg-primary);
|
background-color: var(--bg-primary);
|
||||||
color: var(--text-primary);
|
color: var(--text-primary);
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
z-index: 9999;
|
z-index: 9999;
|
||||||
">
|
">
|
||||||
<style>
|
<style>
|
||||||
#initial-loading-spinner {
|
#initial-loading-spinner {
|
||||||
width: 50px;
|
width: 50px;
|
||||||
@ -193,43 +193,43 @@
|
|||||||
@keyframes initial-loading-spin {
|
@keyframes initial-loading-spin {
|
||||||
to { transform: rotate(360deg); }
|
to { transform: rotate(360deg); }
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<div id="initial-loading-spinner"></div>
|
<div id="initial-loading-spinner"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
// Скрываем индикатор загрузки сразу после загрузки DOM
|
// Скрываем индикатор загрузки сразу после загрузки DOM
|
||||||
// React удалит этот элемент при первом рендере через createRoot
|
// React удалит этот элемент при первом рендере через createRoot
|
||||||
(function() {
|
(function() {
|
||||||
// Используем MutationObserver для отслеживания изменений в #root
|
// Используем MutationObserver для отслеживания изменений в #root
|
||||||
const observer = new MutationObserver(function(mutations) {
|
const observer = new MutationObserver(function(mutations) {
|
||||||
mutations.forEach(function(mutation) {
|
mutations.forEach(function(mutation) {
|
||||||
// Если React начал добавлять элементы в #root, удаляем индикатор
|
// Если React начал добавлять элементы в #root, удаляем индикатор
|
||||||
if (mutation.addedNodes.length > 0) {
|
if (mutation.addedNodes.length > 0) {
|
||||||
const loadingEl = document.getElementById('initial-loading');
|
const loadingEl = document.getElementById('initial-loading');
|
||||||
if (loadingEl && loadingEl.parentNode) {
|
if (loadingEl && loadingEl.parentNode) {
|
||||||
loadingEl.parentNode.removeChild(loadingEl);
|
loadingEl.parentNode.removeChild(loadingEl);
|
||||||
}
|
}
|
||||||
observer.disconnect();
|
observer.disconnect();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Начинаем наблюдение за изменениями в #root
|
// Начинаем наблюдение за изменениями в #root
|
||||||
const root = document.getElementById('root');
|
const root = document.getElementById('root');
|
||||||
if (root) {
|
if (root) {
|
||||||
observer.observe(root, { childList: true, subtree: true });
|
observer.observe(root, { childList: true, subtree: true });
|
||||||
|
|
||||||
// Фолбэк: если через 2 секунды элемент все еще есть, удаляем вручную
|
// Фолбэк: если через 2 секунды элемент все еще есть, удаляем вручную
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
const loadingEl = document.getElementById('initial-loading');
|
const loadingEl = document.getElementById('initial-loading');
|
||||||
if (loadingEl && loadingEl.parentNode) {
|
if (loadingEl && loadingEl.parentNode) {
|
||||||
loadingEl.parentNode.removeChild(loadingEl);
|
loadingEl.parentNode.removeChild(loadingEl);
|
||||||
}
|
}
|
||||||
observer.disconnect();
|
observer.disconnect();
|
||||||
}, 2000);
|
}, 2000);
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
1
backend/public/registerSW.js
Normal file
1
backend/public/registerSW.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
if('serviceWorker' in navigator) {window.addEventListener('load', () => {navigator.serviceWorker.register('/sw.js', { scope: '/' })})}
|
||||||
@ -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,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 a={};const r=e=>n(e,s),d={module:{uri:s},exports:a,require:r};i[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-42KwbWCP.js",revision:"51ac27da669f96309cb113e80898bdf5"},{url:"assets/index-DK8OUj6L.css",revision:"b1e2c4e8724be2f2bcee585338910e99"},{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:"178618f2f59ad9a7efec06e2fb7ab7e6"},{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"}],{ignoreURLParametersMatching:[/^utm_/,/^fbclid$/]}),e.cleanupOutdatedCaches(),e.registerRoute(new e.NavigationRoute(e.createHandlerBoundToURL("/index.html"),{denylist:[/^\/api/,/^\/uploads/]})),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")});
|
||||||
|
|||||||
1
backend/public/workbox-e20531c6.js
Normal file
1
backend/public/workbox-e20531c6.js
Normal file
File diff suppressed because one or more lines are too long
@ -785,7 +785,8 @@ app.get("/api/auth/status", (req, res) => {
|
|||||||
username: req.session.username,
|
username: req.session.username,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
res.status(401).json({ authenticated: false });
|
// Возвращаем 200, так как неавторизованное состояние - это норма, а не ошибка
|
||||||
|
res.status(200).json({ authenticated: false });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -42,13 +42,23 @@ axiosClient.interceptors.response.use(
|
|||||||
"/user/delete-account", // Удаление аккаунта
|
"/user/delete-account", // Удаление аккаунта
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// URL, где 401 не должен обрабатываться как ошибка сессии
|
||||||
|
const statusCheckUrls = [
|
||||||
|
"/auth/status", // Проверка статуса аутентификации
|
||||||
|
];
|
||||||
|
|
||||||
// Проверяем, является ли это запросом с проверкой пароля
|
// Проверяем, является ли это запросом с проверкой пароля
|
||||||
const isPasswordProtected = passwordProtectedUrls.some((url) =>
|
const isPasswordProtected = passwordProtectedUrls.some((url) =>
|
||||||
error.config?.url?.includes(url)
|
error.config?.url?.includes(url)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Разлогиниваем только если это НЕ запрос с проверкой пароля
|
// Проверяем, является ли это запросом проверки статуса
|
||||||
if (!isPasswordProtected) {
|
const isStatusCheck = statusCheckUrls.some((url) =>
|
||||||
|
error.config?.url?.includes(url)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Разлогиниваем только если это НЕ запрос с проверкой пароля и НЕ проверка статуса
|
||||||
|
if (!isPasswordProtected && !isStatusCheck) {
|
||||||
// Очищаем IndexedDB при автоматическом разлогинивании
|
// Очищаем IndexedDB при автоматическом разлогинивании
|
||||||
dbManager.clearAll().catch((err) => {
|
dbManager.clearAll().catch((err) => {
|
||||||
console.error("Ошибка очистки IndexedDB при 401:", err);
|
console.error("Ошибка очистки IndexedDB при 401:", err);
|
||||||
|
|||||||
@ -89,6 +89,29 @@ export default defineConfig({
|
|||||||
},
|
},
|
||||||
workbox: {
|
workbox: {
|
||||||
globPatterns: ["**/*.{js,css,html,ico,png,svg,woff,woff2,ttf,eot}"],
|
globPatterns: ["**/*.{js,css,html,ico,png,svg,woff,woff2,ttf,eot}"],
|
||||||
|
// Игнорируем параметры URL при кешировании
|
||||||
|
ignoreURLParametersMatching: [/^utm_/, /^fbclid$/],
|
||||||
|
// Обработка ошибок при precaching - не падаем на 404
|
||||||
|
navigateFallback: "/index.html",
|
||||||
|
navigateFallbackDenylist: [/^\/api/, /^\/uploads/],
|
||||||
|
// Обработка ошибок при загрузке файлов для precaching
|
||||||
|
dontCacheBustURLsMatching: /\.\w{8}\./,
|
||||||
|
// Фильтруем манифест, чтобы исключить несуществующие файлы и дубликаты
|
||||||
|
manifestTransforms: [
|
||||||
|
async (manifestEntries) => {
|
||||||
|
// Фильтруем дубликаты
|
||||||
|
const seen = new Set<string>();
|
||||||
|
const filtered = manifestEntries.filter((entry) => {
|
||||||
|
// Удаляем дубликаты
|
||||||
|
if (seen.has(entry.url)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
seen.add(entry.url);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
return { manifest: filtered, warnings: [] };
|
||||||
|
},
|
||||||
|
],
|
||||||
runtimeCaching: [
|
runtimeCaching: [
|
||||||
{
|
{
|
||||||
urlPattern: /^https:\/\/api\./,
|
urlPattern: /^https:\/\/api\./,
|
||||||
@ -139,6 +162,8 @@ export default defineConfig({
|
|||||||
cleanupOutdatedCaches: true,
|
cleanupOutdatedCaches: true,
|
||||||
skipWaiting: true,
|
skipWaiting: true,
|
||||||
clientsClaim: true,
|
clientsClaim: true,
|
||||||
|
// Обработка ошибок при precaching - игнорируем 404 ошибки
|
||||||
|
maximumFileSizeToCacheInBytes: 5 * 1024 * 1024, // 5MB
|
||||||
},
|
},
|
||||||
registerType: "prompt",
|
registerType: "prompt",
|
||||||
devOptions: {
|
devOptions: {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user