Модернизация инфраструктуры CSS в DevTools

Обновление архитектуры DevTools: модернизация инфраструктуры CSS в DevTools

Этот пост является частью серии постов в блоге, описывающих изменения, которые мы вносим в архитектуру DevTools и то, как она построена. Мы объясним, как исторически CSS работал в DevTools и как мы модернизировали наш CSS в DevTools в рамках подготовки (в конечном итоге) к переходу на веб-стандартное решение для загрузки CSS в файлы JavaScript.

Предыдущее состояние 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 в своей производственной сборке, но добавление любого упаковщика в производственную сборку может привести к потенциальным проблемам с производительностью при работе с нашей текущей системой сборки. Наша интеграция с системой сборки Chromium GN усложняет объединение, и поэтому сборщики, как правило, плохо интегрируются с текущей системой сборки 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, что позволяет избежать любых проблем, вызванных повторяющимися именами классов или селекторами идентификаторов в файлах 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 для внесения исправлений и автоматического переноса устаревшего кода. 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.

,

Обновление архитектуры DevTools: модернизация инфраструктуры CSS в DevTools

Этот пост является частью серии постов в блоге, описывающих изменения, которые мы вносим в архитектуру DevTools, и способы ее построения. Мы объясним, как исторически CSS работал в DevTools и как мы модернизировали наш CSS в DevTools в рамках подготовки (в конечном итоге) к переходу на веб-стандартное решение для загрузки CSS в файлы JavaScript.

Предыдущее состояние 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 в своей производственной сборке, но добавление любого упаковщика в производственную сборку может привести к потенциальным проблемам с производительностью при работе с нашей текущей системой сборки. Наша интеграция с системой сборки Chromium GN усложняет объединение, и поэтому сборщики, как правило, плохо интегрируются с текущей системой сборки 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, что позволяет избежать любых проблем, вызванных повторяющимися именами классов или селекторами идентификаторов в файлах 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 для внесения исправлений и автоматического переноса устаревшего кода. 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.

,

Обновление архитектуры DevTools: модернизация инфраструктуры CSS в DevTools

Этот пост является частью серии постов в блоге, описывающих изменения, которые мы вносим в архитектуру DevTools и то, как она построена. Мы объясним, как исторически CSS работал в DevTools и как мы модернизировали наш CSS в DevTools в рамках подготовки (в конечном итоге) к переходу на веб-стандартное решение для загрузки CSS в файлы JavaScript.

Предыдущее состояние 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 в своей производственной сборке, но добавление любого упаковщика в производственную сборку может привести к потенциальным проблемам с производительностью при работе с нашей текущей системой сборки. Наша интеграция с системой сборки Chromium GN усложняет объединение, и поэтому сборщики, как правило, плохо интегрируются с текущей системой сборки 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, что позволяет избежать любых проблем, вызванных повторяющимися именами классов или селекторами идентификаторов в файлах 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 для применения исправлений и автоматического переноса устаревшего кода. 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.

,

Обновление архитектуры DevTools: модернизация инфраструктуры CSS в DevTools

Этот пост является частью серии постов в блоге, описывающих изменения, которые мы вносим в архитектуру DevTools и то, как она построена. Мы объясним, как исторически CSS работал в DevTools и как мы модернизировали наш CSS в DevTools в рамках подготовки (в конечном итоге) к переходу на веб-стандартное решение для загрузки CSS в файлы JavaScript.

Предыдущее состояние 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 делает пучки более сложной, и поэтому связки, как правило, не хорошо интегрируются с текущей системой сборки хрома.

Вместо этого мы исследовали возможность использовать текущую систему сборки GN для выполнения этого преобразования для нас.

Новая инфраструктура использования CSS в DevTools

Новое решение включает в себя использование adoptedStyleSheets для добавления стилей в конкретный теневой DOM при использовании системы сборки GN для генерации объектов CSSstylesheets, которые могут быть приняты с помощью 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
  • Применяет стили только к теневым 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 для применения исправлений и автоматического переноса устаревшего кода. Devtools уже использует ряд пользовательских правил, специфичных для кодовой базы DevTools. Это было полезно, так как Eslint уже анализирует код в абстрактном синтаксисном дереве (Abbr. AST), и мы могли бы запросить конкретные узлы вызовов, которые были призывами к регистрации CSS.

Самой большой проблемой, с которой мы столкнулись при написании правил миграции Eslint, было захватывалоя случаев. Мы хотели убедиться, что мы получили правильный баланс между знанием того, какие кромки стоит захватить, а какие следует мигрировать вручную. Мы также хотели иметь возможность убедиться, что мы могли бы сообщить пользователю, когда импортированный файл .css.js не генерируется системой сборки, так как это предотвращает любые файлы, не найденные ошибки в среде выполнения.

Одним из недостатков использования правил ESLINT для миграции было то, что мы не могли изменить необходимый файл сборки GN в системе. Эти изменения должны были быть сделаны вручную пользователем в каждом каталоге. Несмотря на то, что это потребовало большей работы, это был хороший способ подтвердить, что каждый импортный файл .css.js фактически генерируется системой сборки.

В целом, использование правил ESLINT для этой миграции было действительно полезным, так как мы смогли быстро перенести код устаревшего в новую инфраструктуру, и наличие AST легко доступно означало, что мы также могли бы обработать множество случаев в правиле и надежно исправить их, используя Fixer Eslint API .

Что дальше?

До настоящего времени все веб -компоненты в Chromium Devtools были перенесены для использования новой инфраструктуры CSS вместо использования встроенных стилей. Большинство устаревших использования registerRequiredCSS также были перенесены для использования новой системы. Все, что осталось, - это удалить как можно больше файлов module.json , а затем перенести эту текущую инфраструктуру для реализации сценариев модуля CSS в будущем!

Загрузите предварительный просмотр каналов

Рассмотрите возможность использования Chrome Canary , Dev или Beta в качестве браузера для разработки по умолчанию. Эти каналы предварительного просмотра дают вам доступ к новейшим функциям Devtools, позволяют протестировать передовые API веб-платформы и помочь вам найти проблемы на вашем сайте, прежде чем ваши пользователи!

Свяжитесь с командой Chrome DevTools

Используйте следующие параметры, чтобы обсудить новые функции, обновления или что-либо еще, связанное с DevTools.