Skip to content

chore(app): fix initial app load using code splitting and lazy load - #8626

Open
sachin-thakur-bruno wants to merge 6 commits into
usebruno:mainfrom
sachin-thakur-bruno:chore/app-load
Open

sachin-thakur-bruno wants to merge 6 commits into
usebruno:mainfrom
sachin-thakur-bruno:chore/app-load

Conversation

@sachin-thakur-bruno

@sachin-thakur-bruno sachin-thakur-bruno commented Jul 15, 2026 •

Copy link
Copy Markdown
Collaborator

Description

Before After
image image
-------- ---------
image image

1. Re-enable code splitting

Removed the global dynamicImportMode: "eager" and added output.assetPrefix: './' so that split chunks load correctly under Electron's file:// protocol. dynamicImportMode: "eager" is now scoped only to react-player, which uses internal dynamic imports that fail in Electron without it.

2. Move CodeMirror setup out of the main bundle

All CodeMirror modes, addons, themes, and GraphQL plugins were sitting at the top level of Bruno/index.js, forcing the entire CodeMirror setup to load before first paint. Extracted to src/utils/codemirror/setup.js and imported only from CodeEditor/index.js, so CodeMirror loads when an editor first mounts — not at startup.

3. Lazy-load heavy panels

RequestTabPanel, ApiSpecPanel, ManageWorkspace, and AiChatSidebar are not visible on first paint. They are now loaded asynchronously with React.lazy() so their code is excluded from the initial bundle.

4. Lazy-load sidebar modals

Modal components in CollectionsSection, Collection, and CollectionItem (import collection, create collection, rename, clone, delete, run, generate code, etc.) are now lazy-loaded. They only mount when the user triggers them.

5. Lazy-load NewRequest in RequestTabs

RequestTabs statically imported NewRequest, which pulled SingleLineEditor → CodeMirror core and autocomplete.js → @usebruno/common → @faker-js/faker into the main bundle. NewRequest is now lazy-loaded since it only renders when the user clicks the new request button.

6. Move prettier out of the main bundle

formatResponse and related formatting utilities (which import prettier/standalone and prettier/parser-babel) were extracted from utils/common/index.js into a separate utils/common/format-response.js module. Since all callers live inside the lazy RequestTabPanel chunk, prettier now only loads when a request tab is open.

7. Remove unused CSS from startup

Moved CodeMirror, GraphiQL, and GraphQL docs stylesheets out of Main.js and Bruno/index.js. These now load with the async chunks that actually need them. Also removed unused Inter font weights (100, 200, 300, 800, 900) — only 400–700 are used in the app.

8. Lazy-load PDF viewer

pdfjs-dist (~582 KiB) was imported at the top level of QueryResultPreview. Extracted into a new PdfPreview.js component that is lazy-loaded only when a PDF response is received.

Contribution Checklist:

  • I've used AI significantly to create this pull request
  • The pull request only addresses one issue or adds one feature.
  • The pull request does not introduce any breaking changes
  • I have added screenshots or gifs to help explain the change if applicable.
  • I have read the contribution guidelines.
  • Create an issue and link to the pull request.

Note: Keeping the PR small and focused helps make it easier to review and merge. If you have multiple changes you want to make, please consider submitting them as separate pull requests.

Publishing to New Package Managers

Please see here for more information.

