תמיכה ב-CSS ב-JS בכלי הפיתוח

Alex Rudenko
Alex Rudenko

במאמר הזה נפרט על התמיכה ב-CSS-in-JS בכלי הפיתוח שהגיעו החל מגרסה 85 של Chrome, ובאופן כללי על המשמעות של CSS-in-JS ואיך הוא שונה משירות CSS רגיל שנתמך על ידי כלי הפיתוח כבר הרבה זמן.

מה זה CSS-in-JS?

ההגדרה של CSS-in-JS לא מספיק ברורה. במובן הרחב, זו גישה לניהול קוד CSS באמצעות JavaScript. לדוגמה, יכול להיות שתוכן ה-CSS מוגדר באמצעות JavaScript ושהפלט הסופי של ה-CSS נוצר בזמן אמת על ידי האפליקציה.

בהקשר של כלי פיתוח, המשמעות של CSS-in-JS היא שתוכן ה-CSS מוחדר לדף באמצעות ממשקי CSSOM API. שירות CSS רגיל מועבר באמצעות רכיבי <style> או <link>, ויש לו מקור סטטי (למשל, צומת DOM או משאב רשת). לעומת זאת, ל-CSS-in-JS אין בדרך כלל מקור סטטי. מקרה מיוחד במקרה זה הוא שניתן לעדכן את התוכן של רכיב <style> באמצעות CSSOM API, וכתוצאה מכך המקור לא מסונכרן עם גיליון הסגנונות של ה-CSS בפועל.

אם אתם משתמשים בספריית CSS-in-JS (למשל, styled-component , Emotion , JSS), הספרייה עשויה להחדיר סגנונות באמצעות ממשקי API של CSSOM בחלק התחתון, בהתאם למצב הפיתוח ולדפדפן.

בואו נעיף מעט בכמה דוגמאות לאופן שבו מוסיפים גיליון סגנונות באמצעות CSSOM API בדומה לפעולות של ספריות CSS-in-JS.

// Insert new rule to an existing CSS stylesheet
const element = document.querySelector('style');
const stylesheet = element.sheet;
stylesheet.replaceSync('.some { color: blue; }');
stylesheet.insertRule('.some { color: green; }');

ניתן גם ליצור גיליון סגנונות חדש לחלוטין:

// Create a completely new stylesheet
const stylesheet = new CSSStyleSheet();
stylesheet.replaceSync('.some { color: blue; }');
stylesheet.insertRule('.some { color: green; }');

// Apply constructed stylesheet to the document
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];

תמיכה בשירות CSS בכלי פיתוח

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

עד לשנה שעברה, התמיכה בכללי CSS ששונו באמצעות ממשקי CSSOM API הייתה מוגבלת למדי: אפשרות לראות רק את הכללים שהוחלו, אבל לא הייתה אפשרות לערוך אותם. המטרה העיקרית של החברה בשנה שעברה הייתה לאפשר עריכה של כללי CSS-in-JS באמצעות החלונית Styles. לפעמים אנחנו קוראים גם לסגנונות CSS-in-JS 'מורכבים' כדי לציין שהם נבנו באמצעות ממשקי API לאינטרנט.

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

מנגנון לעריכת סגנון בכלי הפיתוח

מנגנון לעריכת סגנון בכלי הפיתוח

כשבוחרים רכיב בכלי הפיתוח, מוצגת החלונית Styles (סגנונות). החלונית Styles מפיקה פקודת CDP בשם CSS.getMatchedStylesForNode כדי לקבל כללי CSS שחלים על הרכיב. CDP הוא ראשי תיבות של Chrome DevTools Protocol (פרוטוקול כלי הפיתוח ל-Chrome). זהו API שמאפשר לחזית של כלי הפיתוח לקבל מידע נוסף על הדף שנבדק.

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

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

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

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

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

זו הסיבה לכך שהעריכה של CSS-in-JS ב-DevTools לא הצליחה לעשות את זה: ל-CSS-in-JS אין מקור בפועל מאוחסן במקום כלשהו וכללי ה-CSS נמצאים בזיכרון של הדפדפן במבני הנתונים של CSSOM.

איך הוספנו תמיכה ב-CSS-in-JS

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

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

String InspectorStyleSheet::CollectStyleSheetRules() {
  StringBuilder builder;
  for (unsigned i = 0; i < page_style_sheet_->length(); i++) {
    builder.Append(page_style_sheet_->item(i)->cssText());
    builder.Append('\n');
  }
  return builder.ToString();
}

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

void InspectorStyleSheet::UpdateText() {
  String text;
  bool success = InspectorStyleSheetText(&text);
  if (!success)
    success = InlineStyleSheetText(&text);
  if (!success)
    success = ResourceStyleSheetText(&text);
  if (!success)
    success = CSSOMStyleSheetText(&text);
  if (success)
    InnerSetText(text, false);
}

בקטע הקוד הזה, אנחנו רואים CSSOMStyleSheetText שקוראת ל-CollectStyleSheetRules באופן פנימי. המערכת מפעילה את CSSOMStyleSheetText אם גיליון הסגנון אינו מוטבע או שהוא גיליון סגנונות של משאב. בעיקרון, שני קטעי הקוד האלו כבר מאפשרים עריכה בסיסית של גיליונות הסגנון שנוצרו באמצעות ה-constructor new CSSStyleSheet().

מקרה מיוחד הוא גיליונות הסגנון שמשויכים לתג <style> שנערכו בהם שינויים באמצעות CSSOM API. במקרה כזה, גיליון הסגנון מכיל את טקסט המקור וכללים נוספים שלא קיימים במקור. כדי לטפל במקרה הזה, אנחנו מציגים שיטה למיזוג הכללים הנוספים האלה לטקסט המקור. במקרה הזה, הסדר חשוב כי אפשר להוסיף כללי CSS באמצע טקסט המקור המקורי. לדוגמה, נניח שהרכיב <style> המקורי הכיל את הטקסט הבא:

/* comment */
.rule1 {}
.rule3 {}

לאחר מכן הדף הוסיף כמה כללים חדשים באמצעות ה-JS API, והפיק את סדר הכללים הבא: .rule0 , .rule1 , .rule2 , .rule3 , .rule4? טקסט המקור שמתקבל לאחר פעולת המיזוג אמור להיות:

.rule0 {}
/* comment */
.rule1 {}
.rule2 {}
.rule3 {}
.rule4 {}

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

היבט נוסף המיוחד לגיליונות סגנונות של CSS-in-JS הוא שהדף יכול לשנות אותם בכל עת. אם כללי ה-CSSOM בפועל לא מסונכרנים עם גרסת הטקסט, העריכה לא תפעל. לשם כך השקנו probe שנקרא, שמאפשר לדפדפן להודיע לחלק העורפי של כלי הפיתוח על שינוי של גיליון סגנונות. לאחר מכן, גיליונות של סגנונות שעברו שינוי מסונכרנים במהלך הקריאה הבאה ל-CSS.getpersonalizedStylesForNode.

כבר ניתן לבצע עריכה ב-CSS-in-JS, ולאחר מכן לשפר את ממשק המשתמש כדי לציין אם גיליון סגנונות נבנה. הוספנו מאפיין חדש בשם isConstructed ל-CSS.CSSStyleSheetHeader של CDP, שבו נעשה שימוש בממשק הקצה כדי להציג באופן תקין את המקור של כלל CSS:

גיליון סגנונות שניתן לבנייה

מסקנות

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

לקבלת רקע נוסף, אפשר לעיין בהצעה שלנו לעיצוב או בבאג למעקב ב-Chromium, שמפנה לכל התיקונים הקשורים.

הורדת הערוצים של התצוגה המקדימה

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

יצירת קשר עם הצוות של כלי הפיתוח ל-Chrome

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

  • אפשר לשלוח לנו הצעה או משוב דרך crbug.com.
  • כדי לדווח על בעיה בכלי הפיתוח, לוחצים על אפשרויות נוספות   עוד   > עזרה > דיווח על בעיות בכלי הפיתוח בכלי הפיתוח.
  • שליחת ציוץ אל @ChromeDevTools.
  • נשמח לשמוע מה חדש בסרטונים ב-YouTube של כלי הפיתוח או בסרטונים ב-YouTube שקשורים לכלי פיתוח.