Files
2026-10-05 09:56:09 +03:00

109 lines
4.7 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { defineConfig } from 'vite';
import { VitePWA } from 'vite-plugin-pwa';
export default defineConfig({
// @sqlite.org/sqlite-wasm:
// - JS-часть идёт как ESM (sqlite3-bundler-friendly.mjs),
// - .wasm подхватывается относительно import.meta.url.
// Vite из коробки копирует такие ассеты в dist и переписывает URL,
// явно добавляем .wasm в assetsInclude и не оптимизируем пакет,
// чтобы dev-сервер отдавал оригинальный .wasm байт-в-байт.
assetsInclude: ['**/*.wasm'],
optimizeDeps: {
exclude: ['@sqlite.org/sqlite-wasm'],
},
worker: {
// Воркер БД (Шаг 2) будет в формате ESM — так sqlite-wasm работает корректно.
format: 'es',
},
server: {
headers: {
// Нужно для OPFS + SharedArrayBuffer (sqlite-wasm использует воркеры).
// COOP/COEP обязательны для crossOriginIsolated.
'Cross-Origin-Opener-Policy': 'same-origin',
'Cross-Origin-Embedder-Policy': 'require-corp',
},
},
preview: {
// Те же заголовки для `vite preview` — иначе прод-сборку локально
// не проверить: без COOP/COEP не будет crossOriginIsolated и OPFS-БД.
headers: {
'Cross-Origin-Opener-Policy': 'same-origin',
'Cross-Origin-Embedder-Policy': 'require-corp',
},
},
plugins: [
{
name: 'configure-response-headers',
configureServer: (server) => {
server.middlewares.use((_req, res, next) => {
res.setHeader('Cross-Origin-Embedder-Policy', 'require-corp');
res.setHeader('Cross-Origin-Opener-Policy', 'same-origin');
next();
});
},
},
// PWA: манифест + precache app shell (Workbox) + sw.js.
// Регистрацию SW делаем сами (injectRegister: null) — см. src/pwa.ts,
// чтобы показать баннер «Доступна новая версия».
VitePWA({
registerType: 'prompt',
injectRegister: null,
manifest: {
id: '/',
name: 'JapLearn — интервальные повторения',
short_name: 'JapLearn',
description: 'Японские слова, колоды и интервальные повторения. Работает офлайн.',
lang: 'ru',
dir: 'ltr',
start_url: '/',
scope: '/',
display: 'standalone',
orientation: 'portrait',
background_color: '#282828',
theme_color: '#282828',
categories: ['education'],
icons: [
{ src: '/icons/icon-192.png', sizes: '192x192', type: 'image/png', purpose: 'any' },
{ src: '/icons/icon-512.png', sizes: '512x512', type: 'image/png', purpose: 'any' },
{ src: '/icons/maskable-192.png', sizes: '192x192', type: 'image/png', purpose: 'maskable' },
{ src: '/icons/maskable-512.png', sizes: '512x512', type: 'image/png', purpose: 'maskable' },
],
},
workbox: {
// В precache идёт вся сборка: js/css/html, sqlite-wasm, иконки, сплэши.
globPatterns: ['**/*.{js,css,html,wasm,png,svg,webmanifest}'],
// Шрифт (8.8 МБ variable TTF) в precache не берём: он нужен только для
// отрисовки, кладём его в runtime-кэш CacheFirst ниже.
globIgnores: ['**/fonts/*.ttf'],
maximumFileSizeToCacheInBytes: 5 * 1024 * 1024,
// SPA без URL-роутинга: любая навигация отдаётся из кэша index.html.
navigateFallback: '/index.html',
cleanupOutdatedCaches: true,
clientsClaim: true,
runtimeCaching: [
{
// Локальный шрифт: после первой загрузки работает офлайн.
urlPattern: /\/fonts\/.*\.ttf$/,
handler: 'CacheFirst',
options: {
cacheName: 'japlearn-fonts',
expiration: { maxEntries: 4 },
cacheableResponse: { statuses: [0, 200] },
},
},
{
// Синхронизация (скачивание .sqlite) — только сеть, никакого кэша.
urlPattern: /^https:\/\/learning\.micialware\.ru\//,
handler: 'NetworkOnly',
},
],
},
devOptions: {
// В dev SW не нужен и мешает отладке кэша (HMR + OPFS).
enabled: false,
},
}),
],
});