Skip to content

feat: new preload strategy swap-low#72

Merged
danielroe merged 4 commits intodanielroe:mainfrom
SukkaW:swap-low
Apr 6, 2025
Merged

feat: new preload strategy swap-low#72
danielroe merged 4 commits intodanielroe:mainfrom
SukkaW:swap-low

Conversation

@SukkaW
Copy link
Copy Markdown
Contributor

@SukkaW SukkaW commented Dec 17, 2024

swap-low uses rel="alternate stylesheet" (instead of rel="alternate stylesheet preload" used by swap-high) to ensure the lowest priority.

See https://filamentgroup.github.io/loadCSS/test/new-low.html


This was originally implemented in GoogleChromeLabs/critters#101, but Google Chrome Teams simply ignored my PR for three years (Just a typical tradition of how Google Chrome Teams treats open-source contributions as always) and simply closed it as they archive the repo.

Description by Callstackai

This PR introduces a new preload strategy called swap-low, which uses rel="alternate stylesheet" to ensure the lowest priority for stylesheets. It updates the README, TypeScript definitions, and adds tests for the new strategy.

Diagrams of code changes
sequenceDiagram
    participant Browser
    participant Beasties
    participant StylesheetLink

    Browser->>Beasties: Process HTML with stylesheet
    
    alt preload="swap-low"
        Beasties->>StylesheetLink: Set rel="alternate stylesheet"
        Beasties->>StylesheetLink: Set title="styles"
        Beasties->>StylesheetLink: Add onload handler
        StylesheetLink-->>Browser: Load stylesheet with lowest priority
        
        Note over StylesheetLink: Once loaded
        StylesheetLink->>StylesheetLink: Clear title
        StylesheetLink->>StylesheetLink: Set rel="stylesheet"
    end

    Beasties->>Browser: Return processed HTML
Loading
Files Changed
FileSummary
packages/beasties/README.mdAdded documentation for the new swap-low preload strategy.
packages/beasties/src/index.d.tsUpdated TypeScript definitions to include swap-low in the preload options.
packages/beasties/src/index.tsImplemented the logic for the swap-low preload strategy in the Beasties class.
packages/beasties/src/types.tsUpdated type definitions to include swap-low in the PreloadStrategy type.
packages/beasties/test/__snapshots__/beasties.test.ts.snapAdded snapshot for the swap-low preload mode test.
packages/beasties/test/beasties.test.tsAdded unit tests to verify the behavior of the swap-low preload mode.

This PR includes files in programming languages that we currently do not support. We have not reviewed files with the extensions .md, .ts, .snap. See list of supported languages.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Dec 17, 2024

Walkthrough

The pull request introduces a new preload strategy "swap-low" to the Beasties package. This addition allows for the conversion of stylesheet links to an alternate stylesheet without the preload attribute, ensuring it has the lowest priority compared to other strategies. The change is implemented across multiple files, including the README, type definitions, and implementation, providing a comprehensive update to the package's configuration options for stylesheet preloading.

Changes

File Change Summary
packages/beasties/README.md Added documentation for new "swap-low" preload strategy and updated type definition for PreloadStrategy
packages/beasties/src/types.ts Updated PreloadStrategy type to include "swap-low" option
packages/beasties/src/index.d.ts Extended Options interface to support "swap-low" preload strategy
packages/beasties/src/index.ts Implemented conditional logic for "swap-low" preload mode in embedLinkedStylesheet method
packages/beasties/test/beasties.test.ts Added tests for "swap-low" and "swap-high" preload modes

Possibly related PRs

  • Add swap-high preload option #46: The changes in the main PR are related to the addition of a new preload option, "swap-low", in the same Options interface where the retrieved PR added "swap-high", indicating a direct modification to the same code structure.

Suggested reviewers

  • alan-agius4

📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ab0e8d1 and b916377.

