vite.config.ts 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  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[] = [
  69. react({
  70. babel: {
  71. plugins: [["babel-plugin-react-compiler", { target: "18" }]],
  72. },
  73. }),
  74. tailwindcss(),
  75. persistPortPlugin(),
  76. wasmPlugin(),
  77. sourcemapPlugin(),
  78. ]
  79. return {
  80. plugins,
  81. resolve: {
  82. alias: {
  83. "@": resolve(__dirname, "./src"),
  84. "@src": resolve(__dirname, "./src"),
  85. "@roo": resolve(__dirname, "../src/shared"),
  86. },
  87. },
  88. build: {
  89. outDir,
  90. emptyOutDir: true,
  91. reportCompressedSize: false,
  92. // Generate complete source maps with original TypeScript sources
  93. sourcemap: true,
  94. // Ensure source maps are properly included in the build
  95. minify: mode === "production" ? "esbuild" : false,
  96. // Use a single combined CSS bundle so both webviews share styles
  97. cssCodeSplit: false,
  98. rollupOptions: {
  99. // Externalize vscode module - it's imported by file-search.ts which is
  100. // dynamically imported by roo-config/index.ts, but should never be bundled
  101. // in the webview since it's not available in the browser context
  102. external: ["vscode"],
  103. input: {
  104. index: resolve(__dirname, "index.html"),
  105. "browser-panel": resolve(__dirname, "browser-panel.html"),
  106. },
  107. output: {
  108. entryFileNames: `assets/[name].js`,
  109. chunkFileNames: (chunkInfo) => {
  110. if (chunkInfo.name === "mermaid-bundle") {
  111. return `assets/mermaid-bundle.js`
  112. }
  113. // Default naming for other chunks, ensuring uniqueness from entry
  114. return `assets/chunk-[hash].js`
  115. },
  116. assetFileNames: (assetInfo) => {
  117. const name = assetInfo.name || ""
  118. // Force all CSS into a single predictable file used by both webviews
  119. if (name.endsWith(".css")) {
  120. return "assets/index.css"
  121. }
  122. if (name.endsWith(".woff2") || name.endsWith(".woff") || name.endsWith(".ttf")) {
  123. return "assets/fonts/[name][extname]"
  124. }
  125. // Ensure source maps are included in the build
  126. if (name.endsWith(".map")) {
  127. return "assets/[name]"
  128. }
  129. return "assets/[name][extname]"
  130. },
  131. manualChunks: (id, { getModuleInfo }) => {
  132. // Consolidate all mermaid code and its direct large dependencies (like dagre)
  133. // into a single chunk. The 'channel.js' error often points to dagre.
  134. if (
  135. id.includes("node_modules/mermaid") ||
  136. id.includes("node_modules/dagre") || // dagre is a common dep for graph layout
  137. id.includes("node_modules/cytoscape") // another potential graph lib
  138. // Add other known large mermaid dependencies if identified
  139. ) {
  140. return "mermaid-bundle"
  141. }
  142. // Check if the module is part of any explicitly defined mermaid-related dynamic import
  143. // This is a more advanced check if simple path matching isn't enough.
  144. const moduleInfo = getModuleInfo(id)
  145. if (moduleInfo?.importers.some((importer) => importer.includes("node_modules/mermaid"))) {
  146. return "mermaid-bundle"
  147. }
  148. if (
  149. moduleInfo?.dynamicImporters.some((importer) => importer.includes("node_modules/mermaid"))
  150. ) {
  151. return "mermaid-bundle"
  152. }
  153. },
  154. },
  155. },
  156. },
  157. server: {
  158. hmr: {
  159. host: "localhost",
  160. protocol: "ws",
  161. },
  162. cors: {
  163. origin: "*",
  164. methods: "*",
  165. allowedHeaders: "*",
  166. },
  167. },
  168. define,
  169. optimizeDeps: {
  170. include: [
  171. "mermaid",
  172. "dagre", // Explicitly include dagre for pre-bundling
  173. // Add other known large mermaid dependencies if identified
  174. ],
  175. exclude: ["@vscode/codicons", "vscode-oniguruma", "shiki"],
  176. },
  177. assetsInclude: ["**/*.wasm", "**/*.wav"],
  178. }
  179. })