تحديث البنية الأساسية لصفحات الأنماط المتتالية (CSS) في "أدوات مطوري البرامج"

تحديث بنية أدوات مطوّري البرامج: تحديث البنية الأساسية لخدمة مقارنة الأسعار (CSS) في "أدوات مطوري البرامج"

تشكّل هذه المشاركة جزءًا من سلسلة من مشاركات المدوّنات التي تصف التغييرات التي نُجريها على بنية أدوات مطوّري البرامج وكيفية إنشائها. سنشرح طريقة عمل CSS في أدوات مطوّري البرامج في السابق وكيفية تحديث CSS في "أدوات مطوري البرامج" استعدادًا لعملية الانتقال (في النهاية) إلى حل عادي على الويب لتحميل CSS في ملفات JavaScript.

الوضع السابق لخدمة مقارنة الأسعار (CSS) في "أدوات مطوري البرامج"

استخدمت "أدوات مطوري البرامج" لغة CSS بطريقتَين مختلفتَين: إحداهما لملفات CSS المستخدَمة في الجزء القديم من "أدوات مطوري البرامج"، والأخرى لمكوّنات الويب الحديثة التي يتم استخدامها في "أدوات مطوري البرامج".

تم تحديد عملية تنفيذ CSS في "أدوات مطوري البرامج" منذ سنوات عديدة، وأصبحت الآن قديمة. لم تتوقّف أدوات مطوّري البرامج عن استخدام نمط module.json وقد تم بذل جهد كبير لإزالة هذه الملفات. أداة الحظر الأخيرة لإزالة هذه الملفات هي قسم resources الذي يُستخدم لتحميل المحتوى في ملفات CSS.

أردنا قضاء بعض الوقت في استكشاف الحلول المحتملة المختلفة التي يمكن أن تتحول في النهاية إلى نصوص وحدة CSS. كان الهدف من ذلك هو إزالة الديون التقنية الناتجة عن النظام القديم، وكذلك تسهيل عملية نقل البيانات إلى النصوص البرمجية لوحدات CSS.

تُعتبر أي ملفات CSS التي كانت في "أدوات مطوري البرامج" "قديمة" لأنه تم تحميلها باستخدام ملف module.json، وهو قيد الإزالة. كان يجب إدراج جميع ملفات CSS ضمن resources في ملف module.json في الدليل نفسه الذي يتضمّن ملف CSS.

مثال على ملف module.json متبقٍ:

{
  "resources": [
    "serviceWorkersView.css",
    "serviceWorkerUpdateCycleView.css"
  ]
}

بعد ذلك، تعمل ملفات CSS هذه على تعبئة خريطة عناصر عامة تُسمى Root.Runtime.cachedResources كعملية ربط من مسار إلى المحتوى. لإضافة أنماط إلى "أدوات مطوري البرامج"، عليك طلب registerRequiredCSS بالمسار الدقيق للملف الذي تريد تحميله.

مثال على مكالمة registerRequiredCSS:

constructor() {
  …
  this.registerRequiredCSS('ui/legacy/components/quick_open/filteredListWidget.css');
  …
}

سيؤدي هذا الإجراء إلى استرداد محتوى ملف CSS وإدراجه كعنصر <style> في الصفحة باستخدام الدالة appendStyle:.

دالة appendStyle تضيف CSS باستخدام عنصر نمط مضمّن:

const content = Root.Runtime.cachedResources.get(cssFile) || '';

if (!content) {
  console.error(cssFile + ' not preloaded. Check module.json');
}

const styleElement = document.createElement('style');
styleElement.textContent = content;
node.appendChild(styleElement);

