Blazor 대화형 컴포넌트에서 프리렌더링 사용 시 발생하는 중복 데이터 로드, UI 깜빡임 및 상태 유지 문제를 해결합니다.
- GitHub 스타
- 5,942
- 파일
- 1
- 마지막 커밋
- 2026년 11월 11일
- 라이선스
- MIT
- 허용된 도구
- —
support-prerendering skill은 무엇을 하나요?
support-prerendering은(는) agent skill입니다. Blazor 대화형 컴포넌트에서 프리렌더링 사용 시 발생하는 중복 데이터 로드, UI 깜빡임 및 상태 유지 문제를 해결합니다.
skill의 SKILL.md에서 생성된 요약입니다.
support-prerendering skill 정보
Blazor 애플리케이션을 구축하는 개발자는 정적 HTML 프리렌더링에서 대화형 런타임으로 전환할 때 발생하는 일반적인 문제를 해결하기 위해 이 SKILL을 사용합니다. OnInitializedAsync에서의 데이터 중복 페칭, 핸드오프 과정 중의 UI 깜빡임, 컴포넌트가 브라우저 전용 API를 기대할 때 발생하는 null 참조 예외와 같은 구체적인 기술적 장애물을 다룹니다. 이 SKILL은 상태 유지 관리 방법을 제공하여 초기 서버 렌더링 중에 로드된 데이터를 대화형 세션이 시작될 때 사용할 수 있도록 보장합니다.
개발자가 데이터 동기화를 위해 [PersistentState] 특성이나 PersistentComponentState 서비스를 구현해야 할 때 에이전트가 이 SKILL을 로드해야 합니다. 또한 특정 컴포넌트의 프리렌더링을 비활성화하거나 [ExcludeFromInteractiveRouting] 특성을 사용하여 특정 페이지를 대화형 라우팅에서 제외하는 데에도 사용됩니다. RendererInfo.IsInteractive와 같은 도구를 활용하여 개발자는 정적 단계에서 오류를 방지하도록 코드 실행을 보호할 수 있습니다. 이 SKILL은 초기 프로젝트 설정이나 일반적인 컴포넌트 작성보다는 기존의 프리렌더링 버그를 수정하는 데 목적이 있습니다.
agent가 수행할 수 있는 작업
- 1중복 API 호출 방지상태 유지를 적용하여 프리렌더링 중에 로드된 데이터가 대화형 런타임 연결 시 다시 페칭되지 않도록 합니다.
- 2특정 컴포넌트의 프리렌더링 비활성화브라우저 API에 즉각적인 액세스가 필요한 컴포넌트의 프리렌더링을 끕니다.
- 3특정 페이지에서 HttpContext 액세스쿠키 또는 요청 헤더 액세스가 필요한 페이지에 대해 전체 페이지 새로고침을 강제합니다.
- 4대화형 전용 코드 보호런타임 체크를 사용하여 특정 로직이 대화형 런타임이 연결된 후에만 실행되도록 보장합니다.
skill의 SKILL.md를 기반으로 작성되었습니다. 모든 사용 사례는 해당 문서의 인용구와 대조 확인되었습니다.
support-prerendering skill 설치 방법
각 명령은 skill 폴더를 클라이언트의 skills 디렉터리에 복사합니다. 클라이언트를 재시작하거나 새 세션을 시작하여 로드하세요.플러그인에 support-prerendering skill 설치
/plugin marketplace add dotnet/skills /plugin install dotnet-blazor@dotnet-agent-skills
Claude Code에 support-prerendering skill 설치
~/.claude/skills/support-prerendering/SKILL.md
$ npx degit dotnet/skills/plugins/dotnet-blazor/skills/support-prerendering ~/.claude/skills/support-prerenderingClaude Code (project)에 support-prerendering skill 설치
.claude/skills/support-prerendering/SKILL.md
$ npx degit dotnet/skills/plugins/dotnet-blazor/skills/support-prerendering .claude/skills/support-prerenderingCodex에 support-prerendering skill 설치
~/.agents/skills/support-prerendering/SKILL.md
$ npx degit dotnet/skills/plugins/dotnet-blazor/skills/support-prerendering ~/.agents/skills/support-prerenderingGemini CLI에 support-prerendering skill 설치
~/.gemini/skills/support-prerendering/SKILL.md
$ npx degit dotnet/skills/plugins/dotnet-blazor/skills/support-prerendering ~/.gemini/skills/support-prerenderingClaude.ai에 support-prerendering skill 설치
npx degit dotnet/skills/plugins/dotnet-blazor/skills/support-prerendering support-prerendering && zip -r support-prerendering.zip support-prerendering # claude.ai → Customize → Skills → + → Create skill → Upload a skill → support-prerendering.zip
자동 검사
2026년 11월 15일에 실행됨전체 보고서 →자동 검사를 통과했습니다. 보안 감사는 아닙니다. 에이전트가 실행하기 전에 스크립트를 읽어 보세요. 검사 방식
- 소스 저장소 연결 및 접근 가능dotnet/skills/plugins/dotnet-blazor/skills/support-prerendering is public and reachablegithub.com/dotnet/skills/tree/HEAD/plugins/dotnet-blazor/ski ↗통과
- 오픈 소스 라이선스 (OSI)MITspdx.org/licenses/MIT.html ↗통과
- 최근 1년 내 커밋 또는 릴리스Last commit 2026-11-11github.com/dotnet/skills/commits ↗통과
- 스크립트에 다운로드 후 실행이나 자격 증명 탈취가 없음No scripts in the skill folder통과
- SKILL.md에 숨겨진 지침 없음No override phrases, safeguard switches, credential requests or hidden charactersgithub.com/dotnet/skills/blob/HEAD/plugins/dotnet-blazor/ski ↗통과
- 사전 허용 도구가 제한됨No pre-approved tools; the agent asks before using onegithub.com/dotnet/skills/blob/HEAD/plugins/dotnet-blazor/ski ↗통과
- SKILL.md가 Agent Skills 형식을 따름Valid name and description; says when to use it; 217 linesgithub.com/dotnet/skills/blob/HEAD/plugins/dotnet-blazor/ski ↗통과
SKILL.md
GitHub에서 보기Support Prerendering
How Prerendering Works
Prerendering is on by default for all interactive render modes. The server renders the component as static HTML and ships it to the browser immediately. Then the interactive runtime (Server/WebAssembly) loads and re-renders the component with full interactivity.
This means:
OnInitializedAsyncruns twice — once during prerender (static), once when the interactive runtime attaches.OnAfterRenderAsyncis NOT called during prerender — only after the interactive render.- Internal navigation between interactive pages (interactive routing) skips prerendering — prerendering only happens on full page loads.
Step 1 — Read the Project's AGENTS.md
Check the project's AGENTS.md for the Interactivity Mode and Interactivity Scope:
| Mode | Prerendering applies? |
|---|---|
| None (Static SSR) | No — there's no interactive handoff |
| Server | Yes |
| WebAssembly | Yes |
| Auto | Yes |
If the mode is None, this skill doesn't apply.
Persist State Across Prerender → Interactive
The most common prerendering problem: data loaded in OnInitializedAsync during prerender is thrown away and re-fetched when the interactive runtime attaches. This causes flicker and duplicate API/DB calls.
Recommended: [PersistentState] attribute
Annotate properties to automatically serialize during prerender and restore on interactive activation:
@page "/forecasts"
@rendermode InteractiveServer
<h1>Weather</h1>
@if (Forecasts is null)
{
<p>Loading...</p>
}
else
{
@foreach (var f in Forecasts)
{
<p>@f.Date: @f.TemperatureC°C</p>
}
}
@code {
[PersistentState]
public WeatherForecast[]? Forecasts { get; set; }
protected override async Task OnInitializedAsync()
{
Forecasts ??= await ForecastService.GetForecastsAsync();
}
}
The ??= pattern is critical — it means "only fetch if the property wasn't already restored from prerender state."
Multiple instances of the same component
When the same component type appears multiple times, use @key to disambiguate state:
@foreach (var item in items)
{
<ItemCard @key="item.Id" />
}
Advanced: PersistentComponentState service
For complex scenarios (dynamic keys, custom serialization), use the imperative API:
@inject PersistentComponentState ApplicationState
@code {
private List<Order>? orders;
protected override async Task OnInitializedAsync()
{
ApplicationState.RegisterOnPersisting(PersistOrders);
if (!ApplicationState.TryTakeFromJson<List<Order>>("orders", out var restored))
{
orders = await OrderService.GetOrdersAsync();
}
else
{
orders = restored;
}
}
private Task PersistOrders()
{
ApplicationState.PersistAsJson("orders", orders);
return Task.CompletedTask;
}
}
Disable Prerendering
Disable prerendering when a component depends on browser APIs immediately or when the prerender+interactive double render causes problems you can't solve with [PersistentState].
On a component definition
@rendermode @(new InteractiveServerRenderMode(prerender: false))
Replace InteractiveServerRenderMode with InteractiveWebAssemblyRenderMode or InteractiveAutoRenderMode as needed.
On a component instance
<MyChart @rendermode="new InteractiveServerRenderMode(prerender: false)" />
On the entire app
In App.razor:
<HeadOutlet @rendermode="new InteractiveServerRenderMode(prerender: false)" />
<Routes @rendermode="new InteractiveServerRenderMode(prerender: false)" />
Note: A parent's prerendering setting overrides children. If <Routes> disables prerendering, individual pages cannot re-enable it.
Exclude Pages from Interactive Routing
In a globally interactive app, some pages may need HttpContext (cookies, request headers, response status codes). These pages must render via static SSR, not inside the interactive runtime.
Use [ExcludeFromInteractiveRouting]:
@page "/privacy"
@attribute [ExcludeFromInteractiveRouting]
<h1>Privacy Policy</h1>
This forces a full page reload when navigating to this page, exiting interactive routing. The page renders as static SSR with full HttpContext access.
In App.razor, conditionally apply the render mode:
<!DOCTYPE html>
<html>
<head>
<HeadOutlet @rendermode="RenderModeForPage" />
</head>
<body>
<Routes @rendermode="RenderModeForPage" />
<script src="_framework/blazor.web.js"></script>
</body>
</html>
@code {
[CascadingParameter]
public HttpContext HttpContext { get; set; } = default!;
private IComponentRenderMode? RenderModeForPage =>
HttpContext.AcceptsInteractiveRouting() ? InteractiveServer : null;
}
Replace InteractiveServer with the app's configured render mode.
Detect Prerender vs Interactive at Runtime
Use RendererInfo to guard code that should only run interactively:
protected override async Task OnInitializedAsync()
{
if (RendererInfo.IsInteractive)
{
// Only runs during the interactive render, not during prerender
await StartSignalRConnection();
}
}
RendererInfo properties:
IsInteractive—falseduring prerender,trueafter interactive runtime attachesName—"Static"during prerender,"Server"or"WebAssembly"when interactive
Client Services Fail During Prerender
Components in the .Client project prerender on the server. Services registered only in the client Program.cs (e.g., IWebAssemblyHostEnvironment) won't be available during prerender.
Fix by one of:
- Register a matching service on the server — both
Program.csfiles provide the service - Make the service optional — use constructor injection with a nullable default:
public MyComponent(IMyService? svc = null) - Create a service abstraction — interface in
.Client, implementations in both projects - Disable prerendering for that component
Don'ts
- Don't call JS interop in
OnInitializedAsync— JS isn't available during prerender. UseOnAfterRenderAsync(firstRender). - Don't assume
OnInitializedAsyncruns once — it runs twice with prerendering. Always use[PersistentState]or??=guards. - Don't use
HttpContextin interactive components — it's only available during the static prerender, not during the interactive lifetime. Use[ExcludeFromInteractiveRouting]for pages that need it. - Don't disable prerendering as a first resort — it hurts perceived load time and SEO. Use
[PersistentState]to preserve state instead.
이 스킬의 파일
1support-prerendering skill 질문
Claude Code에 support-prerendering skill을 어떻게 설치하나요?
npx degit dotnet/skills/plugins/dotnet-blazor/skills/support-prerendering ~/.claude/skills/support-prerendering를 실행합니다. Claude Code는 ~/.claude/skills(모든 프로젝트) 또는 .claude/skills(한 프로젝트)에서 skills를 로드하며, 설명이 작업과 일치할 때 skill을 사용합니다.
support-prerendering skill을 사용할 수 있는 클라이언트는 무엇인가요?
Agent Skills 형식을 읽는 모든 클라이언트(Claude Code, Codex, Gemini CLI, claude.ai(ZIP으로 업로드))가 사용할 수 있습니다. skill 내 스크립트는 클라이언트가 코드 실행을 허용하는 경우에만 실행됩니다.
프리렌더링 중 데이터 중복 페칭을 방지하려면 어떻게 해야 하나요?
속성에 [PersistentState] 특성을 사용하거나 PersistentComponentState 서비스를 사용하여 프리렌더링 중에 데이터를 직렬화하고, 대화형 런타임이 연결될 때 이를 복구합니다.
특정 컴포넌트의 프리렌더링을 비활성화할 수 있나요?
네, @rendermode @(new InteractiveServerRenderMode(prerender: false))와 같이 prerender 파라미터를 false로 설정한 렌더 모드를 전달하여 비활성화할 수 있습니다.
OnInitializedAsync에서 JS interop이 실패하는 이유는 무엇인가요?
프리렌더 단계에서는 JavaScript를 사용할 수 없습니다. JS interop 호출은 OnAfterRenderAsync 메서드로 이동해야 합니다.