import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; import { sentryVitePlugin } from '@sentry/vite-plugin'; import { wasm } from '@rollup/plugin-wasm'; import inject from '@rollup/plugin-inject'; import { viteStaticCopy } from 'vite-plugin-static-copy'; import { vanillaExtractPlugin } from '@vanilla-extract/vite-plugin'; import { VitePWA } from 'vite-plugin-pwa'; import fs from 'fs'; import path from 'path'; import buildConfig from './build.config'; const copyFiles = { targets: [ { src: 'node_modules/@element-hq/element-call-embedded/dist', dest: 'public', rename: 'element-call', }, { src: 'config.json', dest: '', }, { src: 'public/manifest.json', dest: '', rename: { stripBase: true }, }, { src: 'public/res/android', dest: 'public/', rename: { stripBase: 2 }, }, { src: 'public/locales', dest: 'public/', rename: { stripBase: 1 }, }, ], }; function copyPdfWorker() { return { name: 'copy-pdf-worker', closeBundle() { const src = path.resolve('node_modules/pdfjs-dist/build/pdf.worker.min.mjs'); const dest = path.resolve('dist/pdf.worker.min.js'); if (fs.existsSync(src)) fs.copyFileSync(src, dest); }, }; } function serverMatrixSdkCryptoWasm(wasmFilePath) { return { name: 'vite-plugin-serve-matrix-sdk-crypto-wasm', configureServer(server) { server.middlewares.use((req, res, next) => { if (req.url === wasmFilePath) { const resolvedPath = path.join( path.resolve(), '/node_modules/@matrix-org/matrix-sdk-crypto-wasm/pkg/matrix_sdk_crypto_wasm_bg.wasm', ); if (fs.existsSync(resolvedPath)) { res.setHeader('Content-Type', 'application/wasm'); res.setHeader('Cache-Control', 'no-cache'); const fileStream = fs.createReadStream(resolvedPath); fileStream.pipe(res); } else { res.writeHead(404); res.end('File not found'); } } else { next(); } }); }, }; } const vendorChunks = (id) => { if (id.includes('node_modules/matrix-js-sdk')) return 'matrix-sdk'; if (id.includes('node_modules/react-dom')) return 'react-dom'; if ( id.includes('node_modules/react-router-dom') || id.includes('node_modules/@remix-run') || id.includes('node_modules/react-router/') ) return 'router'; if (id.includes('node_modules/@tanstack')) return 'react-query'; if (id.includes('node_modules/linkify')) return 'linkify'; if (id.includes('node_modules/dompurify')) return 'dompurify'; if (id.includes('node_modules/@sentry')) return 'sentry'; if (id.includes('node_modules/i18next') || id.includes('node_modules/react-i18next')) return 'i18n'; if (id.includes('node_modules/jotai')) return 'jotai'; if (id.includes('node_modules/immer')) return 'immer'; if (id.includes('node_modules/folds')) return 'folds'; if (id.includes('node_modules/emojibase')) return 'emojibase'; }; export default defineConfig({ appType: 'spa', publicDir: false, base: buildConfig.base, server: { port: 8080, host: true, fs: { allow: ['..'], }, }, plugins: [ serverMatrixSdkCryptoWasm('/node_modules/.vite/deps/pkg/matrix_sdk_crypto_wasm_bg.wasm'), viteStaticCopy(copyFiles), vanillaExtractPlugin(), wasm(), react(), copyPdfWorker(), ...(process.env.SENTRY_AUTH_TOKEN ? [ sentryVitePlugin({ org: 'lotus-guild', project: 'javascript-react', authToken: process.env.SENTRY_AUTH_TOKEN, sourcemaps: { filesToDeleteAfterUpload: ['./dist/**/*.map'], }, release: { name: process.env.VITE_APP_VERSION ?? 'lotus' }, telemetry: false, }), ] : []), VitePWA({ srcDir: 'src', filename: 'sw.ts', strategies: 'injectManifest', injectRegister: false, manifest: false, injectManifest: { injectionPoint: undefined, // codeSplitting: false is not yet supported by vite-plugin-pwa 1.3.0; // the inlineDynamicImports deprecation warning from Vite is from pwa internal build }, devOptions: { enabled: true, type: 'module', }, }), ], optimizeDeps: { rolldownOptions: { define: { global: 'globalThis', }, }, }, build: { target: 'esnext', outDir: 'dist', sourcemap: process.env.SENTRY_AUTH_TOKEN ? 'hidden' : false, copyPublicDir: false, // manualChunks must be in rolldownOptions (not rollupOptions) for Vite 8 / Rolldown rolldownOptions: { checks: { preferBuiltinFeature: false }, output: { manualChunks: vendorChunks, }, }, rollupOptions: { plugins: [inject({ Buffer: ['buffer', 'Buffer'] })], }, }, });