عندما طرحنا مكونات ويب حديثة (باستخدام عناصر مخصّصة)، قرّرنا في البداية استخدام CSS من خلال علامات <style> المضمّنة في ملفات المكوّنات. قدم هذا تحدياته الخاصة:

  • عدم توفّر دعم لتسليط الضوء على البنية: لا غالبًا ما تكون المكوّنات الإضافية التي توفر تمييز بناء الجملة لـ CSS المضمّنة جيدة مثل تمييز البنية وميزات الإكمال التلقائي في CSS المكتوبة في ملفات .css.
  • زيادة مستوى الأداء: وكانت لغة CSS المضمّنة تعني أيضًا أنه يجب توفير بطاقتَين للحذف: بطاقتان لملفات CSS وأخرى لملفات CSS المضمّنة. كان هذا الإجراء زائدًا عن الأداء ويمكننا إزالته إذا كانت جميع ملفات CSS مكتوبة في ملفات CSS مستقلة.
  • تحدّي تصغير البيانات: تعذر تصغير CSS بسهولة، ولذلك لم يتم تصغير أي من CSS. تمت أيضًا زيادة حجم الملف الخاص بإصدار إصدار أدوات مطوّري البرامج من خلال نسخة CSS المكرّرة التي ظهرت في نُسخ متعددة من مكوّن الويب نفسه.

كان هدف مشروع التدريب الداخلي هو إيجاد حلّ للبنية الأساسية الخاصة بخدمة CSS والتي تتوافق مع كلّ من البنية الأساسية القديمة ومكوّنات الويب الجديدة المستخدَمة في "أدوات مطوري البرامج".

البحث عن الحلول المحتملة

يمكن تقسيم المشكلة إلى قسمين مختلفين:

  • التعرف على كيفية تعامل نظام الإصدار مع ملفات CSS.
  • معرفة كيفية استيراد ملفات CSS واستخدامها من خلال "أدوات مطوّري البرامج"

لقد نظرنا في الحلول المحتملة المختلفة لكل جزء، وتم توضيح هذه الحلول أدناه.

استيراد ملفات CSS

كان الهدف من استيراد لغة CSS واستخدامها في ملفات TypeScript هو الالتزام بأقرب معايير الويب قدر الإمكان، وتعزيز الاتّساق في جميع أدوات مطوّري البرامج وتجنُّب تكرار ملفات CSS في ترميز HTML. أردنا أيضًا أن نتمكّن من اختيار حل يسمح بنقل التغييرات إلى معايير جديدة للنظام الأساسي للويب، مثل النصوص البرمجية لوحدة CSS.

لهذه الأسباب، لا تبدو عبارات @import وعلامات مناسبة لـ "أدوات مطوري البرامج". ولن تكون هذه التنسيقات موحّدة مع عمليات الاستيراد في بقية أدوات مطوّري البرامج، وتؤدي إلى ظهور فلاش من المحتوى غير بأسلوبه (FOUC). سيكون من الصعب نقل البيانات إلى النصوص البرمجية لوحدة CSS، لأنّه يجب إضافة عمليات الاستيراد والتعامل معها بشكلٍ واضح بشكل مختلف عمّا يحدث مع علامات <link>.

const output = LitHtml.html`
<style> @import "css/styles.css"; </style>
<button> Hello world </button>`
const output = LitHtml.html`
<link rel="stylesheet" href="styles.css">
<button> Hello World </button>`

الحلول المحتملة باستخدام @import أو <link>.

بدلاً من ذلك، اخترنا العثور على طريقة لاستيراد ملف CSS كعنصر CSSStyleSheet حتى نتمكن من إضافته إلى Shadow Dom (تستخدم أدوات مطوّري البرامج Shadow DOM لبضعة سنوات الآن) باستخدام السمة adoptedStyleSheets.

خيارات الحِزم

