Skip to content

LCP image src set#755

Merged
feruzm merged 6 commits intodevelopfrom
lcpi
Apr 13, 2026
Merged

LCP image src set#755
feruzm merged 6 commits intodevelopfrom
lcpi

Conversation

@feruzm
Copy link
Copy Markdown
Member

@feruzm feruzm commented Apr 12, 2026

Summary by CodeRabbit

  • New Features

    • Images now include responsive srcset and sizes for improved display and proxy-aware loading.
    • Added a public helper to generate responsive srcset entries.
  • Bug Fixes

    • Rejects submissions with empty or whitespace-only bodies.
    • Outbound analytics errors are now swallowed to avoid surfacing failures.
    • Sanitization now validates img srcset URLs and strips src/srcset/sizes for invalid or relative sources.
  • Tests

    • Updated image-related snapshots and unit tests to cover srcset generation and proxy behavior.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 12, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds responsive image srcset generation and sanitization, exposes the srcset builder, updates image whitelist, updates tests/fixtures, adds upstream validation for empty post bodies in post-edit, and wraps analytics submission in a try/catch to swallow network errors.

Changes

Cohort / File(s) Summary
Post Edit Validation
apps/web/src/app/publish/entry/[author]/[permlink]/_hooks/use-post-edit.ts
Added upfront validation in the post-edit mutation to reject updates when body is missing or only whitespace by throwing a localized error before metadata processing.
Render Helper Public API
packages/render-helper/src/index.ts
Re-exported buildSrcSet from ./proxify-image-src to expose the srcset builder in the package API.
Srcset Implementation & Image Handling
packages/render-helper/src/proxify-image-src.ts, packages/render-helper/src/methods/img.method.ts, packages/render-helper/src/methods/sanitize-html.method.ts, packages/render-helper/src/consts/allowed-attributes.const.ts
Added buildSrcSet and getProxyBase, defined responsive width constants, improved proxied-detection/proxification logic, generate and attach srcset/sizes where appropriate, and validate srcset URLs during sanitization. Allowed srcset and sizes in the XSS whitelist for <img>.
Render Helper Tests & Fixtures
packages/render-helper/src/proxify-image-src.spec.ts, packages/render-helper/src/markdown-2-html.spec.ts, packages/render-helper/src/test/data/legacy/2112524.json
Added tests for buildSrcSet (falsy inputs, expected width descriptors, proxied inputs, custom proxy base) and updated snapshots/fixtures to expect srcset and sizes in rendered <img> output.
Analytics Error Handling
packages/sdk/src/modules/analytics/mutations/use-record-activity.ts
Wrapped outbound Plausible analytics fetch call in a try/catch to swallow network/request failures instead of propagating errors.

Sequence Diagram(s)

(omitted)

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Suggested labels

patch

Poem

🐇 I nibble bytes and stitch a thread,

Srcsets sprout where images spread,
I hush empty drafts with care,
Silent pings fall through the air,
Hoppity-hop — the renderer's fed.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'LCP image src set' is concise and specifically related to the main changes, which involve implementing responsive image srcset functionality with new buildSrcSet utilities and IMAGE_SIZES constants for responsive image rendering.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch lcpi

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.

coderabbitai[bot]

This comment was marked as resolved.

Copy link
Copy Markdown
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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/render-helper/src/methods/img.method.ts`:
- Around line 53-71: The code marks /u/ and /<w>x<h>/ as "already proxied" but
still passes the full proxy URL into buildSrcSet(src), causing buildSrcSet to
re-proxify the proxy URL; change the branch that handles shouldReplace &&
hasAlreadyProxied to pass the original/unwrapped image identifier to buildSrcSet
(use decodedSrc) except when the src truly is a /p/ entry; i.e., in the else-if
for hasAlreadyProxied, check if src startsWith `${base}/p/` then call
buildSrcSet(src) otherwise call buildSrcSet(decodedSrc) so proxifyImageSrc isn't
applied to an already-proxied wrapper and you avoid nested /p/ entries.

In `@packages/render-helper/src/methods/sanitize-html.method.ts`:
- Around line 21-25: The comment for img[srcset] is inaccurate; update the
comment above the srcset handling in sanitize-html.method.ts (the block that
checks tag === 'img' && name === 'srcset', uses decoded and computes candidates)
to state the actual behavior: user-supplied srcset is stripped/normalized and
will be rejected (return '') if any candidate does not start with http:// or
https:// — i.e., the code currently enforces an http(s) URL requirement for all
srcset candidates rather than only allowing renderer-generated values.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 85379d0d-2683-4dd3-8008-3a1bf7a7d9e0

📥 Commits

Reviewing files that changed from the base of the PR and between 3ddef2f and b9555f8.

📒 Files selected for processing (7)
  • packages/render-helper/src/consts/allowed-attributes.const.ts
  • packages/render-helper/src/markdown-2-html.spec.ts
  • packages/render-helper/src/methods/img.method.ts
  • packages/render-helper/src/methods/sanitize-html.method.ts
  • packages/render-helper/src/proxify-image-src.spec.ts
  • packages/render-helper/src/proxify-image-src.ts
  • packages/render-helper/src/test/data/legacy/2112524.json
✅ Files skipped from review due to trivial changes (2)
  • packages/render-helper/src/test/data/legacy/2112524.json
  • packages/render-helper/src/consts/allowed-attributes.const.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/render-helper/src/proxify-image-src.spec.ts

Comment thread packages/render-helper/src/methods/img.method.ts Outdated
Comment thread packages/render-helper/src/methods/sanitize-html.method.ts Outdated
Copy link
Copy Markdown
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.

♻️ Duplicate comments (1)
packages/render-helper/src/methods/img.method.ts (1)

84-91: ⚠️ Potential issue | 🟠 Major

createImageHTML() still builds srcset for non-/p/ proxied routes, causing nested proxy variants.

Line 84 unconditionally calls buildSrcSet(src). For ${base}/u/ and ${base}/<w>x<h>/ inputs, this re-proxifies proxy URLs and produces non-canonical /p/<b58(proxy-url)> entries. img() already avoids this; createImageHTML() should align.

Suggested patch
 export function createImageHTML(src: string, isLCP: boolean): string {
   const proxified = proxifyImageSrc(src);
   if (!proxified) return '';
 
-  const srcset = buildSrcSet(src);
+  const base = getProxyBase().replace(/\/+$/, "");
+  const isPRoute = src.startsWith(`${base}/p/`);
+  const isAvatarOrCoverRoute =
+    src.startsWith(`${base}/u/`) ||
+    new RegExp(`^${base.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}/\\d+x\\d+/`).test(src);
+  const srcset = isAvatarOrCoverRoute ? '' : buildSrcSet(isPRoute ? src : src);
   const loading = isLCP ? 'eager' : 'lazy';
   const fetch = isLCP ? 'fetchpriority="high"' : 'decoding="async"';
   const srcsetAttr = srcset ? `srcset="${srcset}" sizes="${IMAGE_SIZES}"` : '';
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/render-helper/src/methods/img.method.ts` around lines 84 - 91,
createImageHTML() currently always calls buildSrcSet(src), which causes
double-proxied entries when src is already a proxied URL (e.g., routes under
/p/, /u/, or <w>x<h>/). Modify createImageHTML to mirror img() behavior: detect
when the incoming src is already a proxied route and skip calling buildSrcSet
(or pass the original proxified flag) so you do not generate srcset entries that
re-proxify the proxy URL; call buildSrcSet only for canonical non-proxy sources.
Update logic around createImageHTML, buildSrcSet, and the src/proxified
variables to conditionally build srcset based on whether src is a proxy URL
(check the /p/ or other proxy patterns) and ensure srcsetAttr remains empty when
skipping srcset generation.
🧹 Nitpick comments (1)
packages/render-helper/src/methods/img.method.ts (1)

52-55: Normalize proxy base before route checks to avoid false negatives.

If getProxyBase() is configured with a trailing slash, these checks can miss already-proxied URLs (//p/, //u/, etc.). Normalize once before building route prefixes/regex.

Suggested patch
-  const base = getProxyBase();
+  const base = getProxyBase().replace(/\/+$/, "");
   const hasAlreadyProxied = src.startsWith(`${base}/p/`)
     || src.startsWith(`${base}/u/`)
     || new RegExp(`^${base.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}/\\d+x\\d+/`).test(src);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/render-helper/src/methods/img.method.ts` around lines 52 - 55,
Normalize the proxy base returned by getProxyBase() once (e.g., strip any
trailing slash) before using it to build the route prefixes and regex so checks
for already-proxied URLs aren't skipped when the base has a trailing slash;
update the logic that sets base and hasAlreadyProxied (referencing getProxyBase,
hasAlreadyProxied, src) to use the normalized base and then construct the
`${base}/p/`, `${base}/u/` prefixes and the escaped-regex from that normalized
value.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@packages/render-helper/src/methods/img.method.ts`:
- Around line 84-91: createImageHTML() currently always calls buildSrcSet(src),
which causes double-proxied entries when src is already a proxied URL (e.g.,
routes under /p/, /u/, or <w>x<h>/). Modify createImageHTML to mirror img()
behavior: detect when the incoming src is already a proxied route and skip
calling buildSrcSet (or pass the original proxified flag) so you do not generate
srcset entries that re-proxify the proxy URL; call buildSrcSet only for
canonical non-proxy sources. Update logic around createImageHTML, buildSrcSet,
and the src/proxified variables to conditionally build srcset based on whether
src is a proxy URL (check the /p/ or other proxy patterns) and ensure srcsetAttr
remains empty when skipping srcset generation.

---

Nitpick comments:
In `@packages/render-helper/src/methods/img.method.ts`:
- Around line 52-55: Normalize the proxy base returned by getProxyBase() once
(e.g., strip any trailing slash) before using it to build the route prefixes and
regex so checks for already-proxied URLs aren't skipped when the base has a
trailing slash; update the logic that sets base and hasAlreadyProxied
(referencing getProxyBase, hasAlreadyProxied, src) to use the normalized base
and then construct the `${base}/p/`, `${base}/u/` prefixes and the escaped-regex
from that normalized value.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: bd0d9b77-904a-4923-b449-ca6754b71e6d

📥 Commits

Reviewing files that changed from the base of the PR and between b9555f8 and 55b89d8.

📒 Files selected for processing (3)
  • packages/render-helper/src/markdown-2-html.spec.ts
  • packages/render-helper/src/methods/img.method.ts
  • packages/render-helper/src/methods/sanitize-html.method.ts
✅ Files skipped from review due to trivial changes (1)
  • packages/render-helper/src/methods/sanitize-html.method.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/render-helper/src/markdown-2-html.spec.ts

Copy link
Copy Markdown
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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/render-helper/src/methods/img.method.ts`:
- Around line 84-87: The isAlreadyProxied check in img.method.ts uses
getProxyBase() without normalizing trailing slashes, causing false negatives
when setProxyBase() was configured with a trailing '/'; update the logic around
getProxyBase(), isAlreadyProxied and buildSrcSet so you first normalize the
proxy base (trim trailing slashes, e.g., normalizeBase = base.replace(/\/+$/,
'') or call the same normalization used in img()), then use that normalizedBase
in the startsWith(`${normalizedBase}/u/`) check and in the RegExp construction
for the dimension-prefixed path so already-proxied URLs are reliably detected.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 03877926-7965-4d3f-86c1-09bdb8eeea75

📥 Commits

Reviewing files that changed from the base of the PR and between 55b89d8 and d7e1178.

📒 Files selected for processing (2)
  • packages/render-helper/src/markdown-2-html.spec.ts
  • packages/render-helper/src/methods/img.method.ts
✅ Files skipped from review due to trivial changes (1)
  • packages/render-helper/src/markdown-2-html.spec.ts

Comment thread packages/render-helper/src/methods/img.method.ts Outdated
@feruzm feruzm added the patch Bug fixes and patches (1.0.0 → 1.0.1), add this only if any packages/ have patch changes in PR label Apr 13, 2026
@feruzm feruzm merged commit 344d5f7 into develop Apr 13, 2026
@feruzm feruzm deleted the lcpi branch April 13, 2026 05:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

patch Bug fixes and patches (1.0.0 → 1.0.1), add this only if any packages/ have patch changes in PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant