Что нужно, чтобы создать свой веб-браузер
easy

Что нужно, чтобы создать свой веб-браузер

Статья для тех, кому действительно интересно

Последнее время с браузерами всё было просто и предсказуемо: есть Google Chrome для всех, есть Safari для пользователей Mac OS и Edge для Windows, есть Firefox, Opera, Brave и российский Яндекс Браузер, которые живут на тех же движках, что и предыдущие. Но в 2022 году вышел новый браузер Arc, который произвёл мини-революцию и быстро набрал популярность. Получается, что даже в этой области, где всё уже привычно и стандартно, можно создать новый браузер, который понравится пользователям.

Чтобы создать свой браузер, можно написать всё с нуля или использовать готовые компоненты. Но для начала нужно разобраться, как устроены браузеры, что делает движок и что нужно предусмотреть. Сегодня — как раз об этом.

Если вы только в общих чертах представляете, как работает браузер, почитайте нашу статью о том, что происходит, когда мы открываем сайт, Потом возвращайтесь — многое станет понятнее.

Из чего состоит веб-браузер

Обычно архитектуру браузера условно представляют в виде таких основных компонентов:

  • пользовательский интерфейс (User Interface, или UI);
  • движок браузера (Browser Engine);
  • рендеринг-движок (Rendering Engine);
  • сетевой слой (Networking Layer);
  • JavaScript-интерпретатор (JavaScript Interpreter);
  • бэкенд пользовательского интерфейса (UI Backend);
  • хранилище данных (Data Persistence).

Основные компоненты браузера
Основные компоненты браузера

Теперь разберёмся, что делает каждый компонент, за что отвечает и чем управляет.

Пользовательский интерфейс — набор элементов для взаимодействия непосредственно с браузером, а не с веб-страницами, которые он отображает. Это строка для ввода адреса сайта, кнопки «Назад», «Вперёд» и «Обновить страницу», панель закладок и другие подобные элементы. Проще говоря, интерфейс браузера — это то, что мы видим, когда запускаем браузер, но ещё не открыли ни одной страницы.

Движок браузера — самый важный и сложный компонент. Он отвечает за взаимодействие между пользовательским интерфейсом и рендеринг-движком и координирует работу между рендеринг-движком и другими компонентами браузера. Движок браузера управляет загрузкой страниц, обработкой и выполнением скриптов, сетевыми запросами, сессиями и так далее. Можно сказать, что движок — это мозговой центр браузера, без которого всё остальное перестанет работать. 

Рендеринг-движок отвечает за отображение запрошенной веб-страницы. Он читает файлы HTML со структурой страницы, CSS со стилями оформления и JavaScript с интерактивными сценариями, а затем рендерит, то есть отрисовывает, содержимое этих файлов на экране. В результате мы видим визуальное представление страницы, которое может динамически меняться от наших действий. 

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

JavaScript-интерпретатор отвечает за выполнение JavaScript-кода на страницах: анимации, интерактивные элементы и другой динамический контент. JS-интерпретатор обрабатывает события на странице так, что она реагирует на наши клики, ввод текста, прокрутку и наведение курсора мыши.

Бэкенд пользовательского интерфейса обрабатывает запросы от интерфейса и отправляет ответы. Например, когда пользователь вводит адрес сайта, бэкенд направляет этот запрос в сетевой модуль и движок браузера, чтобы загрузить нужную страницу.

Хранилище данных содержит данные пользователя: файлы куки, историю посещений и кэшированные файлы. В современных браузерах хранилище также используется для работы с локальными базами данных и офлайн-режимом.

Теперь важное замечание. На самом деле браузерный движок включает рендеринг-движок, сетевой слой, JavaScript-интерпретатор и бэкенд UI. Но их часто выделяют отдельно из-за того, насколько разные задачи они выполняют. А ещё так сложилось, что рендеринг-движки и JavaScript-интерпретаторы имеют свои названия. Например, в Chromium есть рендеринг-движок Blink и JS-интерпретатор V8. WebKit в Safari сначала был просто рендеринг-движком, а затем вырос до браузерного движка.

