Improve the performance when highlighting sourcecode with highlight.js
Context:
As part of refactoring the repository files browser, we're also changing from highlighting source code on the backend (with Rouge) to highlighting source code on the frontend (with Highlight.js).
What does this MR do and why?
As part of highlighting source code on the frontend with Highlight.js we need to ensure the frontend stays as performant as possible, especially when highlighting large files.
This MR ensures that the frontend can highlight large source files when highlighting with highlight.js.
How do we handle large source files in this MR?
- Chunks:
-
In this MR we've added a mechanism on the frontend to split source code into chunks of 70 lines of code, we highlight and display the 1st chunk (L1-70) to the user as quickly as possible. The rest of the lines (L71+) gets rendered once the browser goes into an idle state (
requestIdleCallback). -
Each chunk is self-contained, this ensures when for example the width of a container on line 1000 changes, it does not trigger a repaint on a parent element that wraps all 1000 lines.
- Only highlighting what is visible to the user:
- We only highlight the chunk that is currently visible to the user. By making use of the Intersection Observer API we can determine when a chunk becomes visible and highlight it accordingly.
- Ensure content that is not visible to the user does not require lots of paints:
-
Content that is not visible to the user do not need to look nice, so by making text transparent and rendering raw (unhighlighted) text, the browser spends less resources on painting content that is not immediately relevant.
-
Why use transparent text as opposed to hiding content entirely?
- If content is hidden entirely, native find text (⌘ + F) won't work.
- When URL contains line numbers, the browser needs to be able to jump to the correct line.
Screenshots or screen recordings
As can be seen below, I get a consistent LCP no matter what the file size is:
How to set up and validate locally
- Enable the Blob Viewer Refactor and highlight.js feature flag
Feature.enable(:refactor_blob_viewer)
Feature.enable(:highlight_js)
- Open a large text file in the blob viewer (sample file)
MR acceptance checklist
This checklist encourages us to confirm any changes have been analyzed to reduce risks in quality, performance, reliability, security, and maintainability.
-
I have evaluated the MR acceptance checklist for this MR.
Related to #349181 (closed)