احتجنا إلى طريقة لتحويل ملفات CSS إلى عنصر CSSStyleSheet حتى نتمكّن من معالجتها بسهولة في ملف TypeScript. اعتبرنا أنّ كلاً من البيانات المجمّعة وحزمة الويب كحزم محتمَلين تتيح لنا تنفيذ عملية التحويل هذه نيابةً عنا. تستخدم أدوات مطوّري البرامج أداة "دمج البيانات" حاليًا في إصدار الإنتاج، ولكن قد تؤدي إضافة أي حزمة إلى إصدار الإنتاج إلى حدوث مشاكل محتملة في الأداء عند العمل مع نظام الإصدار الحالي. يؤدي تكاملنا مع نظام إنشاء GN في Chromium إلى زيادة صعوبة التجميع، وبالتالي لا يميل الحزم إلى الدمج بشكل جيد مع نظام إصدار Chromium الحالي.

بدلاً من ذلك، استكشفنا خيار استخدام نظام إنشاء GN الحالي لإجراء هذا التحويل لنا بدلاً من ذلك.

البنية الأساسية الجديدة لاستخدام CSS في "أدوات مطوري البرامج"

يتضمّن الحلّ الجديد استخدام adoptedStyleSheets لإضافة أنماط إلى Shadow DOM معيّن أثناء استخدام نظام إصدار GN لإنشاء كائنات CSSStyleSheet التي يمكن استخدامها من خلال document أو ShadowRoot.

// CustomButton.ts

// Import the CSS style sheet contents from a JS file generated from CSS
import customButtonStyles from './customButton.css.js';
import otherStyles from './otherStyles.css.js';

export class CustomButton extends HTMLElement{
  …
  connectedCallback(): void {
    // Add the styles to the shadow root scope
    this.shadow.adoptedStyleSheets = [customButtonStyles, otherStyles];
  }
}

ولاستخدام adoptedStyleSheets مزايا متعددة، منها:

  • لا يزال الجهاز في مرحلة التطوير ليصبح معيارًا حديثًا على الويب
  • يتم منع تكرار CSS.
  • ينطبق الأنماط على Shadow DOM فقط، ويؤدي ذلك إلى تجنُّب أي مشاكل ناتجة عن أسماء الفئات المكرّرة أو أدوات اختيار أرقام التعريف في ملفات CSS.
  • سهولة النقل إلى معايير الويب المستقبلية مثل النصوص البرمجية لوحدات CSS وتأكيدات الاستيراد

كان التنبيه الوحيد للحل هو أنّ عبارات import تتطلب استيراد الملف .css.js. للسماح لـ GN بإنشاء ملف CSS أثناء الإنشاء، كتبنا النص البرمجي generate_css_js_files.js. يعالج نظام الإصدار الآن كل ملف CSS ويحوّله إلى ملف JavaScript يصدّر عنصر CSSStyleSheet تلقائيًا. وهذا أمر رائع حيث يمكننا استيراد ملف CSS واستخدامه بسهولة. علاوةً على ذلك، يمكننا الآن أيضًا تصغير حجم إصدار الإنتاج بسهولة، ما يوفر حجم الملف:

const styles = new CSSStyleSheet();
styles.replaceSync(
  // In production, we also minify our CSS styles
  /`${isDebug ? output : cleanCSS.minify(output).styles}
  /*# sourceURL=${fileName} */`/
);

export default styles;

تم إنشاء iconButton.css.js من النص البرمجي باستخدام مثال.

نقل الرمز القديم باستخدام قواعد ESLint

كان من الممكن نقل مكوّنات الويب يدويًا بسهولة، إلّا أنّ عملية نقل الاستخدامات القديمة من registerRequiredCSS كانت أكثر تعقيدًا. الوظيفتان الرئيسيتان اللتان سجّلتهما الأنماط القديمة هما registerRequiredCSS وcreateShadowRootWithCoreStyles. وبما أنّ خطوات نقل بيانات هذه الطلبات كانت آلية إلى حدٍ ما، يمكننا استخدام قواعد ESLint لتطبيق الإصلاحات ونقل الرمز القديم تلقائيًا. تستخدم "أدوات مطوري البرامج" حاليًا عددًا من القواعد المخصّصة الخاصة بقاعدة رموز أدوات مطوّري البرامج. كان ذلك مفيدًا لأنّ ESLint تحلّل الرمز البرمجي مسبقًا إلى شجرة بنية تجريدية(abbr. AST) ويمكننا الاستعلام عن عقد الاستدعاء المحدد الذي كان يمثل استدعاءات لتسجيل CSS.

