Skip to content

Conversation

@vlidholt
Copy link
Contributor

@vlidholt vlidholt commented Oct 6, 2025

Description

Adds support for cache busting using a `cacheBustingConfig:

  • First, create a CacheBustingConfig.
  • Then, add the config to the staticFileHandler.
  • Finally, create busted links using the assetPath method of the config.

Example added in example/static_files_example.dart.

Related Issues

Closes: #200
Fixes: #194

Pre-Launch Checklist

Please ensure that your PR meets the following requirements before submitting:

  • This update focuses on a single feature or bug fix. (For multiple fixes, please submit separate PRs.)
  • I have read and followed the Dart Style Guide and formatted the code using dart format.
  • I have referenced at least one issue this PR fixes or is related to.
  • I have updated/added relevant documentation (doc comments with ///), ensuring consistency with existing project documentation.
  • I have added new tests to verify the changes.
  • All existing and new tests pass successfully.
  • I have documented any breaking changes below.

Breaking Changes

No breaking changes

Summary by CodeRabbit

  • New Features

    • Introduced cache-busting for static assets, enabling hashed URLs and transparent request rewriting.
    • Added configuration and utilities to generate cache-busted URLs with graceful fallbacks.
    • Exposed a public helper to retrieve static file info (including MIME/ETag).
  • Documentation

    • Added a runnable example server showcasing static file serving with cache-busted URLs.
  • Tests

    • Added comprehensive test coverage for cache-busting behavior, edge cases, and integration scenarios.
  • Chores

    • Included a sample static file for demonstration.

@vlidholt vlidholt requested a review from nielsenko October 6, 2025 18:57
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 6, 2025

📝 Walkthrough

Walkthrough

Adds cache-busting middleware and configuration, exposes a static file info accessor, wires export, provides an example server serving cache-busted static assets, includes a sample file, and adds comprehensive tests for middleware behavior and integration.

Changes

Cohort / File(s) Summary
Example app and assets
example/static_files_example.dart, example/static_files/hello.txt
New example HTTP server demonstrating static serving with cache-busted URLs; adds a sample text asset.
Middleware and export
lib/src/io/static/middleware_cache_busting.dart, lib/relic.dart
Introduces cacheBusting middleware, CacheBustingConfig with bust/tryBust, and exports the middleware from the main library.
Static handler accessor
lib/src/io/static/static_handler.dart
Adds public getStaticFileInfo(File, {MimeTypeResolver?}) delegating to existing internal logic.
Tests for cache busting
test/static/cache_busting_middleware_test.dart
Adds tests covering URL rewriting, mounting scenarios, edge cases, error handling, and end-to-end serving of cache-busted assets.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant C as Client
  participant S as Server
  participant M as cacheBusting Middleware
  participant R as Router
  participant H as StaticHandler
  participant FS as File System

  C->>S: GET /static/logo@<hash>.png
  S->>M: Request
  Note over M: Detects mountPrefix and strips "@<hash>" from last segment
  M->>R: Forward as /static/logo.png
  R->>H: Serve /static/logo.png
  H->>FS: Read file, compute ETag/MIME
  FS-->>H: File bytes + meta
  H-->>C: 200 OK (content)
Loading
sequenceDiagram
  autonumber
  participant App as Example App
  participant Cfg as CacheBustingConfig
  participant FS as File System
  Note over App,Cfg: Generating a cache-busted URL at render time
  App->>Cfg: bust("/static/logo.png")
  Cfg->>FS: Resolve and stat file, compute etag/hash
  FS-->>Cfg: Info (hash)
  Cfg-->>App: "/static/logo@<hash>.png"
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title Check ✅ Passed The title clearly and concisely summarizes the main feature added by this pull request—support for cache busting—and aligns with the conventional commit style without extraneous details.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
Description Check ✅ Passed The pull request description adheres to the repository template by including a clear Description, Related Issues section with issue references, a comprehensive Pre-Launch Checklist, and a Breaking Changes declaration. It outlines the new cache busting feature, usage example, and properly references closing and fixing issues. All major template sections are present and informative.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch cache-busting

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 and usage tips.

@codecov
Copy link

codecov bot commented Oct 6, 2025

Codecov Report

❌ Patch coverage is 88.88889% with 8 lines in your changes missing coverage. Please review.
✅ Project coverage is 91.83%. Comparing base (922a5a7) to head (9180ea0).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
lib/src/io/static/cache_busting_config.dart 87.93% 7 Missing ⚠️
lib/src/io/static/static_handler.dart 92.85% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #192      +/-   ##
==========================================
- Coverage   91.90%   91.83%   -0.07%     
==========================================
  Files          85       86       +1     
  Lines        3174     3245      +71     
  Branches     1639     1664      +25     
==========================================
+ Hits         2917     2980      +63     
- Misses        257      265       +8     

☔ 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.

@vlidholt
Copy link
Contributor Author

vlidholt commented Oct 6, 2025

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 6, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Contributor

@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: 2

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2338114 and 372d0b2.

⛔ Files ignored due to path filters (1)
  • example/static_files/logo.svg is excluded by !**/*.svg
📒 Files selected for processing (6)
  • example/static_files/hello.txt (1 hunks)
  • example/static_files_example.dart (1 hunks)
  • lib/relic.dart (1 hunks)
  • lib/src/io/static/middleware_cache_busting.dart (1 hunks)
  • lib/src/io/static/static_handler.dart (1 hunks)
  • test/static/cache_busting_middleware_test.dart (1 hunks)

Copy link
Collaborator

@nielsenko nielsenko left a comment

Choose a reason for hiding this comment

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

Looks good. Great test coverage 🚀

I have a few comments you can look over.

While this is a great improvement there are some things I think we should consider to address later.

  • What about CDN hosted assets?
  • What about pre-building a manifest to avoid hash calculations on each pod we spin up?
  • Do we want to be more strict, and ensure we only return content that are guaranteed to match the content? (as discussed on slack)

@nielsenko
Copy link
Collaborator

Regarding issue, we have serverpod/serverpod#3832 in serverpod. We should probably have a linking issue in relic. @CodeRabbit Can you create one?

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 7, 2025

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Fetch details of the serverpod issue to understand the context
gh issue view 3832 --repo serverpod/serverpod --json title,body,url

Length of output: 2103


🏁 Script executed:

#!/bin/bash
# Create a new issue in relic repository linking to serverpod issue and current PR
gh issue create \
  --repo serverpod/relic \
  --title "Cache busting support for Serverpod static assets" \
  --body "This issue tracks the implementation of cache busting support in Relic, which is needed for Serverpod's automatic static file cache busting feature.

**Related:**
- Serverpod issue: https://github.com/serverpod/serverpod/issues/3832
- Implementation PR: https://github.com/serverpod/relic/pull/192

**Context:**
PR #192 adds cache busting middleware to Relic, providing the foundation for Serverpod to implement automatic cache busting for static assets. This feature allows static assets to be aggressively cached while ensuring updated assets are reloaded when changed.

**Implementation Status:**
The core cache busting functionality has been implemented in PR #192, including:
- \`cacheBusting\` middleware for URL rewriting
- \`CacheBustingConfig\` for generating cache-busted URLs
- Support for hash-based cache busting (e.g., \`/static/file.ext\` → \`/static/file@hash.ext\`)

**Next Steps:**
Integration with Serverpod's web server and templating engine as outlined in serverpod/serverpod#3832.

Requested by: @nielsenko
Reference comment: https://github.com/serverpod/relic/pull/192#discussion_r1234567890" \
  --assignee nielsenko

Length of output: 45


@nielsenko: I've created issue #194 in the relic repository that links to the Serverpod issue #3832 and references this PR #192. The issue tracks how this cache busting implementation in Relic provides the foundation for Serverpod's automatic static file cache busting feature.

You can view the issue here: #194

Copy link
Contributor

@SandPod SandPod left a comment

Choose a reason for hiding this comment

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

Nice to get this solved!

Have a question regarding the hash placement method. As far as I understand this deviates from the recommended standard. Will this work well with CDNs? As is most likely how static assets will be served.

We should also refactor the test to follow the Given, When, Then pattern.

I'll trust @nielsenko review on the implementation details.

@SandPod SandPod linked an issue Oct 8, 2025 that may be closed by this pull request
@SandPod SandPod self-requested a review October 10, 2025 09:34
Copy link
Contributor Author

@vlidholt vlidholt left a comment

Choose a reason for hiding this comment

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

This looks great now! 🥳 Thanks for cleaning it up.

Copy link
Collaborator

@nielsenko nielsenko left a comment

Choose a reason for hiding this comment

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

Got a few comments.

Most importantly I believe validateSeparator should also check for overlap with /

@SandPod SandPod requested a review from nielsenko October 13, 2025 06:21
@nielsenko
Copy link
Collaborator

We can disregard the pana check failure.

@SandPod SandPod merged commit 36b367a into main Oct 13, 2025
25 of 28 checks passed
@SandPod SandPod deleted the cache-busting branch October 13, 2025 07:30
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.

Refactor cache busting middleware tests to conform to test standards Cache busting support for Serverpod static assets

4 participants