234 lines
7.4 KiB
TypeScript
234 lines
7.4 KiB
TypeScript
import { defineConfig } from "vite";
|
||
import react from "@vitejs/plugin-react";
|
||
import { VitePWA } from "vite-plugin-pwa";
|
||
|
||
// https://vitejs.dev/config/
|
||
export default defineConfig({
|
||
plugins: [
|
||
react(),
|
||
VitePWA({
|
||
injectRegister: "auto",
|
||
includeAssets: [
|
||
"icon.svg",
|
||
"icons/icon-192x192.png",
|
||
"icons/icon-512x512.png",
|
||
],
|
||
manifest: {
|
||
name: "NoteJS - Система заметок",
|
||
short_name: "NoteJS",
|
||
description:
|
||
"Современная система заметок с поддержкой Markdown, изображений, тегов и календаря",
|
||
theme_color: "#007bff",
|
||
background_color: "#ffffff",
|
||
display: "standalone",
|
||
orientation: "portrait-primary",
|
||
scope: "/",
|
||
start_url: "/",
|
||
icons: [
|
||
{
|
||
src: "/icons/icon-72x72.png",
|
||
sizes: "72x72",
|
||
type: "image/png",
|
||
purpose: "any",
|
||
},
|
||
{
|
||
src: "/icons/icon-96x96.png",
|
||
sizes: "96x96",
|
||
type: "image/png",
|
||
purpose: "any",
|
||
},
|
||
{
|
||
src: "/icons/icon-128x128.png",
|
||
sizes: "128x128",
|
||
type: "image/png",
|
||
purpose: "any",
|
||
},
|
||
{
|
||
src: "/icons/icon-144x144.png",
|
||
sizes: "144x144",
|
||
type: "image/png",
|
||
purpose: "any",
|
||
},
|
||
{
|
||
src: "/icons/icon-152x152.png",
|
||
sizes: "152x152",
|
||
type: "image/png",
|
||
purpose: "any",
|
||
},
|
||
{
|
||
src: "/icons/icon-192x192.png",
|
||
sizes: "192x192",
|
||
type: "image/png",
|
||
purpose: "any",
|
||
},
|
||
{
|
||
src: "/icons/icon-384x384.png",
|
||
sizes: "384x384",
|
||
type: "image/png",
|
||
purpose: "any",
|
||
},
|
||
{
|
||
src: "/icons/icon-512x512.png",
|
||
sizes: "512x512",
|
||
type: "image/png",
|
||
purpose: "any",
|
||
},
|
||
{
|
||
src: "/icons/icon-192x192.png",
|
||
sizes: "192x192",
|
||
type: "image/png",
|
||
purpose: "maskable",
|
||
},
|
||
{
|
||
src: "/icons/icon-512x512.png",
|
||
sizes: "512x512",
|
||
type: "image/png",
|
||
purpose: "maskable",
|
||
},
|
||
],
|
||
},
|
||
workbox: {
|
||
globPatterns: ["**/*.{js,css,html,ico,png,svg,woff,woff2,ttf,eot}"],
|
||
// Игнорируем параметры URL при кешировании
|
||
ignoreURLParametersMatching: [/^utm_/, /^fbclid$/],
|
||
// Обработка навигации - всегда используем кэшированную версию
|
||
navigateFallback: "/index.html",
|
||
navigateFallbackDenylist: [/^\/api/, /^\/uploads/],
|
||
// Стратегия для навигационных запросов - сначала кэш
|
||
navigationPreload: false,
|
||
// Обработка ошибок при загрузке файлов для 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: [
|
||
// HTML документы - всегда сначала кэш для оффлайн работы
|
||
// Это гарантирует, что при обновлении страницы в оффлайн режиме
|
||
// всегда будет загружаться кэшированная версия БЕЗ попыток обращения к сети
|
||
{
|
||
urlPattern: ({ request }) => request.mode === 'navigate',
|
||
handler: "CacheFirst",
|
||
options: {
|
||
cacheName: "pages-cache",
|
||
expiration: {
|
||
maxEntries: 10,
|
||
maxAgeSeconds: 7 * 24 * 60 * 60, // 7 days
|
||
},
|
||
cacheableResponse: {
|
||
statuses: [0, 200],
|
||
},
|
||
},
|
||
},
|
||
// Дополнительное правило для HTML файлов
|
||
{
|
||
urlPattern: /\.html$/,
|
||
handler: "CacheFirst",
|
||
options: {
|
||
cacheName: "html-cache",
|
||
expiration: {
|
||
maxEntries: 10,
|
||
maxAgeSeconds: 7 * 24 * 60 * 60, // 7 days
|
||
},
|
||
cacheableResponse: {
|
||
statuses: [0, 200],
|
||
},
|
||
},
|
||
},
|
||
{
|
||
urlPattern: /^https:\/\/api\./,
|
||
handler: "NetworkFirst",
|
||
options: {
|
||
cacheName: "api-cache",
|
||
expiration: {
|
||
maxEntries: 50,
|
||
maxAgeSeconds: 60 * 60, // 1 hour
|
||
},
|
||
},
|
||
},
|
||
{
|
||
urlPattern: /\/api\//,
|
||
handler: "NetworkFirst",
|
||
options: {
|
||
cacheName: "api-cache-local",
|
||
expiration: {
|
||
maxEntries: 100,
|
||
maxAgeSeconds: 24 * 60 * 60, // 24 hours
|
||
},
|
||
networkTimeoutSeconds: 10,
|
||
},
|
||
},
|
||
{
|
||
urlPattern: /\/uploads\//,
|
||
handler: "CacheFirst",
|
||
options: {
|
||
cacheName: "uploads-cache",
|
||
expiration: {
|
||
maxEntries: 200,
|
||
maxAgeSeconds: 30 * 24 * 60 * 60, // 30 days
|
||
},
|
||
},
|
||
},
|
||
{
|
||
urlPattern: /\.(?:png|jpg|jpeg|svg|gif|webp)$/,
|
||
handler: "CacheFirst",
|
||
options: {
|
||
cacheName: "images-cache",
|
||
expiration: {
|
||
maxEntries: 100,
|
||
maxAgeSeconds: 30 * 24 * 60 * 60, // 30 days
|
||
},
|
||
},
|
||
},
|
||
],
|
||
cleanupOutdatedCaches: true,
|
||
skipWaiting: true,
|
||
clientsClaim: true,
|
||
// Обработка ошибок при precaching - игнорируем 404 ошибки
|
||
maximumFileSizeToCacheInBytes: 5 * 1024 * 1024, // 5MB
|
||
},
|
||
// Автоматическое обновление SW без запроса пользователя
|
||
// для обеспечения стабильной работы в оффлайн режиме
|
||
registerType: "autoUpdate",
|
||
devOptions: {
|
||
enabled: true,
|
||
type: "module",
|
||
},
|
||
}),
|
||
],
|
||
server: {
|
||
port: 5173,
|
||
allowedHosts: ["app.notejs.ru", "localhost"],
|
||
proxy: {
|
||
"/api": {
|
||
target: "http://localhost:3001",
|
||
changeOrigin: true,
|
||
secure: false,
|
||
ws: true,
|
||
},
|
||
"/uploads": {
|
||
target: "http://localhost:3001",
|
||
changeOrigin: true,
|
||
secure: false,
|
||
},
|
||
"/logout": {
|
||
target: "http://localhost:3001",
|
||
changeOrigin: true,
|
||
secure: false,
|
||
},
|
||
},
|
||
},
|
||
});
|