עדכונים חלקיים דקלרטיביים

תאריך פרסום: 19 במאי 2026

האינטרנט כבר מזמן לא מדיום סטטי שמבוסס על מסמכים, כמו שהוא היה בהתחלה. כולם משתמשים באפליקציות אינטרנט מודרניות ועשירות מסיבות רבות, החל מתקשורת, רכישה וצריכת תוכן עשיר, ועד לניהול החיים המורכבים שלנו.

למרות כל השיפורים שנעשו ב-HTML, הוא עדיין מועבר לפי הסדר מלמעלה למטה, בלי להתחשב במועד שבו התוכן מוכן או במועד שבו המשתמש צורך אותו. שירות CSS מאפשר לשנות את סדר התוכן, אבל לעיתים קרובות יש לכך השפעות משמעותיות על הנגישות. ‫JavaScript מאפשרת לכם לשנות את ה-DOM באמצעות ממשקי API שונים כדי להשתחרר מהמגבלה הזו במידה מסוימת, אבל לעיתים קרובות נדרש תחביר מפורט או בנייה של עצי DOM כדי להתחבר ל-HTML.

הביצועים חשובים מאוד באינטרנט, בהתחשב באופי של הלקוח-שרת של המדיום, אבל לעיתים קרובות נעשות בחירות לא אופטימליות כדי לעקוף את האופי הזה של HTML, מה שמאט את הביצועים. הפעולות האלה כוללות המתנה עד שהדף כולו יהיה מוכן או שימוש במסגרת כבדה כדי להציג רכיבים באופן אסינכרוני. הפופולריות של מסגרות JavaScript מראה שמפתחי אתרים מעדיפים מודל מבוסס-רכיבים ולא את המודל המנטלי הנוקשה של מסמך שמקורו באינטרנט.

צוות Chrome בחן את הבעיה הזו ופיתח תוספות חדשות לפלטפורמת האינטרנט בשם Declarative Partial Updates (עדכונים חלקיים הצהרתיים).

שני סטים חדשים של ממשקי API מאפשרים להציג HTML בצורה פחות לינארית, בין אם מחוץ לסדר במסמך ה-HTML עצמו או באמצעות דרכים קלות יותר להוסיף HTML באופן דינמי למסמכים קיימים באמצעות ממשקי JavaScript API חדשים. התכונות האלה מוכנות לבדיקות של מפתחים החל מ-Chrome 148 באמצעות התכונה הניסיונית chrome://flags/#enable-experimental-web-platform-features. יש גם Polyfills שמאפשרים לכם להשתמש בממשקי ה-API החדשים האלה באופן מיידי, גם בדפדפנים שעדיין לא תומכים בהם.

התוספות האלה לפלטפורמת האינטרנט עוברות תהליך סטנדרטיזציה עם משוב חיובי מספקי דפדפנים אחרים ומגורמים שעוסקים בסטנדרטיזציה. אנחנו מעדכנים את התקנים הרלוונטיים כך שיכללו את ממשקי ה-API החדשים האלה.

סטרימינג לא לפי הסדר

השינוי הראשון הוא ממשקי API חדשים להזרמת נתונים לא לפי הסדר באמצעות רכיב ה-HTML ‏<template> ומשתני placeholder של הוראות עיבוד. לדוגמה:

<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> שמאפשרים להציג תוכן זמני של placeholder לפני שהתבנית עוברת עיבוד:

<div>
  <?start name="another-placeholder">
  Loading…
  <?end>
</div>

...

<template for="another-placeholder">
  Here is some <em>HTML content</em>!
</template>

במקרה כזה, Loading… מוצג עד שרואים את <template>, ואז הוא מוחלף בתוכן החדש.

אפשר גם לכלול הוראות עיבוד בתבניות כדי לאפשר כמה עדכונים:

<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 frameworks כדי ליצור איים אינטראקטיביים יותר או כדי לטפל ברכיבים.
  • העברת תוכן כשהוא מוכן. בזכות ארכיטקטורת האיים הזו, אפשר להזרים תוכן כשהוא מוכן במקום לעכב אותו בגלל תוכן שדורש עיבוד נוסף, למשל חיפוש במסד נתונים. הרבה פלטפורמות מאפשרות סטרימינג של HTML, אבל בגלל האופי של HTML, התוכן לרוב מושהה או שמתבצעות מניפולציות מורכבות ב-DOM של JavaScript. עכשיו אפשר להציג את התוכן הסטטי בזמן ההמתנה, ואז להוסיף את התוכן היקר יותר בסוף של זרם ה-HTML.
  • אפשר להציג HTML בסדר האופטימלי לביצועי טעינת הדף. אפשר גם לשנות את הסדר אחרי שהסרטון מוכן. לדוגמה, תפריטי מגה הם תכונת ניווט נפוצה שמכילה הרבה קוד HTML שהמשתמש לא יראה עד שהדף יהפוך לאינטראקטיבי. אפשר להעביר את החלק הגדול הזה של ה-HTML לחלק מאוחר יותר במסמך ה-HTML, כדי לתת עדיפות ל-HTML חשוב יותר שנדרש לטעינת דף הראשונית. הזמנה לא מהווה יותר מחסום עם HTML.