Чтобы создать свой полноценный браузер, нужно собрать вместе и настроить все эти компоненты. Разве что, если хотите «безголовый браузер» для разработки или тестирования, пользовательский интерфейс не нужен.

Какие процессы происходят в браузере во время его работы

Чтобы браузер работал быстро, стабильно и безопасно, задачи разделяются между разными процессами, которые могут одновременно взаимодействовать с различными компонентами. Приведём несколько примеров.

Основной процесс создаёт и завершает все остальные процессы, а также координирует их работу. Он обеспечивает взаимодействие браузера с операционной системой, включая доступ к файловой системе, сети и аппаратным ресурсам. Основной процесс связан с пользовательским интерфейсом, сетевым слоем, бэкендом UI и хранилищем данных. Если завершить основной процесс, браузер закроется вместе со всеми вкладками.

Рендер-процесс управляет отрисовкой страниц, преобразуя HTML, CSS и другие ресурсы в визуальное представление, и интерпретирует и исполняет JavaScript-код. Вкладки браузера обычно работают в отдельных рендер-процессах, чтобы изолировать их друг от друга. Если одна вкладка зависнет, это не повлияет на остальные. Рендер-процесс связан с рендеринг-движком, JavaScript-интерпретатором, сетевым слоем, бэкендом UI и хранилищем данных.

Процесс GPU помогает разгрузить основной и рендер-процессы. Он обрабатывает графику, которая требует аппаратного ускорения, например сложные визуальные эффекты. Процесс GPU связан с пользовательским интерфейсом браузера и рендеринг-движком.

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

Процесс обработки событий отвечает за обработку пользовательских действий: клики, ввод текста, прокрутку и другие. Эти события он передаёт в соответствующие рендер-процессы. Процесс обработки событий связан с пользовательским интерфейсом, рендеринг-движком, JavaScript-интерпретатором и бэкендом UI.

👉 Короче, нет такого, что компоненты браузера обособлены и процессы крутятся в них замкнуто. Всё переплетено.

Где взять готовые компоненты для создания браузера

Самый простой способ создать свой браузер — собрать его на базе готового проекта с открытым исходным кодом. Для этого весь код копируют, а затем меняют и дополняют по своему усмотрению, соблюдая лицензии. Вот с каких открытых проектов можно начать:

  1. Chromium — свободный браузер, на основе которого сделаны Google Chrome, Opera, Arc и многие другие браузеры. Включает мощный рендеринг-движок Blink и JavaScript-интерпретатор V8, которые можно использовать отдельно. На базе движка Blink сделан Яндекс Браузер.
  2. WebKit — движок, который используется в браузерах Safari и старых версиях Google Chrome. Включает JS-интерпретатор JavaScriptCore, который можно использовать отдельно.
  3. Gecko — движок, разработанный в Mozilla, используется в Firefox. Включает JS-интерпретатор SpiderMonkey, который можно использовать отдельно.
  4. Servo — экспериментальный движок, разработанный в Mozilla Research.
  5. Electron — фреймворк для создания приложений, который работает на движке Chromium и использует библиотеку Node.js для серверного уровня.
  6. Qt WebEngine — компонент фреймворка Qt для C++, основанный на Chromium. Позволяет создавать браузеры и другие веб-приложения.

У этих проектов есть подробная документация и инструкции по получению исходного кода. Выбор зависит от целей и требований к браузеру. Например, если браузер будет ориентирован на macOS или Linux, то лучше выбрать WebKit. 

Если хотите сделать браузер для разработчиков с удобными инструментами для отладки, то лучше выбрать Chromium, так как в него уже встроены нужные инструменты разработчика и можно добавлять свои функции и расширения.

Для легковесного браузера, который будет работать на слабых устройствах, можно выбрать Servo — он заточен на высокую производительность и безопасность (но инструментами разработчика там пользоваться будет сложно).

На чём написать свой движок для браузера

Если вы всё-таки хотите написать свой движок, то сначала нужно выбрать язык. В основном браузерные движки пишут на C++ и Rust.

