게시일: 2026년 5월 19일
웹은 시작된 정적 문서 중심의 매체에서 오래전에 벗어났습니다. 현대적이고 풍부한 웹 앱은 통신, 구매, 리치 콘텐츠 소비, 복잡한 삶 관리 등 다양한 이유로 모든 사람이 사용합니다.
HTML은 모든 발전에도 불구하고 콘텐츠가 준비되거나 사용자가 콘텐츠를 소비하는 시점과 관계없이 위에서 아래로 순서대로 제공됩니다. CSS를 사용하면 콘텐츠 순서를 변경할 수 있지만 접근성 측면에서 상당한 부작용이 발생할 수 있습니다. JavaScript를 사용하면 다양한 API를 통해 DOM을 조작하여 어느 정도 이 문제를 해결할 수 있지만, HTML에 연결하려면 장황한 구문이나 DOM 트리 구성이 필요한 경우가 많습니다.
웹은 클라이언트-서버 특성상 성능이 매우 중요하지만 HTML의 순서대로 제공되는 특성을 우회하기 위해 최적의 선택이 아닌 경우가 많아 성능이 저하됩니다. 여기에는 전체 페이지가 준비될 때까지 기다리거나 비동기식으로 구성요소를 제공하기 위해 무거운 프레임워크를 사용하는 것이 포함됩니다. JavaScript 프레임워크의 인기는 웹 개발자가 웹의 기원인 엄격한 문서 정신 모델보다 구성요소 기반 모델을 선호한다는 것을 보여줍니다.
Chrome팀은 이 문제를 고려해 왔으며 선언적 부분 업데이트라는 이름으로 웹 플랫폼에 새로운 기능을 개발해 왔습니다.
두 가지 새로운 API 세트를 사용하면 HTML 문서 자체에서 순서가 뒤섞이거나 새로운 JavaScript API를 사용하여 기존 문서에 HTML을 동적으로 삽입하는 더 쉬운 방법을 통해 HTML을 덜 선형적인 방식으로 더 쉽게 제공할 수 있습니다. Chrome 148부터 chrome://flags/#enable-experimental-web-platform-features 플래그를 사용하여 개발자 테스트를 진행할 수 있습니다. 폴리필을 사용하면 아직 지원하지 않는 브라우저에서도 이러한 새로운 API를 바로 사용할 수 있습니다.
웹 플랫폼에 추가된 이러한 기능은 다른 브라우저 공급업체 및 표준화 경로의 긍정적인 의견을 바탕으로 표준화되고 있습니다. 관련 표준은 이러한 새로운 API를 포함하도록 업데이트되고 있습니다.
순서가 뒤섞인 스트리밍
첫 번째 변경사항은 새로운 순서가 뒤섞인 스트리밍 API이며, <template> HTML 요소와 처리 명령어 자리표시자를 사용합니다. 예를 들면 다음과 같습니다.
<div>
<?marker name="placeholder">
</div>
...
<template for="placeholder">
Here is some <em>HTML content</em>!
</template>
처리 명령어는 XML에 오랫동안 존재했지만 HTML에서는 주석으로 처리되어 무시되었습니다. 이 새로운 API는 이를 변경하고 처리 명령어를 HTML에 도입합니다. 브라우저가 <?marker name="placeholder"> 처리 명령어를 확인하면 이전과 마찬가지로 바로 아무것도 실행하지 않지만 나중에 참조할 수 있습니다.
<template> 요소는 name 속성으로 해당하는 처리 명령어를 조회하고 콘텐츠를 바꿉니다. 이 경우 파싱된 후 DOM은 다음과 같이 됩니다.
<div>
Here is some <em>HTML content</em>!
</div>
대체용 <?marker> 속성 외에도 템플릿이 처리되기 전에 임시 자리표시자 콘텐츠를 표시할 수 있는 <?start> 및 <?end> 범위 마커도 있습니다.
<div>
<?start name="another-placeholder">
Loading…
<?end>
</div>
...
<template for="another-placeholder">
Here is some <em>HTML content</em>!
</template>
이 경우 <template>이 표시될 때까지 Loading…이 표시된 후 새 콘텐츠로 바뀝니다.
템플릿에 처리 명령어를 포함하여 여러 업데이트를 허용할 수도 있습니다.
<ul id="results">
<?start name="results">
Loading…
<?end>
</ul>
...
<template for="results">
<li>Result One</li>
<?marker name="results">
</template>
...
<template for="results">
<li>Result Two</li>
<?marker name="results">
</template>
...
이렇게 하면 파싱된 후 다음과 같은 HTML이 생성됩니다.
<ul id="results">
<li>Result One</li>
<li>Result Two</li>
<?marker name="results">
</ul>
나중에 문서에 <template for="results">가 추가되는 경우를 대비하여 마지막에 최종 처리 명령어가 있습니다.
데모
이 동영상에서는 스트리밍 HTML을 사용하여 기본 사진 앨범 애플리케이션을 구현합니다.
상태와 사진 모두 초기 레이아웃 후 HTML로 스트리밍됩니다.
사용 사례
스트리밍 HTML과 결합된 이 순서가 뒤섞인 패치 HTML에는 다음과 같은 다양한 사용 사례가 있습니다.
- 아일랜드 아키텍처. Astro와 같은 프레임워크에서 널리 사용되는 일반적인 패턴은 구성요소가 정적 HTML 위에 독립적으로 하이드레이션되는 아일랜드 아키텍처입니다.
<template for>API를 사용하면 정적 콘텐츠를 HTML에서 직접 유사한 방식으로 처리할 수 있습니다. JavaScript 프레임워크는 이를 사용하여 더 상호작용적인 아일랜드를 만들거나 구성요소를 처리할 수도 있습니다. - 준비된 콘텐츠 제공. 이 아일랜드 아키텍처 덕분에 콘텐츠는 추가 처리가 필요한 콘텐츠(예: 데이터베이스 조회)를 위해 보류되는 대신 준비될 때 스트리밍될 수 있습니다. 많은 플랫폼에서 HTML 스트리밍을 허용하지만 HTML의 순서대로 제공되는 특성으로 인해 콘텐츠가 보류되거나 복잡한 JavaScript DOM 조작을 사용하는 경우가 많습니다. 이제 기다리는 동안 정적 콘텐츠를 제공한 다음 HTML 스트림의 끝에 더 비용이 많이 드는 콘텐츠를 연결할 수 있습니다.
- HTML은 페이지 로드 성능에 최적의 순서로 제공될 수 있습니다. 한 단계 더 나아가 준비된 경우에도 순서를 변경할 수 있습니다. 예를 들어 메가 메뉴는 페이지가 상호작용이 될 때까지 사용자가 볼 수 없는 많은 HTML을 포함하는 일반적인 탐색 기능입니다. 이 큰 HTML 청크는 나중에 HTML 문서에서 제공하여 초기 페이지 로드에 필요한 더 중요한 HTML의 우선순위를 지정할 수 있습니다. HTML을 사용하면 순서가 더 이상 장벽이 되지 않습니다.
이러한 사용 사례는 일부에 불과하며 개발자가 이 새로운 API를 어떻게 사용하는지 기대됩니다.
제한사항 및 미묘한 차이
API에는 다음과 같은 몇 가지 제한사항과 미묘한 차이가 있습니다.
<template for>는 보안상의 이유로 동일한 상위 요소 내에서만 처리 명령어를 업데이트할 수 있습니다.<body>요소에 직접<template for>를 추가하면<head>를 포함한 전체 문서에 액세스할 수 있습니다.<?end>처리 명령어는 선택사항이며 누락된 경우<?start>요소와 포함 요소의 끝 사이에 있는 콘텐츠가 대체됩니다.<template for>가 스트리밍을 시작한 후 처리 명령어를 이동하면 새 콘텐츠가 이전 위치로 계속 스트리밍되는 등 예기치 않은 결과가 발생할 수도 있습니다.- `
setHTML` 또는 `innerHTML`과 같은 메서드로 `<template for>`를 동적으로 삽입할 때 파싱되는 템플릿의 '상위'는 중간 문서 프래그먼트입니다. 즉, 이러한 메서드를 사용하여 HTML을 삽입해도 기존 DOM을 수정할 수 없으며 패치는 프래그먼트 내에서 '제자리'에서 발생합니다. 하지만streamHTMLUnsafe(곧 다룰 예정)와 같은 메서드를 사용하여 스트리밍할 때는 중간 프래그먼트가 없으므로 템플릿이 기존 콘텐츠를 대체할 수 있습니다.
향후 추가될 수 있는 기능
고려 중인 향후 추가될 수 있는 기능은 다음과 같습니다.
- 클라이언트 측 포함. 예를 들어
<template for="footer" patchsrc="/partials/footer.html">입니다. - 일괄 처리. 클라이언트 측 프래그먼트 포함을 확장하여 일괄 처리를 처리하여 여러 업데이트가 동시에 발생하도록 할 수도 있습니다.
- 변경되지 않는 콘텐츠 덮어쓰기 방지. 콘텐츠 수정 버전 번호 또는 버전 관리를 통해 이를 달성할 수 있습니다. 이렇게 하면 콘텐츠를 재설정하는 대신 경로 변경 또는 기타 업데이트 간에 상태를 유지할 수 있습니다.
- 패치하는 동안 삭제. 예를 들어
<template for=icon safe><svg id="from-untrusted-source">...</svg></template>입니다.
폴리필
Chrome팀은 다른 브라우저에 이 기능이 도입되기 전에도 사이트에서 이 새로운 기능을 바로 사용할 수 있도록 npm에서 사용할 수 있는 released a template-for-polyfill를 출시했습니다.
브라우저의 HTML 파서를 직접 업데이트할 수 없으므로 몇 가지 제한사항이 있지만 가장 일반적인 사용 사례는 다루고 있습니다. 사이트는 다른 브라우저에서도 계속 테스트해야 합니다.
새로운 HTML 삽입 및 스트리밍 메서드
모든 콘텐츠를 HTML로 제공할 수는 없습니다. 이 영역에서 Chrome이 수행하는 작업의 두 번째 부분은 JavaScript를 통해 콘텐츠를 더 쉽게 업데이트할 수 있도록 하는 것입니다.
JavaScript를 사용하여 기존 문서에 HTML을 동적으로 삽입하는 방법은 이미 여러 가지가 있습니다.
setHTMLsetHTMLUnsafeinnerHTML및outerHTML설정자createContextualFragmentinsertAdjacentHTML
하지만 개발자가 항상 고려하지 않을 수 있는 미묘한 차이와 차이점을 포함하여 모두 약간 다른 방식으로 작동합니다.
- 새 콘텐츠가 덮어쓰기되는지 아니면 추가되는지
- 예를 들어
<script>태그를 이스케이프하여 잠재적으로 위험한 HTML을 삭제하나요? - 그렇지 않은 경우
<script>를 실행해야 하나요? - TrustedTypes와 어떻게 작동하나요?
솔직히 말해 개발자 중 이러한 API를 보고 각 API에 대한 질문에 자신 있게 답할 수 있는 개발자는 거의 없습니다.
큰 제한사항은 HTML을 스트리밍할 수 있도록 호출된 경우 미리 알려진 완전한 HTML 세트에만 사용할 수 있다는 것입니다. 실제로 이는 HTML의 강점 중 하나가 콘텐츠를 바로 스트리밍할 수 있다는 점인데도 콘텐츠를 삽입하기 전에 전체 콘텐츠를 다운로드해야 한다는 의미입니다. 페이로드를 분할하거나 document.write와 같은 임시방편의 지원 중단된 메서드를 사용하여 제한된 방식으로 해결할 수 있지만 자체 문제가 발생합니다.
새로운 정적 및 스트리밍 API 세트
Chrome은 이를 정리하고 스트리밍 기능을 도입하는 기존 setHTML 및 setHTMLUnsafe에 대한 새로운 API 모음 및 확장 프로그램을 제안했습니다.
기존 HTML 전후에 콘텐츠를 삽입하는 메서드와 함께 설정하거나 대체하는 메서드가 있습니다. 각 메서드에는 스트림에 상응하는 메서드가 있습니다.
| 작업 | 정적 | 스트리밍 |
|---|---|---|
| 요소의 HTML 콘텐츠 설정 | setHTML(html, options); |
streamHTML(options); |
| 전체 요소를 이 HTML로 바꾸기 | replaceWithHTML(html, options); |
streamReplaceWithHTML(options); |
| 요소 앞에 HTML 추가 | beforeHTML(html, options); |
streamBeforeHTML(options); |
| 요소의 첫 번째 하위 요소로 HTML 추가 | prependHTML(html, options); |
streamPrependHTML(options); |
| 요소의 마지막 하위 요소로 HTML 추가 | appendHTML(html, options); |
streamAppendHTML(options); |
| 요소 뒤에 HTML 추가 | afterHTML(html, options); |
streamAfterHTML(options); |
곧 다룰 Unsafe 버전도 있습니다. 특히 Unsafe에 상응하는 메서드를 추가하면 많은 것처럼 보일 수 있지만 일관된 이름 지정 규칙을 사용하면 이전에 언급한 관련 없는 메서드에 비해 각 메서드의 기능을 더 명확하게 알 수 있습니다.
정적 버전은 선택적 옵션과 함께 새 HTML을 DOM 문자열 인수로 사용합니다.
const newHTML = "<p>This is a new paragraph</p>";
const contentElement = document.querySelector('#content-to-update');
contentElement.setHTML(newHTML);
스트리밍 버전은 Streams API와 같은 getWriter()와 함께 작동합니다.
const contentElement = document.querySelector('#content-to-update');
const writer = contentElement.streamHTMLUnsafe().getWriter();
// Example stream of updating content
while (true) {
await writer.write(`<p>${++i}</p>`);
await new Promise((resolve) => setTimeout(resolve, 1000));
}
writer.close();
또는 가져오기 응답에서 파이프 체인을 사용합니다.
const contentElement = document.querySelector('#content-to-update');
const response = await fetch('/api/content.html');
response.body
.pipeThrough(new TextDecoderStream())
.pipeTo(contentElement.streamHTMLUnsafe());
중간 TextDecoderStream() 단계 없이 직접 스트리밍할 수 있는 편의 메서드도 추가할 계획입니다.
options 인수를 사용하면 기본값인 default(기본 삭제 구성)로 설정되는 커스텀 sanitizer를 지정할 수 있습니다. 다음과 같이 사용됩니다.
const newHTML = "<p>This is a new paragraph</p>";
const contentElement = document.querySelector('#content-to-update');
// Only allows basic formatting
const basicFormattingSanitzer = new Sanitizer({ elements: ["em", "i", "b", "strong"] });
contentElement.setHTML(newHTML, {sanitizer: basicFormattingSanitzer});
'안전하지 않은' 메서드
각 API의 '안전하지 않은' 버전도 있습니다.
| 작업 | 정적 | 스트리밍 |
|---|---|---|
| 요소의 HTML 콘텐츠 설정 | setHTMLUnsafe(html,options); |
streamHTMLUnsafe(options); |
| 전체 요소를 이 HTML로 바꾸기 | replaceWithHTMLUnsafe(html, options); |
streamReplaceWithHTMLUnsafe(options); |
| 요소 앞에 HTML 추가 | beforeHTMLUnsafe(html, options); |
streamBeforeHTMLUnsafe(options); |
| 요소의 첫 번째 하위 요소로 HTML 추가 | prependHTMLUnsafe(html, options); |
streamPrependHTMLUnsafe(options); |
| 요소의 마지막 하위 요소로 HTML 추가 | appendHTMLUnsafe(html, options); |
streamAppendHTMLUnsafe(options); |
| 요소 뒤에 HTML 추가 | afterHTMLUnsafe(html, options); |
streamAfterHTMLUnsafe(options); |
이러한 '안전하지 않은' 메서드는 기본적으로 삭제를 사용 중지하며 (원하는 경우 커스텀 삭제를 지정할 수 있음) 선택적 runScripts 옵션 (기본값은 false)으로 스크립트를 실행할 수도 있습니다.
setHTML과 마찬가지로 setHTMLUnsafe는 기존 메서드이지만 스크립트 실행과 함께 사용할 수 있도록 runScripts 옵션 매개변수가 추가되었습니다.
const newHTML = `<p>This is a new paragraph</p>
<script src=script.js></script>`;
const contentElement = document.querySelector('#content-to-update');
contentElement.setHTMLUnsafe(newHTML, {runScripts: true});
메서드의 '안전하지 않은'이라는 단어는 이러한 메서드를 사용해서는 안 된다는 것이 아니라 개발자에게 잠재적 위험과 스크립트를 삭제하거나 제한하는 방법을 상기시키기 위한 것입니다.
이것이 얼마나 '안전하지 않은지'는 입력의 신뢰도에 따라 다릅니다. Unsafe 정적 메서드는 모두 DOM 문자열 또는 TrustedHTML을 html 인수로 사용하며 삭제를 사용할 수도 있습니다. 하지만 runScript의 전체 의도는 스크립트를 허용하는 것이므로 기본적으로 삭제가 사용되지 않습니다.
사용 사례
이러한 새로운 API를 사용하면 개발자가 일관된 이름과 옵션으로 새로운 API를 추가하여 기존 페이지에 HTML을 더 쉽게 추가할 수 있습니다. 스트리밍 API는 플랫폼에서 모든 새 콘텐츠를 사용할 수 있을 때까지 기다릴 필요가 없다는 성능상의 이점을 제공합니다.
사용 사례는 다음과 같습니다.
- 단일 페이지 앱에서 대용량 콘텐츠 업데이트의 동적 스트리밍. 앞서 언급했듯이 현재 SPA의 큰 단점은 초기 HTML 로드의 스트리밍 특성을 활용할 수 없다는 것입니다. 이제는 가능합니다!
- HTML 바닥글과 같은 일반적인 콘텐츠 삽입. JavaScript API를 사용하면 전송된 모든 페이지에서 반복하는 대신 부분 파일을 가져와 페이지에 삽입하여 캐싱의 이점을 누릴 수 있습니다. 하지만 JavaScript에 의존하여 실행되므로 초기 로드에서 표시되지 않는 콘텐츠에만 사용해야 합니다.
다시 말하지만 이는 몇 가지 예일 뿐이며 여러분이 어떤 아이디어를 내놓을지 기대됩니다.
제한사항 및 미묘한 차이
이러한 새로운 API에는 다음과 같은 몇 가지 제한사항과 미묘한 차이도 있습니다.
- Trusted Types API와 스트리밍을 통합하려면 삭제를 모든 HTML 설정 작업에 삽입할 수 있는 새로운
createParserOptions메서드를 사용해야 합니다. 신뢰할 수 있는 유형 통합에 관한 자세한 내용은 설명자를 참고하세요. <template for>와 마찬가지로 스트리밍되는 요소를 이동하면 예기치 않은 결과나 스트림 오류가 발생할 수 있습니다.streamHTMLUnsafe는 기본 문서에 추가될 때<template for>명령어 처리, 스트림 끝까지defer스크립트 지연 등 여러 면에서 기본 파서와 더 유사하게 작동합니다.
폴리필
Chrome팀은 다른 브라우저에 이 기능이 도입되기 전에도 사이트에서 이 새로운 기능을 바로 사용할 수 있도록 npm에서 사용할 수 있는 출시했습니다html-setters-polyfill.
이 폴리필은 스트리밍하지 않고 완료되면 버퍼링하고 적용합니다. 기능보다는 API 형태의 폴리필에 가깝습니다.
또한 안전한 콘텐츠 설정은 setHTML 및 Safari에서 지원되지 않는 Sanitizer API에 따라 다릅니다.
이 두 가지를 함께 사용
이러한 API는 두 가지로 나뉘지만 이를 결합하면 진정한 힘을 발휘할 수 있습니다. 새로운 <template for> 요소를 HTML로 스트리밍하면 DOM에 대한 별도의 JavaScript 참조로 각 요소를 직접 타겟팅하지 않고도 콘텐츠의 여러 부분을 동적으로 업데이트할 수 있습니다.
기본 SPA 스타일 페이지 로드는 처리 명령어가 포함된 개요 페이지를 로드한 다음 각 새 페이지의 템플릿을 HTML 하단으로 스트리밍하여 이러한 처리 명령어에 삽입하는 방식으로 구현할 수 있습니다.
이러한 두 API에는 더 많은 잠재력과 사용 사례가 있으므로 (제한된!) 상상력에 제약을 받지 마세요. 부분 업데이트를 더 쉽게 관리할 수 있도록 하면 상용구 코드를 줄이고 업데이트를 더 쉽게 만들고 웹의 새로운 잠재력을 열 수 있습니다.