كانت أكبر مشكلة واجهناها عند كتابة قواعد ESLint لنقل البيانات هي تسجيل الحالات الحدّية. أردنا التأكد من تحقيق التوازن الصحيح بين معرفة الحالات الهامشية التي تستحق تسجيلها وتلك التي يجب نقلها يدويًا. أردنا أيضًا التأكّد من إمكانية إبلاغ المستخدم بأنّ نظام التصميم لا ينشئ ملف .css.js تم استيراده تلقائيًا، لأنّ ذلك يمنع حدوث أي أخطاء في عدم العثور على الملف في وقت التشغيل.

من عيوب استخدام قواعد ESLint في عملية النقل هو عدم تمكّننا من تغيير ملف إصدار GN المطلوب في النظام. يجب أن ينفّذ المستخدم هذه التغييرات يدويًا في كل دليل. كان ذلك يتطلّب جهدًا أكبر، إلا أنّها كانت وسيلة جيدة للتأكّد من أنّ نظام التصميم هو مصدر كل ملف .css.js يتم استيراده.

بشكل عام، كان استخدام قواعد ESLint في عملية النقل هذه مفيدًا للغاية، لأنّنا تمكّنا من نقل الرمز القديم سريعًا إلى البنية الأساسية الجديدة، وكان توفُّر AST متاحًا بسهولة يعني أنّه يمكننا أيضًا التعامل مع حالات الحافة المتعددة ضمن القاعدة وحلّها تلقائيًا بشكل موثوق باستخدام واجهة برمجة التطبيقات لمركز إصلاح ESLint.

ما الخطوات التالية؟

حتى الآن، تم نقل جميع مكوّنات الويب في "أدوات مطوري البرامج في Chromium" لاستخدام البنية الأساسية الجديدة في CSS بدلاً من استخدام الأنماط المضمّنة. تم أيضًا نقل معظم الاستخدامات القديمة لنظام التشغيل registerRequiredCSS لاستخدام النظام الجديد. ما عليك سوى إزالة أكبر عدد ممكن من ملفات module.json ثم نقل هذه البنية الأساسية الحالية لتنفيذ النصوص البرمجية لوحدات CSS في المستقبل.

تنزيل قنوات المعاينة

يمكنك استخدام إصدار Canary أو إصدار مطوّري البرامج أو الإصدار التجريبي من Chrome كمتصفّح تلقائي للتطوير. تتيح لك قنوات المعاينة هذه الوصول إلى أحدث ميزات "أدوات مطوري البرامج" واختبار واجهات برمجة التطبيقات المتطورة للأنظمة الأساسية على الويب والعثور على المشاكل في موقعك الإلكتروني قبل المستخدمين.

التواصل مع فريق "أدوات مطوري البرامج في Chrome"

يُرجى استخدام الخيارات التالية لمناقشة الميزات والتغييرات الجديدة في المشاركة أو أي موضوع آخر ذي صلة بـ "أدوات مطوري البرامج".

  • يمكنك إرسال اقتراحات أو ملاحظات إلينا عبر crbug.com.
  • يمكنك الإبلاغ عن مشكلة في "أدوات مطوري البرامج" باستخدام خيارات إضافية   المزيد > مساعدة > الإبلاغ عن مشاكل في "أدوات مطوري البرامج" في "أدوات مطوري البرامج".
  • يمكنك نشر تغريدة على @ChromeDevTool.
  • يمكنك إضافة تعليقات على الميزات الجديدة في فيديوهات YouTube أو نصائح حول أدوات مطوّري البرامج في فيديوهات YouTube حول الميزات الجديدة.