С++ как низкоуровневый язык позволяет писать код, который выполняется очень быстро. В отличие от языков, которые требуют интерпретаторов, например Python или JavaScript, C++ компилируется непосредственно в машинный код. Это позволяет напрямую взаимодействовать с операционной системой и точно контролировать, как и когда выделяется и освобождается память. На C++ можно написать мощный и производительный движок, как Chromium, Blink, Gecko и WebKit. 

Rust тоже компилируется в машинный код, а ещё использует систему владения и заимствования для управления памятью. У каждого фрагмента данных, например переменной или структуры, есть только один владелец, например функция. После того как она выполняется, память автоматически освобождается. При заимствовании доступ к данным одалживается другим частям кода с условием: либо несколько частей одновременно их читают, либо только одна часть их меняет. Это минимизирует риск утечки памяти и идеально подходит для многопоточных приложений. На Rust можно написать надёжный движок, как Servo от Mozilla.

На этих языках есть готовые библиотеки, которые можно использовать для выполнения различных задач браузера, например:

  • чтение HTML и сбор страниц — Gumbo на C++ и HTML5ever на Rust;
  • чтение CSS и применение стилей — libcss на C++ и rust-cssparser на Rust;
  • работа с сетью — libcurl для HTTP-запросов и libuv для асинхронной загрузки на C++ и Hyper на Rust;
  • обработка пользовательских событий — libev или libuv на C++ и winit на Rust.

Что нужно предусмотреть 

Поскольку браузер обрабатывает большое количество данных — от рендеринга и выполнения JavaScript до загрузки мультимедиа и хранения данных пользователя, то браузер должен эффективно использовать оперативную память, чтобы не зависать и не тормозить. В C++ и Rust есть встроенные механизмы для управления памятью, но браузеру могут потребоваться дополнительные алгоритмы, например для управления памятью в процессе рендеринга или работы с большими данными. Для этих целей можно использовать библиотеки для управления кэшем: jemalloc на C/C++ или moka на Rust.

Данные в браузере должны передаваться безопасно, чтобы злоумышленники не могли перехватить пароли или другую чувствительную информацию. Для этого в браузере должны быть такие штуки:

  • шифрование локально хранимых данных (можно сделать с помощью OpenSSL для C/C++ или rust-crypto для Rust);
  • возможность использовать HTTPS для защиты передачи данных (libcurl на C/C++ и reqwest на Rust);
  • защита от XSS- и CSRF-атак с помощью Content Security Policy. 

Чтобы пользователи могли сохранять свои предпочтения в браузере, а браузер — хранить кэш, куки и пароли, нужно реализовать механизм хранения. Для этого можно использовать SQLite на C/C++, который применяется в большинстве современных браузеров. Это легковесная и мощная база данных, которая поддерживает хранение данных локально на устройстве пользователя.

Далее нужно реализовать систему автоматического обновления, чтобы браузер всегда оставался актуальным, получал новые функции и был защищён от уязвимостей. Для этого понадобится создать сервер обновлений и механизм проверки версий, загрузки и установки обновлений. Можно использовать Squirrel — кроссплатформенное решение для автоматических обновлений.

В собственный браузер также можно добавить инструменты разработчика: либо интегрировать готовые решения (Chromium DevTools), либо создать упрощённые версии, используя доступные API.

Для тестирования и отладки пригодятся фреймворки Selenium или Puppeteer (для браузеров на основе Chromium). Для отладки также можно использовать встроенные возможности языка, например GNU Debugger для C++, или специализированные инструменты для поиска утечек памяти.

Что дальше

В следующий раз соберём собственный браузер из готовых компонентов. Подпишитесь, чтобы не пропустить продолжение.

Редактор:

Инна Долога

Обложка:

Алексей Сухов

Корректор:

Ирина Михеева

Вёрстка:

Маша Климентьева

Соцсети:

Юлия Зубарева

Получите ИТ-профессию
В «Яндекс Практикуме» можно стать разработчиком, тестировщиком, аналитиком и менеджером цифровых продуктов. Первая часть обучения всегда бесплатная, чтобы попробовать и найти то, что вам по душе. Дальше — программы трудоустройства.
Получите ИТ-профессию Получите ИТ-профессию Получите ИТ-профессию Получите ИТ-профессию
Еще по теме
easy