Создайте свое первое расширение, которое вставляет новый элемент на страницу.
Обзор
В этом руководстве описывается создание расширения, которое добавляет ожидаемое время чтения к любому расширению Chrome и странице документации Chrome Web Store.

В этом руководстве мы объясним следующие концепции:
- Манифест расширения.
- Какие размеры иконок использует расширение.
- Как внедрить код на страницы с помощью скриптов контента .
- Как использовать шаблоны соответствия.
- Расширение разрешений.
Прежде чем начать
Это руководство предполагает, что у вас есть базовый опыт веб-разработки. Мы рекомендуем ознакомиться с руководством Hello world для введения в рабочий процесс разработки расширений.
Построить расширение
 Для начала создайте новый каталог с именем reading-time для хранения файлов расширения. Если хотите, можете загрузить полный исходный код с GitHub .
Шаг 1: Добавьте информацию о расширении
 Файл manifest JSON — единственный требуемый файл. Он содержит важную информацию о расширении. Создайте файл manifest.json в корне проекта и добавьте следующий код:
{
  "manifest_version": 3,
  "name": "Reading time",
  "version": "1.0",
  "description": "Add the reading time to Chrome Extension documentation articles"
}
 Эти ключи содержат основные метаданные для расширения. Они управляют тем, как расширение отображается на странице расширений и, после публикации, в Chrome Web Store. Чтобы погрузиться глубже, проверьте ключи "name" , "version" и "description" на странице обзора Manifest .
