Files
project-gifuu/frontend/vite.config.ts
T
2026-05-23 17:17:56 -07:00

118 lines
4.6 KiB
TypeScript

import { defineConfig } from 'vite'
import { readFileSync } from 'fs'
import { basename } from 'path'
import { transpile } from 'typescript'
import { minify } from 'html-minifier-next'
import preact from '@preact/preset-vite'
const appConfig = JSON.parse(readFileSync('tsconfig.app.json', 'utf8'))
export default defineConfig({
build: {
assetsInlineLimit: 999_999_999,
cssMinify: 'esbuild',
minify: 'esbuild',
outDir: 'dist',
rollupOptions: {
input: {
index: 'index.html',
embed: 'embed.html',
},
output: {
hashCharacters: 'hex',
entryFileNames: 'assets/[name].[hash].js',
chunkFileNames: 'assets/[name].[hash].js',
assetFileNames: 'assets/[name].[hash][extname]',
},
},
},
server: {
strictPort: true,
port: 5173,
proxy: {
'/api': {
// cd backend && go run main.go
target: 'http://localhost:8080',
changeOrigin: true,
rewrite: (path) => path.replace('/api', ''),
},
'/cdn': {
// npx serve -C ./backend/_public
target: 'http://localhost:3000',
changeOrigin: true,
rewrite: (path) => path.replace('/cdn', ''),
},
},
},
plugins: [
preact(),
{
name: 'html-template',
transformIndexHtml(html, ctx) {
return html
.replaceAll(/{{ include-env }}/g, () => {
return `<script>
window.__ENV__ = {
CDN: "${ctx.server ? '/cdn' : 'https://cdn.gifuu.pancakz.net'}",
API: "${ctx.server ? '/api' : 'https://api.gifuu.pancakz.net'}",
WEB: "${ctx.server ? '' : 'https://gifuu.pancakz.net'}",
}
</script>`
})
.replaceAll(/{{ include-b64 '(.*?)' '(.*?)' }}/g, (_, mime: string, filepath: string) => {
const content = readFileSync(filepath, 'base64')
const inlined = `data:${mime};base64,${content}`
this.warn(`Embedding 'base64' from '${filepath}'`)
return inlined
})
.replaceAll(/{{ include-tag '(.*?)' '(.*?)' }}/g, (_, tag: string, filepath: string) => {
let content = readFileSync(filepath, 'utf8')
if (tag === 'script' && filepath.endsWith('.ts')) {
content = transpile(content, appConfig)
this.warn(`Transpiled inline script : ${basename(filepath)}`)
}
const inlined = `<${tag}>\n${content}</${tag}>`
this.warn(`Embedding '${tag}' from '${filepath}'`)
return inlined
})
.replaceAll(/{{ include-article '(.*?)' '(.*?)' }}/g, (_, id: string, filepath: string) => {
const content = readFileSync(filepath, 'utf8').replaceAll(
/<pre([^>]*)>\s*\n([\s\S]*?)<\/pre>/g,
(_, attributes, inner) => {
const lines = inner.split('\n')
const indent = lines[0].match(/^(\s*)/)?.[1].length ?? 0
const trimmed = lines
.map((l: string) => l.slice(indent))
.join('\n')
.trim()
return `<pre${attributes}>${trimmed}</pre>`
},
)
const inlined = `<template class="article" id="${id}">\n${content}</template>`
this.warn(`Embedding article '${id}' from '${filepath}'`)
return inlined
})
},
},
{
name: 'html-minify',
transformIndexHtml(html, ctx) {
if (ctx.server) return html // skip dev mode
this.warn(`Minifying Document: ${basename(ctx.filename)}`)
return minify(html, {
collapseWhitespace: true,
removeComments: true,
minifyCSS: true,
minifyJS: true,
})
},
},
],
})