Files
bookorbit/client/vite.config.ts
T
neon 92ade7dbba i18n(client): migrate plural messages to ICU MessageFormat
Replace pipe-delimited Vue I18n plural messages with ICU MessageFormat syntax across all locale catalogs and Vue components. Configure custom message formatting and validation to enforce ICU syntax and argument parity.

Closes #792
2026-07-27 01:28:52 +00:00

161 lines
4.4 KiB
TypeScript

import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueDevTools from 'vite-plugin-vue-devtools'
import tailwindcss from '@tailwindcss/vite'
import { VitePWA } from 'vite-plugin-pwa'
// https://vite.dev/config/
export default defineConfig({
define: {
__INTLIFY_PROD_DEVTOOLS__: false,
__VUE_I18N_FULL_INSTALL__: true,
__VUE_I18N_LEGACY_API__: false,
},
plugins: [
vue(),
vueDevTools(),
tailwindcss(),
VitePWA({
registerType: 'autoUpdate',
injectRegister: 'auto',
includeAssets: [
'favicon.ico',
'pwa-icon-source.svg',
'apple-touch-icon-180x180.png',
'pwa-64x64.png',
'pwa-192x192.png',
'pwa-512x512.png',
'maskable-icon-512x512.png',
],
manifest: {
name: 'BookOrbit',
short_name: 'BookOrbit',
description: 'Your personal book library and reading space',
theme_color: '#1e1e18',
background_color: '#fafaf8',
display: 'standalone',
start_url: '/',
scope: '/',
icons: [
{
src: 'pwa-64x64.png',
sizes: '64x64',
type: 'image/png',
},
{
src: 'pwa-192x192.png',
sizes: '192x192',
type: 'image/png',
},
{
src: 'pwa-512x512.png',
sizes: '512x512',
type: 'image/png',
},
{
src: 'maskable-icon-512x512.png',
sizes: '512x512',
type: 'image/png',
purpose: 'maskable',
},
],
shortcuts: [
{
name: 'Dashboard',
short_name: 'Dashboard',
url: '/dashboard',
icons: [{ src: 'pwa-192x192.png', sizes: '192x192' }],
},
{
name: 'Libraries',
short_name: 'Libraries',
url: '/libraries',
icons: [{ src: 'pwa-192x192.png', sizes: '192x192' }],
},
{
name: 'Settings',
short_name: 'Settings',
url: '/settings',
icons: [{ src: 'pwa-192x192.png', sizes: '192x192' }],
},
],
},
workbox: {
globPatterns: ['**/*.{js,css,html,ico,png,svg,woff,woff2}'],
globIgnores: ['**/assets/foliate/**'],
navigateFallback: 'index.html',
navigateFallbackDenylist: [/^\/api\//],
runtimeCaching: [
{
urlPattern: /^.*\/api\/v1\/books\/\d+\/cover(\?.*)?$/,
handler: 'CacheFirst',
options: {
cacheName: 'book-covers',
expiration: {
maxEntries: 200,
maxAgeSeconds: 60 * 60 * 24 * 30,
},
cacheableResponse: {
statuses: [0, 200],
},
},
},
{
urlPattern: /^.*\/api\/v1\/books\/\d+\/thumbnail(\?.*)?$/,
handler: 'CacheFirst',
options: {
cacheName: 'book-thumbnails',
expiration: {
maxEntries: 200,
maxAgeSeconds: 60 * 60 * 24 * 30,
},
cacheableResponse: {
statuses: [0, 200],
},
},
},
],
},
devOptions: {
enabled: false,
type: 'module',
},
}),
],
resolve: {
dedupe: ['vue'],
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url)),
'@bookorbit/types': fileURLToPath(new URL('../packages/types/src/index.ts', import.meta.url)),
},
},
optimizeDeps: {
include: ['@tanstack/vue-table', '@tanstack/vue-virtual'],
exclude: ['@embedpdf/core', '@embedpdf/core/vue'],
},
server: {
host: true,
allowedHosts: true,
proxy: {
'/api': {
target: 'http://localhost:3000',
configure: (proxy) => {
proxy.on('proxyReq', (proxyReq, req) => {
if (req.headers.host) proxyReq.setHeader('x-forwarded-host', req.headers.host)
const localPort = (req.socket as { localPort?: number })?.localPort
if (localPort) proxyReq.setHeader('x-forwarded-port', String(localPort))
proxyReq.setHeader('x-forwarded-proto', 'http')
})
},
},
'/socket.io': {
target: 'http://localhost:3000',
ws: true,
changeOrigin: true,
},
},
},
})