💡 Другие факты о манифесте расширения
- Он должен располагаться в корне проекта.
-  Единственными обязательными ключами являются "manifest_version","name"и"version".
-  Он поддерживает комментарии ( //) во время разработки, но их необходимо удалить перед загрузкой кода в Chrome Web Store.
Шаг 2: Предоставьте значки
Итак, зачем вам нужны иконки? Хотя иконки необязательны во время разработки, они необходимы, если вы планируете распространять свое расширение в Chrome Web Store. Они также появляются в других местах, например на странице управления расширениями.
 Создайте папку images и поместите туда иконки. Вы можете скачать иконки на GitHub . Затем добавьте выделенный код в свой манифест, чтобы объявить иконки:
{
  "icons": {
    "16": "images/icon-16.png",
    "32": "images/icon-32.png",
    "48": "images/icon-48.png",
    "128": "images/icon-128.png"
  }
}
Мы рекомендуем использовать файлы PNG, но допускаются и другие форматы файлов, за исключением файлов SVG.
💡 Где отображаются эти значки разного размера?
| Размер значка | Использование значка | 
|---|---|
| 16x16 | Фавикон на страницах расширения и в контекстном меню. | 
| 32x32 | Компьютерам на базе Windows часто требуется именно этот размер. | 
| 48x48 | Отображается на странице «Расширения». | 
| 128x128 | Отображается при установке и в интернет-магазине Chrome. | 
Шаг 3: Объявите сценарий контента
Расширения могут запускать скрипты, которые считывают и изменяют содержимое страницы. Они называются скриптами содержимого . Они живут в изолированном мире , то есть они могут вносить изменения в свою среду JavaScript, не конфликтуя со своей страницей-хостом или скриптами содержимого других расширений.
 Добавьте следующий код в manifest.json , чтобы зарегистрировать скрипт контента с именем content.js .
{
  "content_scripts": [
    {
      "js": ["scripts/content.js"],
      "matches": [
        "https://developer.chrome.com/docs/extensions/*",
        "https://developer.chrome.com/docs/webstore/*"
      ]
    }
  ]
}
 Поле "matches" может иметь один или несколько шаблонов соответствия . Они позволяют браузеру определять, на какие сайты следует внедрять скрипты контента. Шаблоны соответствия состоят из трех частей: <scheme>://<host><path> . Они могут содержать символы ' * '.
💡 Выводит ли это расширение предупреждение о разрешении?
Когда пользователь устанавливает расширение, браузер сообщает ему, что может делать расширение. Скрипты контента запрашивают разрешение на запуск на сайтах, которые соответствуют критериям шаблона соответствия.
 В этом примере пользователь увидит следующее предупреждение о правах доступа: 
Чтобы подробнее изучить разрешения расширений, см . раздел Объявление разрешений и предупреждение пользователей .
Шаг 4: Рассчитайте и введите время чтения.
 Скрипты контента могут использовать стандартную модель объектов документа (DOM) для чтения и изменения содержимого страницы. Расширение сначала проверит, содержит ли страница элемент <article> . Затем оно подсчитает все слова в этом элементе и создаст абзац, отображающий общее время чтения.
 Создайте файл content.js внутри папки scripts и добавьте следующий код:
function renderReadingTime(article) {
  // If we weren't provided an article, we don't need to render anything.
  if (!article) {
    return;
  }
  const text = article.textContent;
  const wordMatchRegExp = /[^\s]+/g; // Regular expression
  const words = text.matchAll(wordMatchRegExp);
  // matchAll returns an iterator, convert to array to get word count
  const wordCount = [...words].length;
  const readingTime = Math.round(wordCount / 200);
  const badge = document.createElement("p");
  // Use the same styling as the publish information in an article's header
  badge.classList.add("color-secondary-text", "type--caption");
  badge.textContent = `⏱️ ${readingTime} min read`;
  // Support for API reference docs
  const heading = article.querySelector("h1");
  // Support for article docs with date
  const date = article.querySelector("time")?.parentNode;
  (date ?? heading).insertAdjacentElement("afterend", badge);
}
renderReadingTime(document.querySelector("article"));
💡 Интересный JavaScript, использованный в этом коде
-  Регулярные выражения используются для подсчета только слов внутри элемента <article>.
-  insertAdjacentElement()используется для вставки узла времени чтения после элемента.
- Свойство classList используется для добавления имен классов CSS к атрибуту класса элемента.
- Необязательное связывание, используемое для доступа к свойству объекта, которое может быть неопределенным или иметь значение null.
-  Объединение со значением NULL возвращает <heading>, если<date>равно NULL или не определено.
Шаг 5: Следите за изменениями
С текущим кодом, если вы переключаете статьи с помощью левой навигации, время чтения не добавляется к новой статье. Это связано с тем, что наш сайт реализован как одностраничное приложение (SPA), которое выполняет мягкие навигации с помощью History API .
 Чтобы исправить это, мы можем использовать MutationObserver для отслеживания изменений и добавления времени чтения к новым статьям.
 Для этого добавьте следующее в конец content.js :
const observer = new MutationObserver((mutations) => {
  for (const mutation of mutations) {
    // If a new article was added.
    for (const node of mutation.addedNodes) {
      if (node instanceof Element && node.tagName === 'ARTICLE') {
        // Render the reading time for this particular article.
        renderReadingTime(node);
      }
    }
  }
});
// https://developer.chrome.com/ is a SPA (Single Page Application) so can
// update the address bar and render new content without reloading. Our content
// script won't be reinjected when this happens, so we need to watch for
// changes to the content.
observer.observe(document.querySelector('devsite-content'), {
  childList: true
});
Проверьте, работает ли это
Убедитесь, что файловая структура вашего проекта выглядит следующим образом:

Загрузите свое расширение локально
Чтобы загрузить распакованное расширение в режиме разработчика, следуйте инструкциям в разделе Основы разработки .
Откройте расширение или документацию Chrome Web Store
Вот несколько страниц, которые вы можете открыть, чтобы увидеть, сколько времени займет прочтение каждой статьи.
Это должно выглядеть так:

🎯 Потенциальные улучшения
На основе того, что вы узнали сегодня, попробуйте реализовать любое из следующих действий:
- Добавьте еще один шаблон соответствия в manifest.json для поддержки других страниц разработчиков Chrome , например, Chrome DevTools или Workbox .
- Добавьте новый скрипт контента, который рассчитывает время чтения, в любой из ваших любимых блогов или сайтов документации.
Продолжайте строить
Поздравляю с завершением этого урока 🎉. Продолжайте развивать свои навыки, выполняя другие уроки из этой серии:
| Расширение | Чему вы научитесь | 
|---|---|
| Режим фокусировки | Для запуска кода на текущей странице после нажатия на действие расширения. | 
| Менеджер вкладок | Создать всплывающее окно, управляющее вкладками браузера. | 
Продолжайте исследовать
Мы надеемся, что вам понравилось создание этого расширения Chrome, и вы с нетерпением ждете продолжения обучения разработке Chrome. Мы рекомендуем следующий путь обучения:
- В руководстве разработчика содержатся десятки дополнительных ссылок на документацию, касающуюся создания расширенных расширений.
- Расширения имеют доступ к мощным API, выходящим за рамки того, что доступно в открытом Интернете. Документация по API Chrome рассматривает каждый API.