⛔ Files ignored due to path filters (1)
  • packages/beasties/test/__snapshots__/beasties.test.ts.snap is excluded by !**/*.snap
📒 Files selected for processing (2)
  • packages/beasties/src/index.ts (1 hunks)
  • packages/beasties/test/beasties.test.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/beasties/src/index.ts
🧰 Additional context used
🧬 Code Definitions (1)
packages/beasties/test/beasties.test.ts (1)
packages/beasties/src/index.ts (1)
  • Beasties (32-696)
🔇 Additional comments (3)
packages/beasties/test/beasties.test.ts (3)

409-433: Well-implemented test case for the new 'swap-low' preload mode

The test thoroughly verifies the intended behaviour of the new preload strategy:

  1. Correctly initialises Beasties with the 'swap-low' option
  2. Verifies the critical CSS is inlined in a style tag
  3. Confirms the stylesheet link uses rel="alternate stylesheet" without the "preload" keyword, ensuring lowest priority loading
  4. Checks that the noscript fallback is properly included

This implementation aligns perfectly with the PR objective of creating a lower-priority preload strategy.


435-459: Good complementary test for 'swap-high' mode

Adding this test alongside the 'swap-low' test is excellent for comparison and regression testing. It clearly demonstrates the key difference between the two strategies:

  • 'swap-low' uses rel="alternate stylesheet"
  • 'swap-high' uses rel="alternate stylesheet preload"

Both tests follow the same structure, making it easy to understand their differences and ensuring consistency in the test suite.


409-459:

Details

❓ Verification inconclusive

Verify test coverage with a snapshot test

Both test cases include expect(result).toMatchSnapshot() which is perfect for catching any unexpected changes in the rendered HTML. This ensures comprehensive coverage of the new feature and protects against regression.

You might want to run these tests with browser compatibility checks to ensure the rel="alternate stylesheet" attribute works as expected across different browsers, particularly older ones.


🌐 Web query:

Are there any browser compatibility issues with using rel="alternate stylesheet" as a way to defer stylesheet loading?

💡 Result:

Using rel="alternate stylesheet" to defer stylesheet loading faces significant browser compatibility challenges and may not achieve the intended performance benefits. Here's a breakdown:

Browser Support Limitations

  • Firefox fully supports alternate stylesheets via the View > Page Style menu[1][3][6].
  • Chrome requires extensions for this functionality (as of version 48)[1][2], and support remains inconsistent in newer versions.
  • Internet Explorer partially supports it (starting with IE8)[1], while Safari and Edge have unknown or limited compatibility[1][3].

Key Issues

  1. No Deferred Loading:
    Alternate stylesheets are typically loaded immediately by browsers, even if not applied by default[1][3]. This negates any performance gains from deferred loading, as all stylesheets are fetched during initial page load.

  2. Inconsistent Application:
    Browsers without native support (e.g., Chrome without extensions) will ignore the rel="alternate stylesheet" attribute and apply all stylesheets indiscriminately[2][3], potentially breaking the page’s visual design.

  3. Lack of User Control:
    Most browsers (except Firefox and IE) lack built-in UI for users to switch stylesheets, requiring custom JavaScript solutions[1][2][6].

Recommendations

  • For performance optimization, use standard techniques like media="print", preload, or loading="lazy" for images.
  • To offer theme switching, implement a JavaScript-based style switcher[5], as it works reliably across all modern browsers.

In summary, rel="alternate stylesheet" is not a viable method for deferring stylesheet loading due to inconsistent browser support and loading behavior.

Citations:


Attention: Browser Compatibility Testing Recommended for Deferred Stylesheet Loading

The snapshot tests effectively capture any unintended alterations in the rendered HTML, ensuring regression safety, which is excellent. However, please note the following regarding the use of rel="alternate stylesheet":

  • Compatibility Issues: Although Firefox supports alternate stylesheets, browsers such as Chrome, Safari, and Edge may not defer the stylesheet loading as intended. In some cases, these browsers load the stylesheet immediately, negating the deferred loading benefit.
  • Inconsistent Behaviour: Chrome (and possibly other browsers) may require extensions or additional handling, and the overall support is inconsistent across different versions.
  • Additional Verification: While the snapshot tests secure the HTML output, it is advisable to run cross-browser compatibility tests to confirm that the dynamic switch (via the onload attribute) behaves consistently across the range of supported browsers.

Please consider these points when evaluating the performance benefits and functionality of the deferred stylesheet loading strategy.

✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai plan to trigger planning for file edits and PR creation.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
packages/beasties/src/types.ts (1)

13-13: Fix grammar in documentation.

Change "compare to" to "compared to" for correct English usage.

- * - **"swap-low":** Use `<link rel="alternate stylesheet">` (no `preload` in `rel` here!) and swap to `rel="stylesheet"` once loaded ([details](http://filamentgroup.github.io/loadCSS/test/new-low.html)). It ensures lowest priority compare to `swap-high`. <kbd>JS</kbd>
+ * - **"swap-low":** Use `<link rel="alternate stylesheet">` (no `preload` in `rel` here!) and swap to `rel="stylesheet"` once loaded ([details](http://filamentgroup.github.io/loadCSS/test/new-low.html)). It ensures lowest priority compared to `swap-high`. <kbd>JS</kbd>
packages/beasties/README.md (1)

243-243: Fix grammar in documentation.

Change "compare to" to "compared to" for correct English usage.

- - **"swap-low":** Use `<link rel="alternate stylesheet">` (no `preload` in `rel` here!) and swap to `rel="stylesheet"` once loaded ([details](http://filamentgroup.github.io/loadCSS/test/new-low.html)). It ensures lowest priority compare to `swap-high`. <kbd>JS</kbd>
+ - **"swap-low":** Use `<link rel="alternate stylesheet">` (no `preload` in `rel` here!) and swap to `rel="stylesheet"` once loaded ([details](http://filamentgroup.github.io/loadCSS/test/new-low.html)). It ensures lowest priority compared to `swap-high`. <kbd>JS</kbd>
🧰 Tools
🪛 LanguageTool

[uncategorized] ~243-~243: This verb may not be in the correct form. Consider using a different form for this context.
Context: ...-low.html)). It ensures lowest priority compare to swap-high. JS - **"js":...

(AI_EN_LECTOR_REPLACEMENT_VERB_FORM)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 30a442c and e887b64.

📒 Files selected for processing (4)
  • packages/beasties/README.md (1 hunks)
  • packages/beasties/src/index.d.ts (1 hunks)
  • packages/beasties/src/index.ts (1 hunks)
  • packages/beasties/src/types.ts (1 hunks)
🧰 Additional context used
🪛 LanguageTool
packages/beasties/README.md

[uncategorized] ~243-~243: This verb may not be in the correct form. Consider using a different form for this context.
Context: ...-low.html)). It ensures lowest priority compare to swap-high. JS - **"js":...

(AI_EN_LECTOR_REPLACEMENT_VERB_FORM)

🔇 Additional comments (4)
packages/beasties/src/types.ts (1)

18-18: LGTM! Type definition updated correctly.

The new swap-low strategy has been properly added to the PreloadStrategy type.

packages/beasties/src/index.d.ts (1)

50-50: LGTM! Options interface updated correctly.

The swap-low strategy has been properly added to the preload option in the Options interface, maintaining consistency with the PreloadStrategy type.

packages/beasties/README.md (1)

243-248: LGTM! Documentation updated comprehensively.

The new swap-low strategy is well-documented with clear explanation of its purpose, behaviour, and implementation details. The type definition example is also correctly updated.

🧰 Tools
🪛 LanguageTool

[uncategorized] ~243-~243: This verb may not be in the correct form. Consider using a different form for this context.
Context: ...-low.html)). It ensures lowest priority compare to swap-high. JS - **"js":...

(AI_EN_LECTOR_REPLACEMENT_VERB_FORM)

packages/beasties/src/index.ts (1)

313-319: Implementation looks good and matches the reference!

The new preload strategy swap-low is correctly implemented, following the same pattern as other strategies. The implementation properly sets the rel="alternate stylesheet" attribute to ensure lowest priority loading, which aligns with the reference implementation from Filament Group's test page.

Let's verify the implementation against the reference:

✅ Verification successful

Implementation matches the reference implementation perfectly

The verification confirms that our implementation exactly mirrors the reference implementation from Filament Group's test page:

  • Both set rel="alternate stylesheet"
  • Both use title="styles"
  • Both use the same onload handler to clear the title and switch to rel="stylesheet"
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Compare our implementation with the reference test page
# Expected: Our implementation should match the reference implementation

# Fetch the reference implementation
curl -s https://filamentgroup.github.io/loadCSS/test/new-low.html | rg -A 5 'rel="alternate stylesheet"'

# Check our implementation
rg -A 5 'preloadMode === .swap-low.' packages/beasties/src/index.ts

Length of output: 1228

@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented Dec 25, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 84.92%. Comparing base (67281f2) to head (b916377).

Additional details and impacted files
@@            Coverage Diff             @@
##             main      #72      +/-   ##
==========================================
+ Coverage   84.43%   84.92%   +0.48%     
==========================================
  Files           7        7              
  Lines        1221     1227       +6     
  Branches      283      286       +3     
==========================================
+ Hits         1031     1042      +11     
+ Misses        190      185       -5     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq bot commented Dec 25, 2024

CodSpeed Performance Report

Merging #72 will not alter performance

Comparing SukkaW:swap-low (b916377) with main (67281f2)

Summary

✅ 9 untouched benchmarks

@danielroe
Copy link
Copy Markdown
Owner

i love it! i wonder if there's any useful way of adding tests to cover the strategy?

@SukkaW
Copy link
Copy Markdown
Contributor Author

SukkaW commented Dec 25, 2024

i love it! i wonder if there's any useful way of adding tests to cover the strategy?

Lemme see how to setup a test case for this!

@danielroe
Copy link
Copy Markdown
Owner

did you get a chance to look into this?

I'm also happy to merge without tests on the interim basis

@SukkaW
Copy link
Copy Markdown
Contributor Author

SukkaW commented Apr 6, 2025

did you get a chance to look into this?

Ah sorry. Haven't got any time for a while looking into this and then I just forgot it.

And besides, I don't know what unit test case to add. Currently, beasties doesn't have any existing unit test cases for different modes.

@danielroe danielroe merged commit f99fff2 into danielroe:main Apr 6, 2025
9 checks passed
@danielroe
Copy link
Copy Markdown
Owner

thank you ❤️

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants