Skip to content

fix: added adapter to fix the SSR Icon missing error - #527

Open
rastuhacode wants to merge 1 commit into
nuxt:mainfrom
rastuhacode:fix/ssr-icons-warnings-518
Open

fix: added adapter to fix the SSR Icon missing error#527
rastuhacode wants to merge 1 commit into
nuxt:mainfrom
rastuhacode:fix/ssr-icons-warnings-518

Conversation

@rastuhacode

@rastuhacode rastuhacode commented Aug 12, 2026

Copy link
Copy Markdown

🔗 Linked issue

Resolves #518.

📚 Description

After updating the nuxt/icon up from @2.3.1 the icons fail to render if app uses SSR. For ex:

 WARN  [Icon] failed to load icon lucide:sun 

Related issue describes the core regression correctly.

Solution

The simple priority logic to pick correcrt fetch was added to resolve both initial issue #514 (where regression appeared) and remove that regression.

Here's the logic behind the prioritization:

  1. Pick event.fetch if it is available as the most "context-rich": relative Nitro routes, preserving request’s headers and context, base URL, etc.
  2. Pick useRequestFetch().native if it is available. Used in browser (or future Nuxt 5) and keeping fix by fix: avoid relying on global fetch #514.
    Here's the regression, as Nuxt 4/Nitro 2 useRequestFetch() doesn't expose .native.
  3. Pick globalThis.$fetch.native as the Nuxt 4/Nitro 2 SSR compatibility path.
  4. Pick globalThis.fetch as the final safety net.

I also added fixture, expanded smoke and wrote regression tests.

@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 959073c1-5f13-4e11-bf8e-828e0c903601

📥 Commits

Reviewing files that changed from the base of the PR and between 33777b8 and 85e9d7b.

📒 Files selected for processing (5)
  • playgrounds/nuxt5/test.mjs
  • src/runtime/plugin.ts
  • test/fixtures/ssr-runtime/app.vue
  • test/fixtures/ssr-runtime/nuxt.config.ts
  • test/ssr.test.ts

📝 Walkthrough

Walkthrough

The runtime plugin now configures Iconify with a request-aware fetch chain and uses it for custom icon loading. A Nuxt SSR fixture renders the ph:acorn-bold icon with server bundling and disabled API fallback. SSR tests and Nuxt playground assertions verify HTTP success, rendered Iconify markup, embedded SVG data, and the absence of icon-loading errors.

Estimated code review effort: 3 (Moderate) | ~20 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the SSR icon-rendering fix, which matches the main code and test changes.
Description check ✅ Passed The description explains the SSR regression, fetch-selection fix, fixture, smoke coverage, and regression tests.
Linked Issues check ✅ Passed The changes address issue #518 by providing an SSR fetch fallback chain and verifying server-rendered SVG icons without loading errors.
Out of Scope Changes check ✅ Passed The fixture, smoke assertions, fetch logic, and SSR tests are directly related to the linked issue and PR objectives.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@pkg-pr-new

pkg-pr-new Bot commented Aug 12, 2026

Copy link
Copy Markdown
npm i https://pkg.pr.new/@nuxt/icon@527

commit: 85e9d7b

Comment thread src/runtime/plugin.ts
Comment on lines +14 to +23
_api.setFetch((input, init) => {
const event = tryUseNuxtApp()?.ssrContext?.event as { fetch?: typeof globalThis.fetch } | undefined
const nitroFetch = (globalThis as typeof globalThis & {
$fetch?: { native?: typeof globalThis.fetch }
}).$fetch?.native

// Prefer request-aware fetch, but Nitro 2's useRequestFetch() has no `.native`.
// Its global native fetch keeps deferred relative requests local without retaining an event.
return (event?.fetch || nativeFetch || nitroFetch || globalThis.fetch)(input, init)
})

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think this branch never actually runs, iconify does its fetching from a setTimeout so by the time this callback fires tryUseNuxtApp() returns undefined and it always ends up on globalThis.$fetch.native. What worked for me is grabbing the event at setup instead:

const event = import.meta.server ? useRequestEvent() : undefined

_api.setFetch(
  event?.fetch
  || requestFetch.native
  || globalThis.$fetch?.native
  || globalThis.fetch,
)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Hey! Thank you for a review!

I double checked and yes, you are correct that it is a dead branch. On the other hand I think your setup grab theoritically can create another issue.

As the _api.setFetch() writes to Iconify's module-level variable the scheduled processes might call wrong event.fetch:

let fetchModule

function setFetch(fetch) {
  fetchModule = fetch
}

Consider the case:

  1. Request A runs plugin setup and installs eventA.fetch. Iconify schedules A's icon request with setTimeout
  2. Request B runs plugin setup and installs eventB.fetch
  3. A's timer executes, but Iconify now calls eventB.fetch instead of correct eventA.fetch

While it would work in the most cases, it can forward wrong cookies, headers, middleware's context, etc.

I may be wrong though - I'm not proficient in nuxt codebases, so I would listen to your recommendations, but I thought that this should be mentioned before continuing.

If this is an issue though, I guess correct approach is just remove the event lookup and use native, as I haven't find approach how can we safely get event.fetch without changing Iconify's fetch module configuration.

Am I right to consider this an issue?

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.

SSR: _api.setFetch($fetch.native) disables icon loading entirely — useRequestFetch() returns Nitro's event.$fetch, which has no .native

2 participants