אלה רק כמה תרחישים לדוגמה, ואנחנו נרגשים לראות איך מפתחים משתמשים ב-API החדש הזה.

הגבלות וניואנסים

יש כמה הגבלות וניואנסים שחשוב להכיר לגבי ה-API:

  • מטעמי אבטחה, <template for> יכול לעדכן הוראות עיבוד רק באותו רכיב אב. הוספה של <template for> ישירות לרכיב <body> נותנת לו גישה לכל המסמך (כולל <head>).
  • הוראת העיבוד <?end> היא אופציונלית, ואם היא לא מופיעה, התוכן שבין הרכיב <?start> לסוף הרכיב המכיל יוחלף.
  • העברת הוראות עיבוד אחרי שסטרימינג של <template for> התחיל יכולה גם לגרום לתוצאות לא צפויות, כשהתוכן החדש ממשיך להיות בסטרימינג למיקום הישן.
  • שימו לב: כשמכניסים <template for> באופן דינמי באמצעות שיטה כמו setHTML או innerHTML, ה "הורה" של התבנית בזמן הניתוח הוא קטע מסמך ביניים. המשמעות היא שאי אפשר להשתמש בשיטות האלה כדי להוסיף HTML ולשנות DOM קיים, והתיקון מתבצע 'במקום' בתוך הפרגמנט. עם זאת, כשמבצעים סטרימינג באמצעות שיטות כמו streamHTMLUnsafe (שנסביר עליהן בהמשך!), אין פרגמנט ביניים ולכן התבניות יכולות להחליף תוכן קיים.

תוספות פוטנציאליות בעתיד

הנה כמה תוספות פוטנציאליות שאנחנו שוקלים להוסיף בעתיד:

  • הוספות בצד הלקוח. לדוגמה, <template for="footer" patchsrc="/partials/footer.html">.
  • קיבוץ. בצד הלקוח, אפשר להרחיב את האפשרות של הכללת קטעים כדי לטפל באוסף של כמה עדכונים שמתבצעים בו-זמנית.
  • מניעת החלפה של תוכן שלא ישתנה. אפשר לעשות את זה באמצעות מספר תיקון תוכן או ניהול גרסאות. כך אפשר לשמור את המצב בין שינויים במסלול או עדכונים אחרים, במקום לאפס את התוכן.
  • ניקוי בזמן תיקון. לדוגמה, <template for=icon safe><svg id="from-untrusted-source">...</svg></template>.

פוליפיל

צוות Chrome פרסם template-for-polyfill שזמין ב-npm כדי לאפשר לאתרים להשתמש בפונקציונליות החדשה הזו באופן מיידי, עוד לפני שהיא תהיה זמינה בדפדפנים אחרים.

יש כמה מגבלות כי אי אפשר לעדכן ישירות את מנתחי ה-HTML של הדפדפן, אבל התרחישים הנפוצים ביותר מכוסים. עדיין צריך לבדוק את האתרים בדפדפנים אחרים.

שיטות חדשות להוספת HTML ולהעברה בסטרימינג

לא ניתן להעביר את כל התוכן בפורמט HTML. חלק נוסף בעבודה ש-Chrome מבצע בתחום הזה הוא להקל על עדכון התוכן באמצעות JavaScript.

כבר יש כמה דרכים להוסיף באופן דינמי HTML למסמך קיים באמצעות JavaScript:

  • setHTML
  • setHTMLUnsafe
  • innerHTML ו-outerHTML setters
  • createContextualFragment
  • insertAdjacentHTML

עם זאת, כל אחת מהן פועלת בצורה שונה, עם ניואנסים והבדלים שמפתחים לא תמיד לוקחים בחשבון:

  • האם התוכן החדש מחליף את התוכן הקיים או מתווסף אליו?
  • האם הם מבצעים סניטציה של קוד HTML שעלול להיות מסוכן על ידי ביטול התגים <script>, למשל?
  • אם לא, האם צריך להריץ את <script>?
  • איך הם עובדים עם TrustedTypes?

מעט מאוד מפתחים יכולים להסתכל על ממשקי ה-API האלה ולענות על השאלות האלה לגבי כל אחד מהם.

מגבלה משמעותית היא שאפשר להשתמש בהם רק עבור קבוצה מלאה של HTML שידועה מראש, כשהיו קריאות לאפשר סטרימינג של HTML. בפועל, זה אומר שצריך להוריד את כל התוכן לפני שמוסיפים אותו, כשנקודת החוזק של HTML היא היכולת להזרים תוכן באופן מיידי. אפשר לעקוף את הבעיה הזו במידה מוגבלת על ידי פיצול של מטען ייעודי (payload) או שימוש בשיטות לא רשמיות שהוצאו משימוש כמו document.write, אבל הן יוצרות בעיות משלהן.

קבוצה חדשה של ממשקי API סטטיים וממשקי API של סטרימינג

