Only add static media once per bundle in the diff viewer.

Review Request #14545 — Created Aug. 1, 2025 and submitted

Information

Review Board
release-7.1.x

Reviewers

We're able to display certain binary files in our diff viewer. A binary
file is associated with a review UI, which renders the file. Some Review
UIs have static media bundles which get loaded onto the webpage.
Previously, we'd load these bundles unconditionally. However, now that
we use review UIs in the diff viewer, we've discovered that the static
media of a review UI gets loaded multiple times onto the page, depending
on how many instances of the review UI are in the diff viewer.

This lead to a problem with Power Pack's PDF and Office Document review
UIs in the diff viewer. The review UIs include a bundle for the pdf.js
module, which handles PDF rendering. This module sets up some global
state that is meant to facilitate rendering multiple PDF documents on
one page. However, since we were reloading the review UI's static
bundles everytime a new instance was added to the page, this global
state would get overwritten each time which would lead to PDF rendering
issues.

This change updates the diff viewer page to keep note of what static
bundles have already been loaded onto the page, and to skip loading any
existing bundles when rendering a new diff reviewable onto the diff
viewer. This ensures that any state from the static media of a review
UI will be shared between all instances of that review UI type on the
page. And we're avoiding unnecessary requests for loading the duplicate
static media.
  • Ran unit tests (no new failures).
  • Ran JS unit tests (no new failures).
  • Tested with multiple PDF and Office documents in the diff viewer,
    as well as non-binary files.
  • Tested changing the first and last commits in the diff viewer.
  • Tested with only non-binary files in the diff viewer.
  • Tested viewing standalone review UI pages.
Summary ID
Only add static media once per review UI type in the diff viewer.
We're able to display certain binary files in our diff viewer. A binary file is associated with a review UI, which renders the file. Some Review UIs have static media bundles which get loaded onto the webpage. Previously, we'd load these bundles unconditionally. However, now that we use review UIs in the diff viewer, we've discovered that the static media of a review UI gets loaded multiple times onto the page, depending on how many instances of the review UI are in the diff viewer. This lead to a problem with Power Pack's PDF and Office Document review UIs in the diff viewer. The review UIs include a bundle for the pdf.js module, which handles PDF rendering. This module sets up some global state that is meant to facilitate rendering multiple PDF documents on one page. However, since we were reloading the review UI's static bundles everytime a new instance was added to the page, this global state would get overwritten each time which would lead to PDF rendering issues. This change updates the diff viewer page to keep note of what static bundles have already been loaded onto the page, and to skip loading any existing bundles when rendering a new diff reviewable onto the diff viewer. This ensures that any state from the static media of a review UI will be shared between all instances of that review UI type on the page. And we're avoiding unnecessary requests for loading the duplicate static media.
1a5cbe3f69f3cdc641d5c16949b7ab36d21fb7ac
Description From Last Updated

Elsewhere, we name this css_bundles and the JavaScript js_bundles. Maybe css_bundle_names and js_bundle_names would be appropriate here. That'll help differentiate …

chipx86chipx86

The diff viewer code doesn't have anything else about attachments or review UIs. This is probably better done in reviewboard/reviews/views/diffviewer.py:ReviewsDiffViewerView.get_context_data, …

daviddavid

I assume there's a circular import if we put this at the module level?

chipx86chipx86

line too long (82 > 79 characters) Column: 80 Error code: E501

reviewbotreviewbot

You could combine the statements for these.

chipx86chipx86

Same comments here.

chipx86chipx86

This should be safe to import at the file level now.

daviddavid

And probably these to match.

chipx86chipx86

No need for the backticks here (or really the one below, but it was already like that).

chipx86chipx86

New unit tests can use () => instead of function(). We used to use function() because older Jasmine required that, …

chipx86chipx86

We should be documenting these. The others didn't get documented, but at least for new ones it'd be worth doing …

chipx86chipx86

Can you swap these so they're in alphabetical order?

chipx86chipx86

line too long (82 > 79 characters) Column: 80 Error code: E501

reviewbotreviewbot

This should go below the next option (alphabetical).

chipx86chipx86

This line's too long.

chipx86chipx86

Can you add a blank line between these, so it doesn't get lost with the commented one?

chipx86chipx86
Checks run (1 failed, 1 succeeded)
flake8 failed.
JSHint passed.

flake8

david
  1. 
      
  2. reviewboard/diffviewer/diffutils.py (Diff revision 1)
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
    Show all issues

    The diff viewer code doesn't have anything else about attachments or review UIs. This is probably better done in reviewboard/reviews/views/diffviewer.py:ReviewsDiffViewerView.get_context_data, where we iterate over context['files'] and add a bunch of additional stuff.

    css_media and js_media would then become fields of SerializedReviewsDiffFile (defined in that same file)

  3. 
      
chipx86
  1. Looks great. I just have comments on naming and some small modernization nits.

  2. reviewboard/diffviewer/diffutils.py (Diff revision 1)
     
     
    Show all issues

    Elsewhere, we name this css_bundles and the JavaScript js_bundles. Maybe css_bundle_names and js_bundle_names would be appropriate here. That'll help differentiate from, say, arbitrary CSS or JavaScript URLs.

    1. I went with _media because we have an old ReviewUI.js_files attribute where people can list JavaScript URLs to include on the page instead of bundle names. So technically the js_media set can include arbitrary JavaScript URLs. The css_media will only include bundle names though.

    2. Ah okay, I didn't see that was getting populated. Sounds good then.

  3. reviewboard/diffviewer/diffutils.py (Diff revision 1)
     
     
    Show all issues

    I assume there's a circular import if we put this at the module level?

  4. reviewboard/diffviewer/diffutils.py (Diff revision 1)
     
     
     
     
     
     
    Show all issues

    You could combine the statements for these.

  5. reviewboard/reviews/views/diffviewer.py (Diff revision 1)
     
     
    Show all issues

    Same comments here.

  6. Show all issues

    And probably these to match.

  7. Show all issues

    No need for the backticks here (or really the one below, but it was already like that).

  8. Show all issues

    New unit tests can use () => instead of function().

    We used to use function() because older Jasmine required that, but now () => is recommended.

    Same with other tests.

  9. Show all issues

    We should be documenting these. The others didn't get documented, but at least for new ones it'd be worth doing so intent is clear.

  10. Show all issues

    Can you swap these so they're in alphabetical order?

  11. 
      
maubin
david
  1. 
      
  2. reviewboard/reviews/views/diffviewer.py (Diff revisions 1 - 2)
     
     
    Show all issues

    This should be safe to import at the file level now.

  3. 
      
maubin
Review request changed
Change Summary:

Added an optimization where we try take advantage of already loaded file attachments instead of hitting the database, when possible.

Commits:
Summary ID
Only add static media once per review UI type in the diff viewer.
We're able to display certain binary files in our diff viewer. A binary file is associated with a review UI, which renders the file. Some Review UIs have static media bundles which get loaded onto the webpage. Previously, we'd load these bundles unconditionally. However, now that we use review UIs in the diff viewer, we've discovered that the static media of a review UI gets loaded multiple times onto the page, depending on how many instances of the review UI are in the diff viewer. This lead to a problem with Power Pack's PDF and Office Document review UIs in the diff viewer. The review UIs include a bundle for the pdf.js module, which handles PDF rendering. This module sets up some global state that is meant to facilitate rendering multiple PDF documents on one page. However, since we were reloading the review UI's static bundles everytime a new instance was added to the page, this global state would get overwritten each time which would lead to PDF rendering issues. This change updates the diff viewer page to keep note of what static bundles have already been loaded onto the page, and to skip loading any existing bundles when rendering a new diff reviewable onto the diff viewer. This ensures that any state from the static media of a review UI will be shared between all instances of that review UI type on the page. And we're avoiding unnecessary requests for loading the duplicate static media.
e3cd17ac5c048c48a6fd3d0797271d5da9481492
Only add static media once per review UI type in the diff viewer.
We're able to display certain binary files in our diff viewer. A binary file is associated with a review UI, which renders the file. Some Review UIs have static media bundles which get loaded onto the webpage. Previously, we'd load these bundles unconditionally. However, now that we use review UIs in the diff viewer, we've discovered that the static media of a review UI gets loaded multiple times onto the page, depending on how many instances of the review UI are in the diff viewer. This lead to a problem with Power Pack's PDF and Office Document review UIs in the diff viewer. The review UIs include a bundle for the pdf.js module, which handles PDF rendering. This module sets up some global state that is meant to facilitate rendering multiple PDF documents on one page. However, since we were reloading the review UI's static bundles everytime a new instance was added to the page, this global state would get overwritten each time which would lead to PDF rendering issues. This change updates the diff viewer page to keep note of what static bundles have already been loaded onto the page, and to skip loading any existing bundles when rendering a new diff reviewable onto the diff viewer. This ensures that any state from the static media of a review UI will be shared between all instances of that review UI type on the page. And we're avoiding unnecessary requests for loading the duplicate static media.
1a5cbe3f69f3cdc641d5c16949b7ab36d21fb7ac

Checks run (1 failed, 1 succeeded)

flake8 failed.
JSHint passed.

flake8

david
  1. Ship It!
  2. 
      
chipx86
  1. Tiny things, but everything looks good! Ship it after this.

  2. Show all issues

    This should go below the next option (alphabetical).

  3. Show all issues

    This line's too long.

  4. Show all issues

    Can you add a blank line between these, so it doesn't get lost with the commented one?

  5. 
      
maubin
Review request changed
Status:
Completed
Change Summary:
Pushed to release-7.1.x (47c5d7e)