รีเฟรชสถาปัตยกรรมเครื่องมือสำหรับนักพัฒนาเว็บ: การปรับโครงสร้างพื้นฐาน CSS ให้ทันสมัยในเครื่องมือสำหรับนักพัฒนาเว็บ
โพสต์นี้เป็นส่วนหนึ่งของชุดบล็อกโพสต์ที่อธิบายการเปลี่ยนแปลงที่เราทำกับสถาปัตยกรรมของ DevTools และวิธีสร้าง เราจะอธิบายวิธีที่ผ่านมาของ CSS ในเครื่องมือสำหรับนักพัฒนาเว็บ รวมถึงวิธีที่เราปรับ CSS ในเครื่องมือสำหรับนักพัฒนาเว็บให้ทันสมัยเพื่อเตรียมพร้อมสำหรับการย้ายข้อมูลไปยังโซลูชันมาตรฐานเว็บสำหรับการโหลด CSS ในไฟล์ JavaScript (ในที่สุด)
สถานะก่อนหน้าของ CSS ในเครื่องมือสำหรับนักพัฒนาเว็บ
DevTools ใช้ CSS ใน 2 วิธีด้วยกัน วิธีแรกสำหรับไฟล์ CSS ที่ใช้ในส่วนเดิมของ DevTools และอีกวิธีสำหรับคอมโพเนนต์เว็บสมัยใหม่ที่ใช้ใน DevTools
การใช้งาน 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
call
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 ในบรรทัดยังหมายความว่าจะต้องทำการแก้ไข 2 ครั้ง ได้แก่ 1 ครั้งสำหรับไฟล์ CSS และ 1 ครั้งสำหรับ CSS ในบรรทัด นี่เป็นค่าใช้จ่ายด้านประสิทธิภาพที่เรานำออกได้หาก CSS ทั้งหมดเขียนในไฟล์ CSS แบบสแตนด์อโลน
- ปัญหาในการย่อขนาด CSS ในหน้านั้นสามารถลดขนาดลงได้ยาก ดังนั้นจึงไม่มีการลด CSS ใดเลย นอกจากนี้ ขนาดไฟล์ของบิลด์รุ่นของ DevTools ยังเพิ่มขึ้นด้วย CSS ที่ซ้ำกันซึ่งเกิดจากอินสแตนซ์หลายรายการของคอมโพเนนต์เว็บเดียวกัน
เป้าหมายของโปรเจ็กต์การฝึกงานของฉันคือการหาโซลูชันสำหรับโครงสร้างพื้นฐาน CSS ที่ทำงานได้กับทั้งโครงสร้างพื้นฐานเดิมและคอมโพเนนต์เว็บใหม่ที่ใช้ใน DevTools
ค้นหาวิธีแก้ปัญหาที่เป็นไปได้
ปัญหานี้อาจแบ่งออกเป็น 2 ส่วนดังนี้
- ดูว่าระบบบิลด์จัดการไฟล์ 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 (DevTools ใช้ Shadow DOM มาเป็นเวลา 2-3 ปีแล้ว) โดยใช้พร็อพเพอร์ตี้ adoptedStyleSheets
ตัวเลือก Bundler
เราต้องการวิธีแปลงไฟล์ CSS เป็นออบเจ็กต์ CSSStyleSheet
เพื่อให้จัดการไฟล์ TypeScript ได้ง่าย เราพิจารณาทั้ง Rollup และ webpack เป็น Bundler ที่อาจทำการเปลี่ยนแปลงนี้ให้เราได้ DevTools ใช้ Rollup ในบิลด์สำหรับใช้งานจริงอยู่แล้ว แต่การเพิ่มเครื่องมือจัดกลุ่มลงในบิลด์สำหรับใช้งานจริงอาจทำให้เกิดปัญหาด้านประสิทธิภาพเมื่อทำงานร่วมกับระบบบิลด์ปัจจุบันของเรา การผสานรวมกับระบบบิลด์ 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
เราได้เขียนสคริปต์ generate_css_js_files.js
เพื่อให้ GN สร้างไฟล์ CSS ในระหว่างการสร้าง ตอนนี้ระบบในรุ่นจะประมวลผลไฟล์ 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
นั้นซับซ้อนกว่า ฟังก์ชันหลัก 2 รายการที่ลงทะเบียนสไตล์เดิมคือ registerRequiredCSS
และ createShadowRootWithCoreStyles
เราตัดสินใจว่าเนื่องจากขั้นตอนการย้ายข้อมูลการเรียกเหล่านี้ค่อนข้างมีความสำคัญ เราใช้กฎ ESLint เพื่อทำการแก้ไขและย้ายโค้ดเดิมได้โดยอัตโนมัติ เครื่องมือสำหรับนักพัฒนาเว็บใช้กฎที่กำหนดเองจำนวนหนึ่งอยู่แล้วสำหรับฐานของโค้ดเครื่องมือสำหรับนักพัฒนาเว็บ ซึ่งมีประโยชน์เนื่องจาก ESLint จะแยกวิเคราะห์โค้ดเป็นAbstract Syntax Tree (ย่อมาจาก AST) AST) และเราค้นหาโหนดการเรียกที่เฉพาะเจาะจงซึ่งเรียก CSS ที่ลงทะเบียนได้
ปัญหาใหญ่ที่สุดที่เราพบเมื่อเขียนกฎ ESLint สำหรับการย้ายข้อมูลคือการจับขอบเขตกรณี เราต้องการหาจุดสมดุลที่เหมาะสมระหว่างการรู้ว่ากรณีขอบใดควรบันทึกไว้และกรณีขอบใดควรย้ายข้อมูลด้วยตนเอง นอกจากนี้ เรายังต้องสามารถแจ้งให้ผู้ใช้ทราบได้เมื่อระบบสร้างไฟล์ .css.js
ที่นำเข้าโดยอัตโนมัติไม่ได้ เนื่องจากการดำเนินการนี้จะช่วยป้องกันข้อผิดพลาดที่ระบบไม่พบไฟล์รันไทม์
ข้อเสียอย่างหนึ่งของการใช้กฎ ESLint สำหรับการย้ายข้อมูลคือเราไม่สามารถเปลี่ยนแปลงไฟล์บิลด์ GN ที่จำเป็นในระบบได้ ผู้ใช้ต้องทําการเปลี่ยนแปลงเหล่านี้ด้วยตนเองในแต่ละไดเรกทอรี แม้ว่าการดำเนินการนี้จะต้องดำเนินการเพิ่มเติม แต่ก็เป็นวิธีที่ดีในการยืนยันว่าระบบบิลด์เป็นผู้สร้างไฟล์ .css.js
ทุกๆ ไฟล์ที่นำเข้าจริงๆ
โดยรวมแล้ว การใช้กฎ ESLint สำหรับการย้ายข้อมูลนี้มีประโยชน์มาก เนื่องจากเราย้ายข้อมูลโค้ดเดิมไปยังโครงสร้างพื้นฐานใหม่ได้อย่างรวดเร็ว และการมี AST พร้อมใช้งานทำให้เราสามารถจัดการกับกรณีขอบหลายรายการในกฎและแก้ไขโดยอัตโนมัติได้อย่างน่าเชื่อถือโดยใช้ Fixer API ของ ESLint
มีอะไรต่อไป
จนถึงตอนนี้ คอมโพเนนต์เว็บทั้งหมดในเครื่องมือสำหรับนักพัฒนาซอฟต์แวร์ Chromium ได้ย้ายข้อมูลไปใช้โครงสร้างพื้นฐาน CSS ใหม่แทนการใช้รูปแบบอินไลน์แล้ว นอกจากนี้ เรายังได้ย้ายข้อมูลการใช้งานเดิมส่วนใหญ่ของ registerRequiredCSS
ไปใช้ระบบใหม่ด้วย สิ่งที่เหลืออยู่คือนำไฟล์ module.json
ออกให้มากที่สุด แล้วย้ายข้อมูลโครงสร้างพื้นฐานปัจจุบันนี้เพื่อใช้สคริปต์โมดูล CSS ในอนาคต
ดาวน์โหลดเวอร์ชันตัวอย่าง
ลองใช้ Chrome Canary, Dev หรือ เบต้า เป็นเบราว์เซอร์สำหรับนักพัฒนาซอฟต์แวร์เริ่มต้น ช่องทางเวอร์ชันตัวอย่างเหล่านี้จะช่วยให้คุณเข้าถึงฟีเจอร์ล่าสุดของ DevTools, ทดสอบ API ของแพลตฟอร์มเว็บที่ล้ำสมัย และช่วยคุณค้นหาปัญหาในเว็บไซต์ได้ก่อนที่ผู้ใช้จะพบ
ติดต่อทีมเครื่องมือสำหรับนักพัฒนาเว็บใน Chrome
ใช้ตัวเลือกต่อไปนี้เพื่อพูดคุยเกี่ยวกับฟีเจอร์ใหม่ การอัปเดต หรือสิ่งอื่นๆ ที่เกี่ยวข้องกับเครื่องมือสำหรับนักพัฒนาเว็บ
- ส่งความคิดเห็นและคำขอฟีเจอร์ถึงเราได้ที่ crbug.com
- รายงานปัญหาเกี่ยวกับเครื่องมือสำหรับนักพัฒนาเว็บโดยใช้ ตัวเลือกเพิ่มเติม > ความช่วยเหลือ > รายงานปัญหาเกี่ยวกับเครื่องมือสำหรับนักพัฒนาเว็บในเครื่องมือสำหรับนักพัฒนาเว็บ
- ทวีตถึง @ChromeDevTools
- แสดงความคิดเห็นในมีอะไรใหม่ในวิดีโอ YouTube เกี่ยวกับเครื่องมือสำหรับนักพัฒนาเว็บ หรือวิดีโอ YouTube เคล็ดลับสำหรับเครื่องมือสำหรับนักพัฒนาเว็บ