نوسازی زیرساخت CSS در DevTools

به روز رسانی معماری DevTools: مدرن سازی زیرساخت CSS در DevTools

این پست بخشی از یک سری پست های وبلاگ است که تغییراتی را که ما در معماری DevTools ایجاد می کنیم و نحوه ساخت آن را توضیح می دهد. ما توضیح خواهیم داد که چگونه CSS از لحاظ تاریخی در DevTools کار می کرد و چگونه CSS خود را در DevTools در آماده سازی برای مهاجرت (در نهایت) به یک راه حل استاندارد وب برای بارگیری CSS در فایل های جاوا اسکریپت مدرن کرده ایم.

وضعیت قبلی CSS در DevTools

DevTools CSS را به دو روش مختلف پیاده‌سازی کرد: یکی برای فایل‌های CSS که در بخش قدیمی DevTools استفاده می‌شوند، دیگری برای اجزای وب مدرن که در DevTools استفاده می‌شوند.

پیاده سازی CSS در DevTools سال ها پیش تعریف شد و اکنون منسوخ شده است. DevTools به استفاده از الگوی module.json پایبند بوده و تلاش زیادی برای حذف این فایل ها انجام شده است. آخرین مسدود کننده برای حذف این فایل ها قسمت resources است که برای بارگذاری در فایل های CSS استفاده می شود.

ما می‌خواستیم برای بررسی راه‌حل‌های بالقوه مختلف که در نهایت می‌توانند به اسکریپت‌های ماژول CSS تبدیل شوند، وقت بگذاریم. هدف حذف بدهی فنی ناشی از سیستم قدیمی و همچنین تسهیل فرآیند انتقال به اسکریپت‌های ماژول CSS بود.

همه فایل‌های CSS که در DevTools بودند، به‌عنوان «میراث» در نظر گرفته می‌شدند زیرا با استفاده از فایل module.json بارگیری می‌شدند که در مرحله حذف است. همه فایل‌های CSS باید در فهرست resources در فایل module.json در همان فهرست فایل CSS قرار می‌گرفتند.

نمونه ای از فایل module.json باقی مانده:

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

این فایل‌های CSS سپس یک نقشه شی جهانی به نام Root.Runtime.cachedResources را به عنوان نقشه‌برداری از مسیری به محتویات خود پر می‌کنند. برای افزودن سبک به DevTools، باید 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‌ها کوچک‌سازی نشدند. اندازه فایل نسخه انتشار DevTools نیز توسط CSS تکراری که توسط چندین نمونه از یک مؤلفه وب معرفی شده بود، افزایش یافت.

هدف پروژه کارآموزی من یافتن راه حلی برای زیرساخت CSS بود که هم با زیرساخت قدیمی و هم با مؤلفه های وب جدید استفاده شده در DevTools کار می کند.

تحقیق در مورد راه حل های بالقوه

مشکل را می توان به دو بخش مختلف تقسیم کرد:

  • پی بردن به نحوه برخورد سیستم ساخت با فایل های CSS.
  • فهمیدن اینکه چگونه فایل‌های CSS توسط DevTools وارد و استفاده می‌شوند.

ما راه‌حل‌های بالقوه مختلفی را برای هر بخش بررسی کردیم که در زیر به آنها اشاره شده است.

وارد کردن فایل های CSS

هدف از وارد کردن و استفاده از CSS در فایل‌های TypeScript این بود که تا حد امکان به استانداردهای وب نزدیک شویم، یکپارچگی را در سراسر DevTools اعمال کنیم و از CSS تکراری در HTML خودداری کنیم . ما همچنین می‌خواستیم راه‌حلی را انتخاب کنیم که امکان انتقال تغییرات ما به استانداردهای جدید پلتفرم وب، مانند اسکریپت‌های ماژول CSS را فراهم کند.

به این دلایل عبارت @import و برچسب ها برای DevTools مناسب به نظر نمی رسید. آنها با واردات در بقیه ابزارهای DevTools یکسان نیستند و منجر به یک Flash Of Unstyled Content (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 اضافه کنیم (DevTools چند سال است که از Shadow DOM استفاده می کند) با استفاده از ویژگی adoptedStyleSheets آن.

گزینه های باندلر

ما به راهی برای تبدیل فایل های CSS به یک شی CSSStyleSheet نیاز داشتیم تا بتوانیم آن را به راحتی در فایل TypeScript دستکاری کنیم. ما هم Rollup و هم webpack را به عنوان باندلرهای بالقوه در نظر گرفتیم تا این تحول را برای ما انجام دهند. DevTools در حال حاضر از Rollup در ساخت تولید خود استفاده می‌کند، اما افزودن هر یک از باندلرها به ساخت تولید می‌تواند مشکلات عملکردی بالقوه‌ای در هنگام کار با سیستم ساخت فعلی ما داشته باشد. ادغام ما با سیستم ساخت GN Chromium، بسته‌بندی را دشوارتر می‌کند و بنابراین، بسته‌کننده‌ها تمایل دارند به خوبی با سیستم ساخت Chromium فعلی ادغام نشوند.

در عوض، ما گزینه استفاده از سیستم ساخت فعلی GN را برای انجام این تغییر برای ما بررسی کردیم.

زیرساخت جدید استفاده از CSS در DevTools

راه حل جدید شامل استفاده از 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 اعمال می‌کند و از هر گونه مشکل ناشی از نام‌های کلاس تکراری یا انتخابگرهای ID در فایل‌های CSS جلوگیری می‌کند.
  • انتقال آسان به استانداردهای وب آینده مانند اسکریپت های ماژول CSS و ادعاهای واردات

تنها اخطار به راه حل این بود که دستورهای import نیاز به وارد کردن فایل .css.js داشتند. برای اینکه GN در حین ساختن یک فایل CSS تولید کند، اسکریپت generate_css_js_files.js را نوشتیم. سیستم ساخت اکنون هر فایل CSS را پردازش می کند و آن را به یک فایل جاوا اسکریپت تبدیل می کند که به طور پیش فرض یک شی 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 برای اعمال اصلاحات و انتقال خودکار کدهای قدیمی استفاده کنیم. DevTools قبلاً از تعدادی قوانین سفارشی خاص برای پایگاه کد DevTools استفاده می کند. این مفید بود زیرا ESLint قبلاً کد را به یک درخت نحو انتزاعی (مخفف AST) تجزیه می‌کند و می‌توانستیم گره‌های فراخوانی خاصی را که فراخوانی برای ثبت CSS هستند پرس و جو کنیم.

بزرگترین مشکلی که هنگام نوشتن قوانین مهاجرت ESLint با آن مواجه شدیم، گرفتن موارد لبه بود. ما می‌خواستیم مطمئن شویم که تعادل مناسبی بین دانستن اینکه کدام لبه‌ها ارزش عکس‌برداری دارند و کدام‌ها باید به‌صورت دستی منتقل شوند را به دست آورده‌ایم. ما همچنین می‌خواستیم اطمینان حاصل کنیم که می‌توانیم به کاربر بگوییم که یک فایل .css.js وارد شده به‌طور خودکار توسط سیستم ساخت تولید نمی‌شود، زیرا این کار از خطای یافت نشدن فایل در زمان اجرا جلوگیری می‌کند.

یکی از معایب استفاده از قوانین ESLint برای مهاجرت این بود که نمی‌توانستیم فایل ساخت GN مورد نیاز در سیستم را تغییر دهیم. این تغییرات باید به صورت دستی توسط کاربر در هر دایرکتوری انجام می شد. در حالی که این کار به کار بیشتری نیاز داشت، این روش خوبی برای تأیید این بود که هر فایل .css.js که وارد می‌شود، در واقع توسط سیستم ساخت تولید می‌شود.

به طور کلی، استفاده از قوانین ESLint برای این انتقال بسیار مفید بود زیرا ما توانستیم به سرعت کدهای قدیمی را به زیرساخت جدید منتقل کنیم و داشتن AST به راحتی در دسترس بود به این معنی که می‌توانیم موارد متعدد لبه را نیز در این قانون مدیریت کنیم و با استفاده از ثابت‌کننده ESLint به‌طور خودکار آنها را به‌طور قابل‌اطمینانی برطرف کنیم. API .

بعدش چی؟

تا کنون، تمام اجزای وب در Chromium DevTools برای استفاده از زیرساخت جدید CSS به جای استفاده از سبک‌های درون خطی منتقل شده‌اند. بسیاری از استفاده های قدیمی registerRequiredCSS نیز برای استفاده از سیستم جدید منتقل شده اند. تنها چیزی که باقی می ماند این است که تا حد امکان فایل های module.json را حذف کنید و سپس این زیرساخت فعلی را برای پیاده سازی اسکریپت های ماژول CSS در آینده منتقل کنید!

کانال های پیش نمایش را دانلود کنید

استفاده از Chrome Canary ، Dev یا Beta را به عنوان مرورگر توسعه پیش‌فرض خود در نظر بگیرید. این کانال‌های پیش‌نمایش به شما امکان می‌دهند به جدیدترین ویژگی‌های DevTools دسترسی داشته باشید، APIهای پلت‌فرم وب پیشرفته را آزمایش کنید و قبل از اینکه کاربرانتان این کار را انجام دهند، مشکلات موجود در سایت خود را پیدا کنید!

تماس با تیم Chrome DevTools

از گزینه های زیر برای بحث در مورد ویژگی ها و تغییرات جدید در پست یا هر چیز دیگری مربوط به DevTools استفاده کنید.

  • پیشنهاد یا بازخورد خود را از طریق crbug.com برای ما ارسال کنید.
  • با استفاده از گزینه های بیشتر ، مشکل DevTools را گزارش کنیدبیشتر > راهنما > گزارش مشکلات DevTools در DevTools.
  • توییت در @ChromeDevTools .
  • نظرات خود را در مورد ویدیوهای YouTube DevTools یا نکات DevTools در YouTube ما بنویسید.