Share via


정적 서버 쪽 렌더링을 사용하여 Core Blazor JavaScript ASP.NET(정적 SSR)

이 문서에서는 정적 서버 쪽 렌더링(JS정적 SSR) 및 향상된 탐색을 사용하여 웹앱에서 Blazor JavaScript()를 로드하는 방법을 설명합니다.

일부 앱은 각 페이지와 관련된 초기화 작업을 수행하기 위해 의존 JS 합니다. 사용자가 전체 페이지를 다시 로드하지 않도록 하는 향상된 탐색 기능을 사용하는 Blazor경우 향상된 페이지 탐색이 발생할 때마다 페이지별 페이지가 JS 예상대로 다시 실행되지 않을 수 있습니다.

이 문제를 방지하려면 구성 요소에 적용된 레이아웃 파일 외부에 배치된 페이지별 <script> 요소를 사용하지 않는 것이 좋습니다. 대신 스크립트는 초기화 논리를 afterWebStartedJS 수행하고 이벤트 수신기(blazor.addEventListener("enhancedload", callback))를 사용하여 향상된 탐색으로 인한 페이지 업데이트를 수신 대기하도록 이니셜라이저를 등록해야 합니다.

다음 예제에서는 향상된 탐색을 사용하여 정적으로 렌더링된 페이지가 처음 로드되거나 업데이트될 때 실행되도록 코드를 구성하는 JS 한 가지 방법을 보여 줍니다.

다음 PageWithScript 구성 요소 예제는 정적 SSR 및 향상된 탐색을 사용하여 스크립트를 실행해야 하는 앱의 구성 요소입니다. 다음 구성 요소 예제에는 이 문서의 뒷부분에 있는 솔루션에 Razor 추가된 RCL(클래스 라이브러리)의 구성 요소가 포함되어 PageScript 있습니다.

Components/Pages/PageWithScript.razor:

@page "/page-with-script"
@using BlazorPageScript

<PageTitle>Enhanced Load Script Example</PageTitle>

<PageScript Src="./Components/Pages/PageWithScript.razor.js" />

Welcome to my page.

웹앱에서 Blazor 다음 데이터 정렬된 JS 파일을 추가합니다.

  • onLoad 는 스크립트가 페이지에 추가되면 호출됩니다.
  • onUpdate 는 향상된 업데이트 후 페이지에 스크립트가 여전히 존재할 때 호출됩니다.
  • onDispose 는 향상된 업데이트 후 페이지에서 스크립트가 제거될 때 호출됩니다.

Components/Pages/PageWithScript.razor.js:

export function onLoad() {
  console.log('Loaded');
}

export function onUpdate() {
  console.log('Updated');
}

export function onDispose() {
  console.log('Disposed');
}

Razor RCL(클래스 라이브러리)(예: RCL 이름BlazorPageScript)에서 다음 모듈을 추가합니다.

wwwroot/BlazorPageScript.lib.module.js:

const pageScriptInfoBySrc = new Map();

function registerPageScriptElement(src) {
  if (!src) {
    throw new Error('Must provide a non-empty value for the "src" attribute.');
  }

  let pageScriptInfo = pageScriptInfoBySrc.get(src);

  if (pageScriptInfo) {
    pageScriptInfo.referenceCount++;
  } else {
    pageScriptInfo = { referenceCount: 1, module: null };
    pageScriptInfoBySrc.set(src, pageScriptInfo);
    initializePageScriptModule(src, pageScriptInfo);
  }
}

function unregisterPageScriptElement(src) {
  if (!src) {
    return;
  }

  const pageScriptInfo = pageScriptInfoBySrc.get(src);
  
  if (!pageScriptInfo) {
    return;
  }

  pageScriptInfo.referenceCount--;
}

async function initializePageScriptModule(src, pageScriptInfo) {
  if (src.startsWith("./")) {
    src = new URL(src.substr(2), document.baseURI).toString();
  }

  const module = await import(src);

  if (pageScriptInfo.referenceCount <= 0) {
    return;
  }

  pageScriptInfo.module = module;
  module.onLoad?.();
  module.onUpdate?.();
}

function onEnhancedLoad() {
  for (const [src, { module, referenceCount }] of pageScriptInfoBySrc) {
    if (referenceCount <= 0) {
      module?.onDispose?.();
      pageScriptInfoBySrc.delete(src);
    }
  }

  for (const { module } of pageScriptInfoBySrc.values()) {
    module?.onUpdate?.();
  }
}

export function afterWebStarted(blazor) {
  customElements.define('page-script', class extends HTMLElement {
    static observedAttributes = ['src'];

    attributeChangedCallback(name, oldValue, newValue) {
      if (name !== 'src') {
        return;
      }

      this.src = newValue;
      unregisterPageScriptElement(oldValue);
      registerPageScriptElement(newValue);
    }

    disconnectedCallback() {
      unregisterPageScriptElement(this.src);
    }
  });

  blazor.addEventListener('enhancedload', onEnhancedLoad);
}

RCL에서 다음 PageScript 구성 요소를 추가합니다.

PageScript.razor:

<page-script src="@Src"></page-script>

@code {
    [Parameter]
    [EditorRequired]
    public string Src { get; set; } = default!;
}

PageScript 구성 요소는 일반적으로 페이지의 최상위 수준에서 작동합니다.

구성 요소를 앱의 레이아웃(예MainLayout.razor: 레이아웃을 사용하는 페이지 간에 공유PageScript)에 배치 PageScript 하는 경우 구성 요소는 전체 페이지 다시 로드 후 및 onUpdate 향상된 탐색을 포함하여 향상된 페이지 업데이트가 발생하는 경우에만 실행됩니다onLoad.

페이지 간에 동일한 모듈을 다시 사용하지만 onLoad 각 페이지에서 호출된 콜백과 onDispose 콜백을 변경하려면 다른 모듈로 인식되도록 스크립트 끝에 쿼리 문자열을 추가합니다. 앱은 구성 요소의 이름을 쿼리 문자열 값으로 사용하는 규칙을 채택할 수 있습니다. 다음 예제에서는 이 PageScript 구성 요소 참조가 구성 요소에 Counter 배치되므로 쿼리 문자열은 "counter"입니다. 이것은 단지 제안일 뿐이며 원하는 쿼리 문자열 체계를 사용할 수 있습니다.

<PageScript Src="./Components/Pages/PageWithScript.razor.js?counter" />

특정 DOM 요소의 변경 내용을 모니터링하려면 클라이언트에서 MutationObserverJS 패턴을 사용합니다. 자세한 내용은 ASP.NET Core Blazor JavaScript 상호 운용성(JS)을 참조하세요.

RCL을 사용하지 않는 예제 구현

이 문서에 설명된 접근 방식은 RCL(클래스 라이브러리)을 Blazor 사용하지 Razor 않고 웹앱에서 직접 구현할 수 있습니다. 예를 들어 ASP.NET Core Blazor Web App에서 TOTP 인증자 앱에 QR 코드 생성을 사용하도록 설정하세요.