Fix excessive icon refetch made by importing bookmarks
Twitter bookmark import was causing excessive icon refetching, making too many network requests during progress updates. If 1000 bookmakrs processed 1000 http requests are sent to fetch icon.
Solution:
Changed Twitter import button to use CSS background-image instead of <img> elements to load the icon once and cache it.
Changes:
- Updated
createTwitterImportButton()inui-components.tsto use CSS background-image - Added cleanup code in
updateTwitterImportUI()to handle old<img>elements - Icon now loads once via
browser.runtime.getURL("/icon-16.png")and stays cached
Result:
- Stops repeated icon requests during bookmark import updates
- Better performance, fewer API calls
- Same visual appearance, more efficient
Note: Same <img> issue exists in ChatGPT, Claude, T3, and toast notifications. Should create a utility function to fix this pattern across all platforms.
How to use the Graphite Merge Queue
Add the label Main to this PR to add it to the merge queue.
You must have a Graphite account in order to use the merge queue. Sign up using this link.
An organization admin has enabled the Graphite Merge Queue in this repository.
Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue.
@fyzanshaik i have tested in prod i don't see this issue at all both in browser network tab and extension network tab
FYI: the requests are going to just extension, not to any server.
@MaheshtheDev I verified it once again, and yes the requests are happening to the extension itself. I guess its not a big deal
https://github.com/user-attachments/assets/242cbf44-6657-4efa-a4eb-51e6c3e1ca2a
Code Review - PR #496: Fix Excessive Icon Refetch During Bookmark Import
Summary
This PR optimizes the Twitter bookmark import feature by eliminating excessive icon refetching. Instead of using <img> elements that trigger network requests on every UI update, it uses CSS background-image which loads the icon once and caches it.
โ Strengths
- Performance Fix: Reduces 1000 HTTP requests to 1 when importing 1000 bookmarks
- Root Cause Analysis: Correctly identifies the problem (repeated innerHTML assignments creating new img elements)
-
Backward Compatibility: Includes cleanup code to handle existing old
<img>elements - Documentation: Well-documented PR description with clear before/after comparison
- Identifies Future Work: Notes that the same pattern exists in other components
๐ Code Quality
Positives
- Clean separation of concerns (icon setup vs text updates)
- Proper DOM element reuse via
#sm-import-textID - Good inline styles organization
Suggestions for Improvement
1. Magic Numbers & Hardcoded Values
// Current
button.style.backgroundSize = "20px 20px"
button.style.paddingLeft = "28px"
// Suggest: Add constants at top of file
const ICON_SIZE = 20
const ICON_PADDING = 28 // ICON_SIZE + 8px gap
2. Font Size Inconsistency
// ui-components.ts uses 12px
textSpan.style.cssText = "font-weight: 500; font-size: 12px;"
// twitter.ts uses 14px
textSpan.style.cssText = "font-weight: 500; font-size: 14px;"
Question: Is this intentional? Should they be consistent?
3. Potential Memory Leak
The existingImg.remove() handles backward compat, but consider:
- Will old event listeners be cleaned up?
- Could this cause issues if called multiple times?
4. DRY Principle Violation The icon setup code is duplicated between:
- Initial button creation (
createTwitterImportButton) - Cleanup/migration code (
updateTwitterImportUI)
Recommendation: Extract to a shared function:
function applyIconBackground(element: HTMLElement, iconUrl: string) {
element.style.backgroundImage = `url("${iconUrl}")`
element.style.backgroundRepeat = "no-repeat"
element.style.backgroundSize = "20px 20px"
element.style.backgroundPosition = "left center"
element.style.paddingLeft = "28px"
}
๐ง Technical Considerations
1. Browser Compatibility
- CSS background-image approach is well-supported
- No concerns for modern browsers
2. Accessibility
- โ Proper alt text was preserved (though now in CSS)
- โ ๏ธ Consider: Should there be an
aria-labelsince the icon is now decorative in CSS?
3. Extension-Specific Concerns
-
browser.runtime.getURL()is correct for extension resources - Icon will be cached by browser automatically with this approach
๐งช Testing Recommendations
- [ ] Test importing 1000+ bookmarks (verify performance improvement)
- [ ] Test upgrading from old version (verify img cleanup works)
- [ ] Test rapid UI updates during import
- [ ] Verify visual appearance matches original
- [ ] Test in different browsers (Chrome, Firefox, Edge)
- [ ] Monitor network tab to confirm single icon request
๐ฏ Follow-up Items
As noted in the PR description:
- Apply same fix to ChatGPT button
- Apply same fix to Claude button
- Apply same fix to T3 button
- Apply same fix to toast notifications
-
Create shared utility:
createButtonWithCachedIcon()to prevent future occurrences
Suggestion: Create a tracking issue for these follow-ups to ensure they are addressed.
๐ Security
- No security concerns
- Using proper extension API for resource URLs
โ๏ธ Verdict
Approve with minor suggestions - This is a solid performance optimization that addresses a real problem. The code works but could benefit from:
- Extracting magic numbers to constants
- Creating a shared utility function for the icon pattern
- Addressing the font-size inconsistency
- Adding aria-label for accessibility
The PR can be merged as-is, but I strongly recommend creating follow-up issues/PRs for:
- Applying the same fix to other components mentioned
- Creating the shared utility function
- Adding constants for magic numbers
Great catch on the performance issue!
Review generated by Claude Code
Code Review: Fix Excessive Icon Refetch
Summary
This PR fixes a real performance issue where importing 1000 bookmarks triggered 1000 HTTP requests for the same icon. The solution replaces img tags with CSS background-image to leverage browser caching. This is a solid performance fix with good execution.
Positive Aspects
- Correctly identifies the problem - Progress updates were causing repeated DOM manipulation and image reloads
- Effective solution - CSS background-image loads once and stays cached
- Backward compatibility - Handles cleanup of old img elements gracefully
- Maintains visual consistency - Same appearance, better performance
- Documents the issue - Notes that similar patterns exist in other platforms
Code Quality Analysis
1. Excellent: Separation of concerns
Location: apps/browser-extension/utils/ui-components.ts:187-200
Good: Icon loaded once via CSS, text in separate span for easy updates. Browser caches the background-image properly.
2. Smart: Backward compatibility handling
Location: apps/browser-extension/entrypoints/content/twitter.ts:123-133
Handles migration from old img approach gracefully. Ensures consistent behavior across updates with no breaking changes.
Issues and Concerns
1. Potential race condition (Low severity)
Location: apps/browser-extension/entrypoints/content/twitter.ts:160-165
Issue: If another import starts within the 3-second window after completion, the setTimeout could fire and reset the button to "Import Bookmarks" while an import is in progress.
Recommendation: Store timeout ID and clear it when new import starts.
2. Magic numbers and inconsistent styling (Minor)
Issues:
- fontSize: "14px" in twitter.ts:145 but "12px" in ui-components.ts:197 - should be consistent
- Hardcoded color #059669 in twitter.ts:156 - should be a constant
- Multiple inline styles instead of CSS classes
Recommendation: Create constants for reusability.
3. Inconsistent icon size handling
Icon size (20px) is duplicated in two places. Should be a constant to avoid drift.
Performance Analysis
Before:
- 1000 bookmarks = 1000+ HTTP requests for the same icon
- Each innerHTML update creates new img element โ browser fetches icon again
After:
- 1 HTTP request for icon (CSS background-image)
- Text updates only modify DOM text node
Performance gain: โญโญโญโญโญ Excellent - ~99% reduction in icon-related network time
Testing Recommendations
- Performance testing - Verify only ONE request to icon-16.png with 100+ bookmarks
- Visual regression - Compare button appearance, test success state
- Edge cases - Test back-to-back imports, cache disabled, slow network
- Backward compatibility - Test upgrade mid-import
Suggested Changes
- HIGH PRIORITY: Add timeout cleanup to prevent race condition
- MEDIUM PRIORITY: Extract magic numbers to constants, make font-size consistent
- FUTURE WORK: Apply fix to ChatGPT, Claude, T3, and toast notifications
Security Analysis
Status: No security concerns identified
- Uses browser.runtime.getURL() - trusted source
- No user input in CSS values
- No XSS vectors
Code Quality: 8.5/10
Pros: Solves real performance problem, clean implementation, good backward compatibility
Cons: Minor race condition possible, some magic numbers, font size inconsistency
Approval Status: Approve with minor suggestions
This is a solid performance fix. The core fix is excellent and should be merged soon. Suggested improvements can be follow-up PRs if needed.
Additional Note
Great catch on identifying this pattern in other platforms! Consider creating a utility function for reusable icon button creation.