import { resolve } from 'path'; import react from '@vitejs/plugin-react'; import { visualizer } from 'rollup-plugin-visualizer'; import { defineConfig } from 'vite'; import dts from 'vite-plugin-dts'; import { libInjectCss } from 'vite-plugin-lib-inject-css'; import { version, name } from './package.json'; export function generateScopedName(className: string, filePath: string): string { const normalized = filePath.replace(/\\/g, '/'); const scope = normalized.match(/\/(?:components|baseComp)\/([^/]+)\//)?.[1] ?? 'shared'; return `uikit-${scope}-${className}`; } // https://vite.dev/config/ export default defineConfig(({ mode }) => { const isDevelopment = mode === 'development'; return { define: { __CHAT_UIKIT_VERSION__: JSON.stringify(version), __CHAT_UIKIT_NAME__: JSON.stringify(name), }, resolve: { alias: { '@': resolve(__dirname, 'src'), }, }, build: { lib: { entry: resolve(__dirname, 'src/index.ts'), formats: ['es'], }, rollupOptions: { external: (id) => { if (id === 'react' || id === 'react/jsx-runtime' || id.startsWith('react-dom')) { return true; } if (id === 'tuikit-atomicx-react' || id.startsWith('tuikit-atomicx-react/')) { return true; } const externalPeers = [ '@tencentcloud/lite-chat', '@tencentcloud/tui-core-lite', '@tencentcloud/universal-api', '@tencentcloud/chat-uikit-engine-lite', '@tencentcloud/call-uikit-react', '@tencentcloud/uikit-base-component-react', '@base-ui/react', 'zustand', 'i18next', 'marked', ]; return externalPeers.some(peer => id === peer || id.startsWith(`${peer}/`)); }, input: getComponentEntries(), output: { format: 'es', compact: !isDevelopment, hoistTransitiveImports: false, entryFileNames: '[name].js', chunkFileNames: '_internal/[name]-[hash:8].js', assetFileNames: 'styles/[name]-[hash:8][extname]', manualChunks: { 'classnames': ['classnames'], 'react-vendors': ['react-transition-group'], 'es-toolkit': ['es-toolkit/function', 'es-toolkit/compat/throttle'], 'date-fns': ['date-fns'], 'tiptap': [ '@tiptap/react', '@tiptap/starter-kit', '@tiptap/extension-mention', '@tiptap/extension-placeholder', '@tiptap/extension-image', '@tiptap/suggestion', '@tiptap/pm/state', '@tiptap/pm/model', 'tippy.js', ], }, }, treeshake: true, }, minify: isDevelopment ? false : 'esbuild', sourcemap: isDevelopment, }, plugins: [ react(), libInjectCss(), dts({ tsconfigPath: './tsconfig.app.json', include: [ 'src/index.ts', 'src/components/*/index.ts', 'src/components/*/*.tsx', ], exclude: ['**/*.stories.tsx', '**/*.stories.jsx'], outDir: 'dist', entryRoot: 'src', }), enableBuildStats(!isDevelopment), ], css: { modules: { generateScopedName, }, postcss: { plugins: [], }, preprocessorOptions: { scss: { api: 'modern-compiler', additionalData: ` @use "@tencentcloud/uikit-base-component-react/dist/styles/theme/util" as *; `, }, }, }, }; }); function getComponentEntries(): Record { const components = [ 'Chat', 'ChatHeader', 'ChatHeaderH5', 'ChatSetting', 'ChatSettingH5', 'ContactList', 'ContactListH5', 'ConversationList', 'ConversationListH5', 'MessageInput', 'MessageInputH5', 'MessageList', 'MessageListH5', 'ProfileEditButton', 'Search', 'SearchNewH5', ]; const entries: Record = { index: resolve(__dirname, 'src/index.ts'), }; for (const comp of components) { entries[`components/${comp}/index`] = resolve(__dirname, `src/components/${comp}/index.ts`); } return entries; } function enableBuildStats(enable: boolean = false) { return enable && visualizer({ filename: './.stats/stats.html', template: 'flamegraph', open: true, }); }