mirror of
https://github.com/Afilmory/afilmory
synced 2026-05-01 10:16:40 +00:00
When index.html was included in the precache manifest, the NavigationRoute served a cached (stale) version for all navigation requests. This caused newly added photos to be invisible until the new service worker activated, because the old index.html contained an outdated photo manifest. By removing html from globPatterns, navigation requests fall through to the network, ensuring users always get the latest index.html. Fixes #90
241 lines
6.7 KiB
TypeScript
241 lines
6.7 KiB
TypeScript
import { execSync } from 'node:child_process'
|
|
import { rmSync } from 'node:fs'
|
|
import path, { resolve } from 'node:path'
|
|
import { fileURLToPath } from 'node:url'
|
|
|
|
import tailwindcss from '@tailwindcss/vite'
|
|
import react from '@vitejs/plugin-react'
|
|
import { codeInspectorPlugin } from 'code-inspector-plugin'
|
|
import { cyan, dim, green } from 'kolorist'
|
|
import type { PluginOption, ViteDevServer } from 'vite'
|
|
import { defineConfig } from 'vite'
|
|
import { analyzer } from 'vite-bundle-analyzer'
|
|
import { checker } from 'vite-plugin-checker'
|
|
import { createHtmlPlugin } from 'vite-plugin-html'
|
|
import { VitePWA } from 'vite-plugin-pwa'
|
|
import { routeBuilderPlugin } from 'vite-plugin-route-builder'
|
|
import tsconfigPaths from 'vite-tsconfig-paths'
|
|
|
|
import PKG from '../../package.json'
|
|
import { siteConfig } from '../../site.config'
|
|
import { astPlugin } from './plugins/vite/ast'
|
|
import { createDependencyChunksPlugin } from './plugins/vite/deps'
|
|
import { createFeedSitemapPlugin } from './plugins/vite/feed-sitemap'
|
|
import { localesJsonPlugin } from './plugins/vite/locales-json'
|
|
import { manifestInjectPlugin } from './plugins/vite/manifest-inject'
|
|
import { ogImagePlugin } from './plugins/vite/og-image-plugin'
|
|
import { photosStaticPlugin } from './plugins/vite/photos-static'
|
|
import { siteConfigInjectPlugin } from './plugins/vite/site-config-inject'
|
|
|
|
const devPrint = (): PluginOption => ({
|
|
name: 'dev-print',
|
|
configureServer(server: ViteDevServer) {
|
|
server.printUrls = () => {
|
|
console.info(` ${green('➜')} ${dim('Next.js SSR')}: ${cyan('http://localhost:1924')}`)
|
|
}
|
|
},
|
|
})
|
|
|
|
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
|
|
if (process.env.CI) {
|
|
rmSync(path.join(process.cwd(), 'src/pages/(debug)'), {
|
|
recursive: true,
|
|
force: true,
|
|
})
|
|
}
|
|
const DEV_NEXT_JS = process.env.DEV_NEXT_JS === 'true'
|
|
|
|
const ReactCompilerConfig = {
|
|
/* ... */
|
|
}
|
|
|
|
const ROOT = fileURLToPath(new URL('./', import.meta.url))
|
|
const routeGenPlugins: PluginOption[] = [
|
|
routeBuilderPlugin({
|
|
pagePattern: `${resolve(ROOT, './src/pages')}/**/*.tsx`,
|
|
outputPath: `${resolve(ROOT, './src/generated-routes.ts')}`,
|
|
enableInDev: true,
|
|
|
|
segmentGroupOrder: ['main'],
|
|
}),
|
|
]
|
|
const staticWebBuildPlugins: PluginOption[] = [
|
|
manifestInjectPlugin(),
|
|
siteConfigInjectPlugin(),
|
|
photosStaticPlugin(),
|
|
VitePWA({
|
|
base: '/',
|
|
scope: '/',
|
|
registerType: 'autoUpdate',
|
|
includeAssets: ['favicon.ico', 'apple-touch-icon.png', 'masked-icon.svg'],
|
|
manifest: {
|
|
name: siteConfig.title,
|
|
short_name: siteConfig.name,
|
|
description: siteConfig.description,
|
|
theme_color: '#1c1c1e',
|
|
background_color: '#1c1c1e',
|
|
display: 'standalone',
|
|
scope: '/',
|
|
start_url: '/',
|
|
icons: [
|
|
{
|
|
src: 'android-chrome-192x192.png',
|
|
sizes: '192x192',
|
|
type: 'image/png',
|
|
},
|
|
{
|
|
src: 'android-chrome-512x512.png',
|
|
sizes: '512x512',
|
|
type: 'image/png',
|
|
},
|
|
{
|
|
src: 'apple-touch-icon.png',
|
|
sizes: '180x180',
|
|
type: 'image/png',
|
|
},
|
|
],
|
|
},
|
|
workbox: {
|
|
maximumFileSizeToCacheInBytes: 10 * 1024 * 1024, // 10MB
|
|
navigateFallback: '',
|
|
globPatterns: ['**/*.{js,css,ico,png,svg,webp}'],
|
|
globIgnores: ['**/*.{jpg,jpeg}'], // 忽略大图片文件
|
|
runtimeCaching: [
|
|
{
|
|
urlPattern: /^https:\/\/fonts\.googleapis\.com\/.*/i,
|
|
handler: 'CacheFirst',
|
|
options: {
|
|
cacheName: 'google-fonts-cache',
|
|
expiration: {
|
|
maxEntries: 10,
|
|
maxAgeSeconds: 60 * 60 * 24 * 365, // <== 365 days
|
|
},
|
|
},
|
|
},
|
|
{
|
|
urlPattern: /^https:\/\/fonts\.gstatic\.com\/.*/i,
|
|
handler: 'CacheFirst',
|
|
options: {
|
|
cacheName: 'gstatic-fonts-cache',
|
|
expiration: {
|
|
maxEntries: 10,
|
|
maxAgeSeconds: 60 * 60 * 24 * 365, // <== 365 days
|
|
},
|
|
},
|
|
},
|
|
{
|
|
urlPattern: /\.(?:png|jpg|jpeg|svg|webp)$/,
|
|
handler: 'CacheFirst',
|
|
options: {
|
|
cacheName: 'images-cache',
|
|
expiration: {
|
|
maxEntries: 100,
|
|
maxAgeSeconds: 60 * 60 * 24 * 30, // <== 30 days
|
|
},
|
|
},
|
|
},
|
|
],
|
|
},
|
|
devOptions: {
|
|
enabled: false, // 开发环境不启用 PWA
|
|
},
|
|
}),
|
|
|
|
ogImagePlugin({
|
|
title: siteConfig.title,
|
|
description: siteConfig.description,
|
|
siteName: siteConfig.name,
|
|
siteUrl: siteConfig.url,
|
|
}),
|
|
createFeedSitemapPlugin(siteConfig),
|
|
createHtmlPlugin({
|
|
minify: {
|
|
collapseWhitespace: true,
|
|
keepClosingSlash: true,
|
|
removeComments: true,
|
|
removeRedundantAttributes: true,
|
|
removeScriptTypeAttributes: true,
|
|
removeStyleLinkTypeAttributes: true,
|
|
useShortDoctype: true,
|
|
minifyCSS: true,
|
|
minifyJS: true,
|
|
},
|
|
inject: {
|
|
data: {
|
|
title: siteConfig.title,
|
|
description: siteConfig.description,
|
|
},
|
|
},
|
|
}),
|
|
]
|
|
|
|
const BUILD_FOR_SERVER_SERVE = process.env.BUILD_FOR_SERVER_SERVE === '1'
|
|
// https://vitejs.dev/config/
|
|
export default defineConfig(() => {
|
|
return {
|
|
base: BUILD_FOR_SERVER_SERVE ? '/static/web/' : '/',
|
|
// Vite MPA configuration
|
|
build: {
|
|
rollupOptions: BUILD_FOR_SERVER_SERVE
|
|
? {
|
|
input: {
|
|
main: path.resolve(__dirname, 'index.html'),
|
|
share: path.resolve(__dirname, 'share.html'),
|
|
},
|
|
}
|
|
: undefined,
|
|
},
|
|
plugins: [
|
|
codeInspectorPlugin({
|
|
bundler: 'vite',
|
|
hotKeys: ['altKey'],
|
|
}),
|
|
react({
|
|
babel: {
|
|
plugins: [['babel-plugin-react-compiler', ReactCompilerConfig]],
|
|
},
|
|
}),
|
|
|
|
astPlugin,
|
|
tsconfigPaths(),
|
|
checker({
|
|
typescript: true,
|
|
enableBuild: true,
|
|
root: __dirname,
|
|
}),
|
|
|
|
...routeGenPlugins,
|
|
createDependencyChunksPlugin([
|
|
['heic-to'],
|
|
['react', 'react-dom'],
|
|
['i18next', 'i18next-browser-languagedetector', 'react-i18next'],
|
|
]),
|
|
localesJsonPlugin(),
|
|
tailwindcss(),
|
|
...(BUILD_FOR_SERVER_SERVE ? [] : staticWebBuildPlugins),
|
|
process.env.analyzer && analyzer(),
|
|
|
|
devPrint(),
|
|
],
|
|
server: {
|
|
port: !DEV_NEXT_JS ? 1924 : 13333, // 1924 年首款 35mm 相机问世
|
|
},
|
|
define: {
|
|
APP_DEV_CWD: JSON.stringify(process.cwd()),
|
|
APP_NAME: JSON.stringify(PKG.name),
|
|
BUILT_DATE: JSON.stringify(new Date().toLocaleDateString()),
|
|
GIT_COMMIT_HASH: JSON.stringify(getGitHash()),
|
|
},
|
|
}
|
|
})
|
|
|
|
function getGitHash() {
|
|
try {
|
|
return execSync('git rev-parse HEAD').toString().trim()
|
|
} catch (e) {
|
|
console.error('Failed to get git hash', e)
|
|
return ''
|
|
}
|
|
}
|