Summary by CodeRabbit

  • New Features

    • Added scrollable, multi-page PDF response previews.
    • Improved Swagger UI styling and documentation rendering.
    • Expanded editor initialization to support richer syntax highlighting, linting, autocomplete, and editor helpers.
  • Performance

    • Improved app startup and navigation by deferring heavier panels and dialogs via on-demand loading.
    • Optimized response formatting for large payloads to keep the UI responsive.
  • Bug Fixes

    • Improved desktop (file://) loading reliability for dynamically loaded chunks.

@sachin-thakur-bruno sachin-thakur-bruno changed the title chore(app-first-load)/fix app load using code splitting and lazy load chore(app): fix initial app load using code splitting and lazy load Jul 15, 2026
@coderabbitai

coderabbitai Bot commented Jul 15, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 0a12e486-7a58-4776-a1cf-fb30880b7682

📥 Commits

Reviewing files that changed from the base of the PR and between 35b82a8 and d85499b.

📒 Files selected for processing (2)
  • packages/bruno-app/src/components/RequestTabPanel/index.js
  • packages/bruno-app/src/pages/Bruno/index.js
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/bruno-app/src/pages/Bruno/index.js
  • packages/bruno-app/src/components/RequestTabPanel/index.js

Walkthrough

The PR extracts response formatting, code-splits heavy application components and previews, scopes editor and resource initialization, adds Electron bundle settings, and removes the terminal session ID helper.

Changes

Application loading and rendering

Layer / File(s) Summary
Response formatting extraction
packages/bruno-app/src/utils/common/format-response.js, packages/bruno-app/src/utils/common/index.js, packages/bruno-app/src/components/ResponsePane/...
Response formatting and prettification move to a dedicated module, with response consumers updated to import it from the new path.
Response preview loading
packages/bruno-app/src/components/ResponsePane/QueryResult/QueryResultPreview/*
PDF rendering moves into a lazy-loaded PdfPreview, while PDF and JSON previews render through Suspense.
Application UI lazy loading
packages/bruno-app/src/pages/Bruno/index.js, packages/bruno-app/src/components/RequestTabs/*, packages/bruno-app/src/components/Sidebar/..., packages/bruno-app/src/components/StatusBar/*, packages/bruno-app/src/components/Notifications/...
Major panels, tabs, modals, cookies, and Markdown rendering use dynamic imports with Suspense fallbacks.
Runtime resource configuration
packages/bruno-app/rsbuild.config.mjs, packages/bruno-app/src/utils/codemirror/setup.js, packages/bruno-app/src/components/CodeEditor/index.js, packages/bruno-app/src/components/ApiSpecPanel/..., packages/bruno-app/src/components/RequestTabPanel/index.js, packages/bruno-app/src/pages/Main.js
Bundle analysis is opt-in, Electron assets use relative paths, react-player retains eager imports selectively, and editor and renderer styles load from relevant modules.
Terminal loading boundary
packages/bruno-app/src/utils/terminal.js
The unused terminal session ID import and exported helper are removed.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

Suggested reviewers: bijin-bruno, helloanoop, lohit-bruno, naman-bruno, sanish-bruno

Poem

Heavy chunks drift out of sight,
Suspense holds the loading light.
PDFs unfold page by page,
Formats move to a cleaner stage.
Electron finds its path just right.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly reflects the PR’s main change: improving initial app load via code splitting and lazy loading.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
putComment timed out

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/bruno-app/src/utils/common/index.js (1)

301-317: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Duplicate prettifyHtmlString across two files, already diverging. formatResponse and prettifyJavaScriptString were properly removed from utils/common/index.js and replaced with "moved" comments, but prettifyHtmlString was left behind there while also being re-implemented in the new module — and the two copies already differ (one still logs errors, the other doesn't). Since prettifyHtmlString doesn't use prettier/fast-json-format, there's no bundle-splitting reason to duplicate it; it should have a single source of truth.

  • packages/bruno-app/src/utils/common/index.js#L301-L317: keep this as the single implementation (it's already exported from this module).
  • packages/bruno-app/src/utils/common/format-response.js#L31-L43: remove this copy and instead import prettifyHtmlString from utils/common alongside safeStringifyJSON, safeParseXML, formatHexView, isHexFormat.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/bruno-app/src/utils/common/index.js` around lines 301 - 317, Use the
existing exported prettifyHtmlString implementation in
packages/bruno-app/src/utils/common/index.js as the single source of truth. In
packages/bruno-app/src/utils/common/format-response.js, remove the local
duplicate and import prettifyHtmlString from utils/common alongside
safeStringifyJSON, safeParseXML, formatHexView, and isHexFormat; no direct
change is needed in index.js.
🧹 Nitpick comments (1)
packages/bruno-app/src/components/ResponsePane/QueryResult/QueryResultPreview/PdfPreview.js (1)

23-23: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Avoid variable shadowing.

The callback parameter { numPages } shadows the numPages state variable defined on line 17. While not functionally broken, it's a confusing practice. Consider renaming the parameter to improve clarity.

♻️ Proposed refactor
-        onLoadSuccess={({ numPages }) => setNumPages(numPages)}
+        onLoadSuccess={(pdf) => setNumPages(pdf.numPages)}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/bruno-app/src/components/ResponsePane/QueryResult/QueryResultPreview/PdfPreview.js`
at line 23, Rename the onLoadSuccess callback’s destructured numPages parameter
in PdfPreview to avoid shadowing the existing numPages state variable, and
update the setNumPages call to use the renamed parameter while preserving the
current behavior.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@packages/bruno-app/src/components/ResponsePane/QueryResult/QueryResultPreview/PdfPreview.js`:
- Around line 25-27: Update the page iteration in the PDF preview component to
use Array.from with a length of numPages || 0 instead of new Array(numPages),
ensuring the initial null state produces no Page elements while preserving the
existing page numbering and rendering props.

In `@packages/bruno-app/src/pages/Bruno/index.js`:
- Around line 127-133: Replace the default loading labels with accurate name
props on every affected fallback: in packages/bruno-app/src/pages/Bruno/index.js
at lines 127-133, pass API Spec and workspace names to the two PageLoader
instances; at lines 151-153 and 156-158, pass AI Assistant. In
packages/bruno-app/src/components/RequestTabPanel/index.js at lines 427-431,
530-534, and 538-542, pass changelog, OpenAPI Sync, and OpenAPI Spec
respectively to RequestTabPanelLoading.
- Around line 163-165: Update the Suspense wrapper around Devtools to use a null
fallback instead of PageLoader, preserving the bottom-anchored panel’s layout
while its chunk loads. Leave the Devtools rendering and mainSectionRef prop
unchanged.

In `@packages/bruno-app/src/utils/codemirror/setup.js`:
- Around line 9-41: Add the companion CSS imports for the CodeMirror addons
loaded in setup.js: dialog, foldgutter, show-hint, and lint. Place them with the
existing addon CSS imports while leaving the JavaScript addon requires
unchanged.

---

Outside diff comments:
In `@packages/bruno-app/src/utils/common/index.js`:
- Around line 301-317: Use the existing exported prettifyHtmlString
implementation in packages/bruno-app/src/utils/common/index.js as the single
source of truth. In packages/bruno-app/src/utils/common/format-response.js,
remove the local duplicate and import prettifyHtmlString from utils/common
alongside safeStringifyJSON, safeParseXML, formatHexView, and isHexFormat; no
direct change is needed in index.js.

---

Nitpick comments:
In
`@packages/bruno-app/src/components/ResponsePane/QueryResult/QueryResultPreview/PdfPreview.js`:
- Line 23: Rename the onLoadSuccess callback’s destructured numPages parameter
in PdfPreview to avoid shadowing the existing numPages state variable, and
update the setNumPages call to use the renamed parameter while preserving the
current behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 0c880ff7-f06b-4bba-b71e-b7a22bcfc91b

📥 Commits

Reviewing files that changed from the base of the PR and between 33ce3fa and b7200eb.

📒 Files selected for processing (19)
  • packages/bruno-app/rsbuild.config.mjs
  • packages/bruno-app/src/components/ApiSpecPanel/Renderers/Swagger/index.js
  • packages/bruno-app/src/components/CodeEditor/index.js
  • packages/bruno-app/src/components/RequestTabPanel/index.js
  • packages/bruno-app/src/components/RequestTabs/index.js
  • packages/bruno-app/src/components/ResponsePane/QueryResult/QueryResultPreview/PdfPreview.js
  • packages/bruno-app/src/components/ResponsePane/QueryResult/QueryResultPreview/index.js
  • packages/bruno-app/src/components/ResponsePane/QueryResult/index.js
  • packages/bruno-app/src/components/ResponsePane/ResponseBookmark/index.js
  • packages/bruno-app/src/components/ResponsePane/ResponseCopy/index.js
  • packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/index.js
  • packages/bruno-app/src/components/Sidebar/Collections/Collection/index.js
  • packages/bruno-app/src/components/Sidebar/Sections/CollectionsSection/index.js
  • packages/bruno-app/src/components/StatusBar/index.js
  • packages/bruno-app/src/pages/Bruno/index.js
  • packages/bruno-app/src/pages/Main.js
  • packages/bruno-app/src/utils/codemirror/setup.js
  • packages/bruno-app/src/utils/common/format-response.js
  • packages/bruno-app/src/utils/common/index.js
💤 Files with no reviewable changes (1)
  • packages/bruno-app/src/pages/Main.js

Comment on lines +25 to +27
{Array.from(new Array(numPages), (el, index) => (
<Page key={`page_${index + 1}`} pageNumber={index + 1} renderAnnotationLayer={false} />
))}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Avoid new Array(null) quirk.

When numPages is null (its initial state), new Array(numPages) evaluates to [null] rather than an empty array. This causes the component to prematurely render one <Page> before the document has loaded, which is logically incorrect.

Use Array.from({ length: numPages || 0 }) to safely generate the array with the expected length.

💚 Proposed fix
-        {Array.from(new Array(numPages), (el, index) => (
+        {Array.from({ length: numPages || 0 }, (_, index) => (
           <Page key={`page_${index + 1}`} pageNumber={index + 1} renderAnnotationLayer={false} />
         ))}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{Array.from(new Array(numPages), (el, index) => (
<Page key={`page_${index + 1}`} pageNumber={index + 1} renderAnnotationLayer={false} />
))}
{Array.from({ length: numPages || 0 }, (_, index) => (
<Page key={`page_${index + 1}`} pageNumber={index + 1} renderAnnotationLayer={false} />
))}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/bruno-app/src/components/ResponsePane/QueryResult/QueryResultPreview/PdfPreview.js`
around lines 25 - 27, Update the page iteration in the PDF preview component to
use Array.from with a length of numPages || 0 instead of new Array(numPages),
ensuring the initial null state produces no Page elements while preserving the
existing page numbering and rendering props.

Comment thread packages/bruno-app/src/pages/Bruno/index.js Outdated
Comment thread packages/bruno-app/src/pages/Bruno/index.js Outdated
Comment thread packages/bruno-app/src/utils/codemirror/setup.js

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/bruno-app/rsbuild.config.mjs (1)

58-65: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Make the module path regex OS-agnostic.

On Windows, the absolute resource paths passed to loaders and parsers use backslashes (\). This hardcoded forward slash may cause the regex to silently fail on Windows, breaking the lazy-loading fix for Electron. Use [\\/] to safely match both path separators.

As per path instructions, ensure all code is OS-agnostic and avoid hardcoding / or \\ separators.

💻 Proposed fix
           {
-            test: /node_modules\/react-player/,
+            test: /node_modules[\\/]react-player/,
             parser: {
               javascript: {
                 dynamicImportMode: 'eager',
               },
             },
           },
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/bruno-app/rsbuild.config.mjs` around lines 58 - 65, Update the
module path regex in the react-player rule to match both `/` and `\` separators,
using the established `[\\/]` pattern so the dynamicImportMode eager
configuration applies consistently across operating systems.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@packages/bruno-app/rsbuild.config.mjs`:
- Around line 58-65: Update the module path regex in the react-player rule to
match both `/` and `\` separators, using the established `[\\/]` pattern so the
dynamicImportMode eager configuration applies consistently across operating
systems.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 341ec9a0-d12d-4e96-a38c-36e799d6a1c4

📥 Commits

Reviewing files that changed from the base of the PR and between b7200eb and 35b82a8.

📒 Files selected for processing (6)
  • packages/bruno-app/rsbuild.config.mjs
  • packages/bruno-app/src/components/Notifications/NotificationsModal/NotificationDetail.js
  • packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/ExampleItem/index.js
  • packages/bruno-app/src/pages/Bruno/index.js
  • packages/bruno-app/src/utils/codemirror/setup.js
  • packages/bruno-app/src/utils/terminal.js
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/bruno-app/src/pages/Bruno/index.js
  • packages/bruno-app/src/utils/codemirror/setup.js

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant