vite.config.ts
1 import { defineConfig, PluginOption } from 'vite' 2 import tsconfigPaths from 'vite-tsconfig-paths' 3 import react from '@vitejs/plugin-react-swc' 4 5 6 7 8 // https://vitejs.dev/config/ 9 export default defineConfig({ 10 plugins: [react(), tsconfigPaths(), preloadAllScripts()], 11 server: { 12 port: 3000, 13 proxy: { 14 '/api': 'http://127.0.0.1:8000' 15 // '/api': 'https://demo.evidentlyai.com' 16 } 17 }, 18 build: { 19 rollupOptions: { 20 output: { 21 assetFileNames: (assetInfo) => { 22 const fileName = assetInfo.names?.[0] || 'unknown' 23 let [extType] = fileName.split('.').reverse() 24 25 if (/png|jpe?g|svg|gif|tiff|bmp|ico/i.test(extType)) { 26 // don't hash images 27 return `static/img/[name][extname]` 28 } 29 // hash everything else (like css) 30 return `static/${extType}/[name]-[hash][extname]` 31 }, 32 chunkFileNames: 'static/js/[name]-[hash].js', 33 entryFileNames: 'static/js/[name]-[hash].js' 34 } 35 } 36 } 37 }) 38 39 40 function preloadAllScripts() { 41 const [headClosedTag, tabs4, tabs2] = ['</head>', ' ', ' '] 42 43 return { 44 name: 'insert modulepreload additional js chunk link tags', 45 transformIndexHtml: (html, ctx) => { 46 if (!ctx.bundle) { 47 return 48 } 49 50 const scriptNames = Object.values(ctx.bundle) 51 .map(({ type, fileName }) => 52 type === 'asset' || html.includes(fileName) 53 ? // return `false` to skip file if 54 // file is css/img etc, or if 55 // this file already in html 56 false 57 : fileName 58 ) 59 .filter((e): e is string => typeof e === 'string') 60 61 const modulepreloadLinks = scriptNames 62 .map((scriptName) => `${tabs4}<link rel="modulepreload" crossorigin href="/${scriptName}">`) 63 .join('\n') 64 65 const additionalLinks = `\n${tabs4}${'<!-- Preload all additional js chunks -->'}\n${modulepreloadLinks}\n${tabs2}` 66 67 return html.replace(headClosedTag, `${additionalLinks}${headClosedTag}`) 68 } 69 } satisfies PluginOption 70 }