docs/vite.config.ts
import fs from 'fs'
import type { Plugin } from 'vite'
import { defineConfig } from 'vite'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import Unocss from 'unocss/vite'
import transformerDirective from '@unocss/transformer-directives'
import { presetAttributify, presetIcons, presetUno, presetTypography } from 'unocss'
import { resolve } from 'pathe'
import type { VitePluginPWAAPI } from 'vite-plugin-pwa'
import { VitePWA } from 'vite-plugin-pwa'
import fg from 'fast-glob'
import {
pwaFontStylesRegex,
pwaFontsRegex,
feathersDescription,
feathersName,
feathersShortName
} from './.vitepress/meta'
import { optimizePages } from './.vitepress/scripts/assets'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import { SearchPlugin } from 'vitepress-plugin-search'
const PWA = VitePWA({
outDir: '.vitepress/dist',
registerType: 'autoUpdate',
// include all static assets under public/
includeAssets: fg.sync('**/*.{png,svg,ico,txt}', { cwd: resolve(__dirname, 'public') }),
manifest: {
id: '/',
name: feathersName,
short_name: feathersShortName,
description: feathersDescription,
theme_color: '#ffffff',
icons: [
{
src: 'pwa-192x192.png',
sizes: '192x192',
type: 'image/png'
},
{
src: 'pwa-512x512.png',
sizes: '512x512',
type: 'image/png'
},
{
src: 'logo.svg',
sizes: '165x165',
type: 'image/svg',
purpose: 'any maskable'
}
]
},
workbox: {
navigateFallbackDenylist: [/^\/new$/],
runtimeCaching: [
{
urlPattern: pwaFontsRegex,
handler: 'CacheFirst',
options: {
cacheName: 'google-fonts-cache',
expiration: {
maxEntries: 10,
maxAgeSeconds: 60 * 60 * 24 * 365 // <== 365 days
},
cacheableResponse: {
statuses: [0, 200]
}
}
},
{
urlPattern: pwaFontStylesRegex,
handler: 'CacheFirst',
options: {
cacheName: 'gstatic-fonts-cache',
expiration: {
maxEntries: 10,
maxAgeSeconds: 60 * 60 * 24 * 365 // <== 365 days
},
cacheableResponse: {
statuses: [0, 200]
}
}
}
]
}
})
export default defineConfig({
plugins: [
SearchPlugin(),
AutoImport({
resolvers: [ElementPlusResolver()]
}),
Components({
include: [/\.vue/, /\.md/],
dirs: '.vitepress/components',
dts: '.vitepress/components.d.ts',
resolvers: [ElementPlusResolver({ ssr: false })]
}),
Unocss({
shortcuts: [
[
'btn',
'px-4 py-1 rounded inline-flex justify-center gap-2 text-white leading-30px children:mya !no-underline cursor-pointer disabled:cursor-default disabled:bg-gray-600 disabled:opacity-50'
]
],
presets: [
presetUno({
dark: 'media'
}),
presetAttributify(),
presetIcons({
scale: 1.2
}),
presetTypography()
],
transformers: [transformerDirective()]
}),
IncludesPlugin(),
PWA,
{
name: 'pwa:post',
enforce: 'post',
async buildEnd() {
const pwaPlugin: VitePluginPWAAPI = PWA.find((i) => i.name === 'vite-plugin-pwa')?.api
const pwa = pwaPlugin && !pwaPlugin.disabled
await optimizePages(pwa)
if (pwa) await pwaPlugin.generateSW()
}
}
],
ssr: { noExternal: ['element-plus'] }
})
function IncludesPlugin(): Plugin {
return {
name: 'include-plugin',
enforce: 'pre',
transform(code, id) {
let changed = false
code = code.replace(/\[@@include\]\((.*?)\)/, (_, url) => {
changed = true
const full = resolve(id, url)
return fs.readFileSync(full, 'utf-8')
})
if (changed) return code
}
}
}