Files
gochat/frontend/vite.config.ts
T

172 lines
5.3 KiB
TypeScript

/// <reference types="vitest" />
/**
* GoChat frontend Vite config — decoupled from Rails.
*
* Originally Chatwoot used vite-plugin-ruby which auto-discovers entrypoints
* from app/javascript/entrypoints/ via config/vite.json. We replaced it with
* explicit rollupOptions.input so the frontend builds as a standalone Vite app
* that talks to the GoChat Go backend (no Ruby/Rails required).
*
* Entry points (mirrors app/javascript/entrypoints/):
* dashboard — agent dashboard SPA (mounted at #app via /app/*)
* widget — customer-facing web widget
* portal — help-center portal
* sdk — standalone SDK (library mode, built separately)
* superadmin — super admin panel
* survey — CSAT survey form
* v3app — v3 login/signup flow
*/
import { defineConfig } from 'vite';
import path from 'path';
import vue from '@vitejs/plugin-vue';
import yaml from '@rollup/plugin-yaml';
const isLibraryMode = process.env.BUILD_MODE === 'library';
const isTestMode = process.env.TEST === 'true';
const vueOptions = {
template: {
compilerOptions: {
isCustomElement: (tag: string) => ['ninja-keys'].includes(tag),
},
},
};
const resolveAliases = {
vue: 'vue/dist/vue.esm-bundler.js',
components: path.resolve(__dirname, './app/javascript/dashboard/components'),
next: path.resolve(__dirname, './app/javascript/dashboard/components-next'),
v3: path.resolve(__dirname, './app/javascript/v3'),
dashboard: path.resolve(__dirname, './app/javascript/dashboard'),
helpers: path.resolve(__dirname, './app/javascript/shared/helpers'),
shared: path.resolve(__dirname, './app/javascript/shared'),
survey: path.resolve(__dirname, './app/javascript/survey'),
widget: path.resolve(__dirname, './app/javascript/widget'),
assets: path.resolve(__dirname, './app/javascript/dashboard/assets'),
};
// Entrypoints that vite-plugin-ruby used to auto-discover
const entrypoints = {
dashboard: path.resolve(__dirname, './app/javascript/entrypoints/dashboard.js'),
widget: path.resolve(__dirname, './app/javascript/entrypoints/widget.js'),
portal: path.resolve(__dirname, './app/javascript/entrypoints/portal.js'),
superadmin: path.resolve(__dirname, './app/javascript/entrypoints/superadmin.js'),
superadmin_pages: path.resolve(__dirname, './app/javascript/entrypoints/superadmin_pages.js'),
survey: path.resolve(__dirname, './app/javascript/entrypoints/survey.js'),
v3app: path.resolve(__dirname, './app/javascript/entrypoints/v3app.js'),
};
let plugins = [vue(vueOptions), yaml()];
if (isLibraryMode) {
plugins = [];
} else if (isTestMode) {
plugins = [vue(vueOptions), yaml()];
}
export default defineConfig({
plugins,
css: {
preprocessorOptions: {
scss: {
api: 'modern-compiler',
quietDeps: true,
silenceDeprecations: ['import', 'global-builtin'],
},
},
},
// Dev server proxies API + WebSocket to the GoChat Go backend
server: {
host: '0.0.0.0',
port: 3036,
proxy: {
'/api': {
target: process.env.VITE_API_HOST || 'http://127.0.0.1:3000',
changeOrigin: true,
},
'/auth': {
target: process.env.VITE_API_HOST || 'http://127.0.0.1:3000',
changeOrigin: true,
},
'/platform': {
target: process.env.VITE_API_HOST || 'http://127.0.0.1:3000',
changeOrigin: true,
},
'/profile': {
target: process.env.VITE_API_HOST || 'http://127.0.0.1:3000',
changeOrigin: true,
},
'/cable': {
target: process.env.VITE_API_HOST || 'http://127.0.0.1:3000',
ws: true,
changeOrigin: true,
},
'/health': {
target: process.env.VITE_API_HOST || 'http://127.0.0.1:3000',
changeOrigin: true,
},
},
},
build: {
outDir: 'dist',
rollupOptions: {
input: isLibraryMode ? undefined : entrypoints,
output: {
// [NOTE] when not in library mode, no new keys will be added or overwritten
...(isLibraryMode
? {
dir: 'dist/sdk',
entryFileNames: (chunkInfo: { name: string }) => {
if (chunkInfo.name === 'sdk') {
return 'js/sdk.js';
}
return '[name].js';
},
}
: {}),
inlineDynamicImports: isLibraryMode, // Disable code-splitting for SDK
},
},
lib: isLibraryMode
? {
entry: path.resolve(__dirname, './app/javascript/entrypoints/sdk.js'),
formats: ['iife'] as const, // IIFE format for single file
name: 'sdk',
}
: undefined,
},
resolve: {
alias: resolveAliases,
},
test: {
environment: 'jsdom',
include: ['app/**/*.{test,spec}.?(c|m)[jt]s?(x)'],
coverage: {
reporter: ['lcov', 'text'],
include: ['app/**/*.js', 'app/**/*.vue'],
exclude: [
'app/**/*.@(spec|stories|routes).js',
'**/specs/**/*',
'**/i18n/**/*',
],
},
globals: true,
outputFile: 'coverage/sonar-report.xml',
pool: 'threads',
poolOptions: {
threads: {
singleThread: false,
},
},
server: {
deps: {
inline: ['tinykeys', '@material/mwc-icon'],
},
},
setupFiles: ['fake-indexeddb/auto', 'vitest.setup.js'],
mockReset: true,
clearMocks: true,
},
});