צוות Chrome הציע חבילה של ממשקי API חדשים ותוספים ל-setHTML ול-setHTMLUnsafe הקיימים, כדי לפתור את הבעיה הזו, וגם כדי להוסיף פונקציונליות של סטרימינג:

יש שיטות להגדיר או להחליף, וגם שיטות להוספת תוכן לפני או אחרי קוד 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 String, יחד עם אפשרויות אופציונליות:

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 מאפשר לציין sanitizer בהתאמה אישית, שברירת המחדל שלו היא default, כלומר הגדרת ברירת המחדל של אמצעי החיטוי. השימוש הוא כזה:

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 String או עם TrustedHTML בתור ארגומנטים של html, ומאפשרות גם להשתמש במסנני חיטוי. אבל עם runScript המטרה היא לאפשר סקריפטים, ולכן כברירת מחדל לא נעשה שימוש בחיטוי.

תרחישים לדוגמה

ממשקי ה-API החדשים האלה מאפשרים למפתחים להוסיף HTML לדפים קיימים בקלות רבה יותר, באמצעות הוספה של ממשקי API חדשים עם שמות ואפשרויות עקביים. ממשקי ה-API של הסטרימינג מאפשרים ליהנות מיתרונות הביצועים של לא לחכות עד שכל התוכן החדש יהיה זמין בפלטפורמה.

תרחישי שימוש לדוגמה:

  • סטרימינג דינמי של עדכוני תוכן גדולים באפליקציות בדף יחיד. כמו שציינו קודם, חיסרון גדול של SPAs נוכחיים הוא שהם לא יכולים ליהנות מהטבע של טעינות HTML ראשוניות – עד עכשיו!
  • הוספת תוכן נפוץ כמו כותרות תחתונות ב-HTML. השימוש ב-JavaScript API מאפשר לכם לשלוף חלקים ולהוסיף אותם לדף, וליהנות מהיתרונות של שמירה במטמון, במקום לחזור עליהם בכל דף שנשלח. עם זאת, בהתחשב בתלות ב-JavaScript להפעלה, צריך להשתמש בשיטה הזו רק לתוכן שלא יוצג בטעינה הראשונית.

שוב, אלה רק כמה דוגמאות, ואנחנו כבר לא יכולים לחכות לראות מה תצליחו ליצור!

הגבלות וניואנסים

בנוסף, יש כמה הגבלות וניואנסים שחשוב להכיר לגבי ממשקי ה-API החדשים:

  • כדי לשלב סטרימינג עם Trusted Types API, צריך להשתמש ב-method חדש createParserOptions שמאפשר להוסיף אמצעי לניקוי נתונים לכל פעולת הגדרת HTML. מידע נוסף על שילוב סוגים מהימנים
  • בדומה ל<template for>, הזזה של רכיבים שמוזרמים לתוך, יכולה ליצור השלכות לא צפויות או שגיאות בהזרמה.
  • streamHTMLUnsafe פועל בדומה לניתוח התחביר הראשי בהרבה מובנים, כולל עיבוד ההוראות של <template for> כשהן מתווספות למסמך הראשי, ודחיית הסקריפטים של defer עד לסוף הזרם.

פוליפיל

צוות Chrome פרסם html-setters-polyfill שזמין ב-npm כדי לאפשר לאתרים להשתמש בפונקציונליות החדשה הזו באופן מיידי, עוד לפני שהיא תהיה זמינה בדפדפנים אחרים.

שימו לב: הפוליפיל הזה לא מזרים נתונים, אלא מאגר אותם ומחיל אותם כשהוא מסתיים. הוא יותר פוליפיל לצורת ה-API מאשר לפונקציונליות.

בנוסף, הגדרת תוכן בטוח תלויה ב-setHTML וב-Sanitizer API שלא נתמך ב-Safari.

אפשר להשתמש בשניהם ביחד

אלה שני ממשקי API נפרדים, אבל העוצמה האמיתית שלהם מתגלה כשמשלבים ביניהם. באמצעות סטרימינג של רכיבי <template for> חדשים ל-HTML, אפשר לעדכן באופן דינמי חלקים שונים של התוכן בלי לטרגט כל אחד מהם ישירות באמצעות הפניות נפרדות של JavaScript ל-DOM.

אפשר להטמיע טעינת דף בסיסית בסגנון SPA על ידי טעינת דף מתאר עם הוראות עיבוד, ולאחר מכן להזרים את התבניות של כל דף חדש לחלק התחתון של ה-HTML כדי להוסיף אותן להוראות העיבוד האלה.

אין ספק שיש עוד פוטנציאל ומקרים לשימוש בשני ממשקי ה-API האלה, אז אל תתנו לדמיון (המוגבל!) שלנו לעצור אתכם. העדכונים החלקיים קלים יותר לניהול, כך שאתם יכולים לצמצם חלק מקוד ה-boilerplate, לבצע עדכונים בקלות רבה יותר ולפתוח אפשרויות חדשות לאתר שלכם.