From d1a3853449c2a5f3385f590a834eac9a8c7b9f42 Mon Sep 17 00:00:00 2001 From: Fovway Date: Tue, 4 Nov 2025 12:21:47 +0700 Subject: [PATCH] =?UTF-8?q?=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=20.gitignore=20=D0=B4=D0=BB=D1=8F=20=D0=B8=D1=81=D0=BA?= =?UTF-8?q?=D0=BB=D1=8E=D1=87=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=BD=D0=BE=D0=B2?= =?UTF-8?q?=D1=8B=D1=85=20=D0=B0=D1=80=D1=82=D0=B5=D1=84=D0=B0=D0=BA=D1=82?= =?UTF-8?q?=D0=BE=D0=B2=20=D1=81=D0=B1=D0=BE=D1=80=D0=BA=D0=B8=20=D0=B8=20?= =?UTF-8?q?=D0=B2=D1=80=D0=B5=D0=BC=D0=B5=D0=BD=D0=BD=D1=8B=D1=85=20=D1=84?= =?UTF-8?q?=D0=B0=D0=B9=D0=BB=D0=BE=D0=B2.=20=D0=98=D0=B7=D0=BC=D0=B5?= =?UTF-8?q?=D0=BD=D0=B5=D0=BD=20=D1=82=D0=B8=D0=BF=20=D0=B2=20=D0=BA=D0=BE?= =?UTF-8?q?=D0=BD=D1=84=D0=B8=D0=B3=D1=83=D1=80=D0=B0=D1=86=D0=B8=D0=B8=20?= =?UTF-8?q?Vite=20=D0=BD=D0=B0=20"classic"=20=D1=81=20=D0=B4=D0=BE=D0=B1?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=D0=BC=20navigateFall?= =?UTF-8?q?back.=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D1=8B?= =?UTF-8?q?=20=D0=BD=D0=BE=D0=B2=D1=8B=D0=B5=20=D0=BC=D0=B0=D1=80=D1=88?= =?UTF-8?q?=D1=80=D1=83=D1=82=D1=8B=20=D0=B4=D0=BB=D1=8F=20=D0=BE=D0=B1?= =?UTF-8?q?=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=BA=D0=B8=20=D1=81=D0=B5=D1=80?= =?UTF-8?q?=D0=B2=D0=B8=D1=81=D0=BD=D0=BE=D0=B3=D0=BE=20=D1=80=D0=B0=D0=B1?= =?UTF-8?q?=D0=BE=D1=87=D0=B5=D0=B3=D0=BE=20=D1=81=D0=BA=D1=80=D0=B8=D0=BF?= =?UTF-8?q?=D1=82=D0=B0=20=D0=B2=20dev=20=D1=80=D0=B5=D0=B6=D0=B8=D0=BC?= =?UTF-8?q?=D0=B5,=20=D0=B2=D0=BA=D0=BB=D1=8E=D1=87=D0=B0=D1=8F=20=D0=BF?= =?UTF-8?q?=D0=BE=D0=B4=D0=B4=D0=B5=D1=80=D0=B6=D0=BA=D1=83=20dev-sw.js=20?= =?UTF-8?q?=D0=B8=20registerSW.js.=20=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=20index.html=20=D0=B4=D0=BB=D1=8F=20=D1=83=D0=BB?= =?UTF-8?q?=D1=83=D1=87=D1=88=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=BF=D0=BE=D0=BB?= =?UTF-8?q?=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D0=B5=D0=BB=D1=8C=D1=81?= =?UTF-8?q?=D0=BA=D0=BE=D0=B3=D0=BE=20=D0=BE=D0=BF=D1=8B=D1=82=D0=B0=20?= =?UTF-8?q?=D1=81=20=D0=B8=D0=BD=D0=B4=D0=B8=D0=BA=D0=B0=D1=82=D0=BE=D1=80?= =?UTF-8?q?=D0=BE=D0=BC=20=D0=B7=D0=B0=D0=B3=D1=80=D1=83=D0=B7=D0=BA=D0=B8?= =?UTF-8?q?.=20=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB=D0=B5=D0=BD=20=D0=BC?= =?UTF-8?q?=D0=B0=D0=BD=D0=B8=D1=84=D0=B5=D1=81=D1=82=20=D0=B8=20=D1=81?= =?UTF-8?q?=D0=B5=D1=80=D0=B2=D0=B8=D1=81=D0=BD=D1=8B=D0=B9=20=D1=80=D0=B0?= =?UTF-8?q?=D0=B1=D0=BE=D1=87=D0=B8=D0=B9=20=D1=81=D0=BA=D1=80=D0=B8=D0=BF?= =?UTF-8?q?=D1=82=20=D0=B4=D0=BB=D1=8F=20=D1=83=D0=BB=D1=83=D1=87=D1=88?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=BA=D1=8D=D1=88=D0=B8=D1=80=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0=D0=BD=D0=B8=D1=8F=20=D0=B8=20=D0=BE=D0=B1=D1=80?= =?UTF-8?q?=D0=B0=D0=B1=D0=BE=D1=82=D0=BA=D0=B8=20=D0=B7=D0=B0=D0=BF=D1=80?= =?UTF-8?q?=D0=BE=D1=81=D0=BE=D0=B2.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 35 +++- backend/public/index.html | 352 +++++++++++++++++++++-------------- backend/public/manifest.json | 17 -- backend/public/sw.js | 2 +- backend/server.js | 61 ++++-- dev-dist/sw.js | 2 +- vite.config.ts | 3 +- 7 files changed, 297 insertions(+), 175 deletions(-) diff --git a/.gitignore b/.gitignore index 78a64ad..4a546d8 100644 --- a/.gitignore +++ b/.gitignore @@ -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 diff --git a/backend/public/index.html b/backend/public/index.html index fd7cee9..cb9ad94 100644 --- a/backend/public/index.html +++ b/backend/public/index.html @@ -1,69 +1,69 @@ - - - - - - NoteJS - Система заметок - - - - - + + + + + + NoteJS - Система заметок + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+ + + diff --git a/backend/public/manifest.json b/backend/public/manifest.json index ac17bce..ad0f651 100644 --- a/backend/public/manifest.json +++ b/backend/public/manifest.json @@ -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", diff --git a/backend/public/sw.js b/backend/public/sw.js index 0f41c4a..d2cb491 100644 --- a/backend/public/sw.js +++ b/backend/public/sw.js @@ -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")}); diff --git a/backend/server.js b/backend/server.js index b93897a..e2a9fce 100644 --- a/backend/server.js +++ b/backend/server.js @@ -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 с правильным цветом diff --git a/dev-dist/sw.js b/dev-dist/sw.js index 04d17d9..66cc4be 100644 --- a/dev-dist/sw.js +++ b/dev-dist/sw.js @@ -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"), { diff --git a/vite.config.ts b/vite.config.ts index d7e1ff5..ba6dd44 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -143,7 +143,8 @@ export default defineConfig({ registerType: "prompt", devOptions: { enabled: true, - type: "module", + type: "classic", + navigateFallback: "index.html", }, }), ],