vite.config.ts 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. import path, { resolve } from "path"
  2. import fs from "fs"
  3. import { execSync } from "child_process"
  4. import { defineConfig, type PluginOption, type Plugin } from "vite"
  5. import react from "@vitejs/plugin-react"
  6. import tailwindcss from "@tailwindcss/vite"
  7. import { sourcemapPlugin } from "./src/vite-plugins/sourcemapPlugin"
  8. function getGitSha() {
  9. let gitSha: string | undefined = undefined
  10. try {
  11. gitSha = execSync("git rev-parse HEAD").toString().trim()
  12. } catch (_error) {
  13. // Do nothing.
  14. }
  15. return gitSha
  16. }
  17. const wasmPlugin = (): Plugin => ({
  18. name: "wasm",
  19. async load(id) {
  20. if (id.endsWith(".wasm")) {
  21. const wasmBinary = await import(id)
  22. return `
  23. const wasmModule = new WebAssembly.Module(${wasmBinary.default});
  24. export default wasmModule;
  25. `
  26. }
  27. },
  28. })
  29. const persistPortPlugin = (): Plugin => ({
  30. name: "write-port-to-file",
  31. configureServer(viteDevServer) {
  32. viteDevServer?.httpServer?.once("listening", () => {
  33. const address = viteDevServer?.httpServer?.address()
  34. const port = address && typeof address === "object" ? address.port : null
  35. if (port) {
  36. fs.writeFileSync(resolve(__dirname, "..", ".vite-port"), port.toString())
  37. console.log(`[Vite Plugin] Server started on port ${port}`)
  38. } else {
  39. console.warn("[Vite Plugin] Could not determine server port")
  40. }
  41. })
  42. },
  43. })
  44. // https://vitejs.dev/config/
  45. export default defineConfig(({ mode }) => {
  46. let outDir = "../src/webview-ui/build"
  47. const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, "..", "src", "package.json"), "utf8"))
  48. const gitSha = getGitSha()
  49. const define: Record<string, any> = {
  50. "process.platform": JSON.stringify(process.platform),
  51. "process.env.VSCODE_TEXTMATE_DEBUG": JSON.stringify(process.env.VSCODE_TEXTMATE_DEBUG),
  52. "process.env.PKG_NAME": JSON.stringify(pkg.name),
  53. "process.env.PKG_VERSION": JSON.stringify(pkg.version),
  54. "process.env.PKG_OUTPUT_CHANNEL": JSON.stringify("Roo-Code"),
  55. ...(gitSha ? { "process.env.PKG_SHA": JSON.stringify(gitSha) } : {}),
  56. }
  57. // TODO: We can use `@roo-code/build` to generate `define` once the
  58. // monorepo is deployed.
  59. if (mode === "nightly") {
  60. outDir = "../apps/vscode-nightly/build/webview-ui/build"
  61. const nightlyPkg = JSON.parse(
  62. fs.readFileSync(path.join(__dirname, "..", "apps", "vscode-nightly", "package.nightly.json"), "utf8"),
  63. )
  64. define["process.env.PKG_NAME"] = JSON.stringify(nightlyPkg.name)
  65. define["process.env.PKG_VERSION"] = JSON.stringify(nightlyPkg.version)
  66. define["process.env.PKG_OUTPUT_CHANNEL"] = JSON.stringify("Roo-Code-Nightly")
  67. }
  68. const plugins: PluginOption[] = [react(), tailwindcss(), persistPortPlugin(), wasmPlugin(), sourcemapPlugin()]
  69. return {
  70. plugins,
  71. resolve: {
  72. alias: {
  73. "@": resolve(__dirname, "./src"),
  74. "@src": resolve(__dirname, "./src"),
  75. "@roo": resolve(__dirname, "../src/shared"),
  76. },
  77. },
  78. build: {
  79. outDir,
  80. emptyOutDir: true,
  81. reportCompressedSize: false,
  82. // Generate complete source maps with original TypeScript sources
  83. sourcemap: true,
  84. // Ensure source maps are properly included in the build
  85. minify: mode === "production" ? "esbuild" : false,
  86. // Use a single combined CSS bundle so both webviews share styles
  87. cssCodeSplit: false,
  88. rollupOptions: {
  89. input: {
  90. index: resolve(__dirname, "index.html"),
  91. "browser-panel": resolve(__dirname, "browser-panel.html"),
  92. },
  93. output: {
  94. entryFileNames: `assets/[name].js`,
  95. chunkFileNames: (chunkInfo) => {
  96. if (chunkInfo.name === "mermaid-bundle") {
  97. return `assets/mermaid-bundle.js`
  98. }
  99. // Default naming for other chunks, ensuring uniqueness from entry
  100. return `assets/chunk-[hash].js`
  101. },
  102. assetFileNames: (assetInfo) => {
  103. const name = assetInfo.name || ""
  104. // Force all CSS into a single predictable file used by both webviews
  105. if (name.endsWith(".css")) {
  106. return "assets/index.css"
  107. }
  108. if (name.endsWith(".woff2") || name.endsWith(".woff") || name.endsWith(".ttf")) {
  109. return "assets/fonts/[name][extname]"
  110. }
  111. // Ensure source maps are included in the build
  112. if (name.endsWith(".map")) {
  113. return "assets/[name]"
  114. }
  115. return "assets/[name][extname]"
  116. },
  117. manualChunks: (id, { getModuleInfo }) => {
  118. // Consolidate all mermaid code and its direct large dependencies (like dagre)
  119. // into a single chunk. The 'channel.js' error often points to dagre.
  120. if (
  121. id.includes("node_modules/mermaid") ||
  122. id.includes("node_modules/dagre") || // dagre is a common dep for graph layout
  123. id.includes("node_modules/cytoscape") // another potential graph lib
  124. // Add other known large mermaid dependencies if identified
  125. ) {
  126. return "mermaid-bundle"
  127. }
  128. // Check if the module is part of any explicitly defined mermaid-related dynamic import
  129. // This is a more advanced check if simple path matching isn't enough.
  130. const moduleInfo = getModuleInfo(id)
  131. if (moduleInfo?.importers.some((importer) => importer.includes("node_modules/mermaid"))) {
  132. return "mermaid-bundle"
  133. }
  134. if (
  135. moduleInfo?.dynamicImporters.some((importer) => importer.includes("node_modules/mermaid"))
  136. ) {
  137. return "mermaid-bundle"
  138. }
  139. },
  140. },
  141. },
  142. },
  143. server: {
  144. hmr: {
  145. host: "localhost",
  146. protocol: "ws",
  147. },
  148. cors: {
  149. origin: "*",
  150. methods: "*",
  151. allowedHeaders: "*",
  152. },
  153. },
  154. define,
  155. optimizeDeps: {
  156. include: [
  157. "mermaid",
  158. "dagre", // Explicitly include dagre for pre-bundling
  159. // Add other known large mermaid dependencies if identified
  160. ],
  161. exclude: ["@vscode/codicons", "vscode-oniguruma", "shiki"],
  162. },
  163. assetsInclude: ["**/*.wasm", "**/*.wav"],
  164. }
  165. })