Files
FoxBrowser/ULTRALIGHT_AGENT_GUIDE.md
T
2026-10-01 01:46:18 +03:00

13 KiB
Raw Blame History

FoxBrowser — гайд з переходу на Ultralight (замість/поруч з WebView2)

Контекст і чому це взагалі розглядається

Поточна архітектура (TabManager.cs, NativeAudioSession.cs) побудована на Microsoft Edge WebView2 — тобто по суті на Chromium/Blink рушії, який вже стоїть у системі. Виграш там — тільки по диску (немає власної копії Chromium в інсталяторі) і по shell-архітектурі (один спільний WebView2, suspend вкладок, audio-only CSS/JS). Базове споживання RAM на сторінку залишається "chromium-рівня", бо рушій той самий.

Диск користувача не хвилює. Хвилює тільки RAM. Тому єдиний спосіб реально зменшити базове споживання пам'яті — це взяти інший, не Chromium-похідний рушій. Ultralight — головний кандидат: це форк WebKit (WebCore) зі своїм легким рендерером і JavaScriptCore замість V8, зроблений спеціально для embedding в apps/games, а не для повноцінного браузингу.

Це не заміна архітектури "один shell — багато логічних вкладок" — це заміна рушія під капотом TabManager. Wrapper-рівень (metadata tabs, watchdog, resource firewall) залишається концептуально тим самим.

⚠️ Критичне обмеження — прочитати перед тим, як писати хоч рядок коду

Офіційний FAQ Ultralight прямо каже: рушій не підтримує WebGL, WebRTC, а підтримка HTML5 Video/Audio — "currently experimental". DRM (Widevine) не підтримується взагалі — це навіть не обговорюється в їхніх матеріалах, бо Ultralight не є Chromium-похідним і не має ліцензованого DRM-модуля.

Це напряму б'є по головному сценарію проєкту — YouTube/музичні сервіси:

  • Звичайний <video>/<audio> на YouTube може просто не програватись, або програватися нестабільно, бо аудіо/відео декодування в рушії — експериментальна фіча, а не production-ready шлях.
  • Будь-який контент з DRM (YouTube Premium, Spotify Web Player з захищеними треками тощо) гарантовано не запрацює.
  • YouTube — важкий сучасний SPA (React-подібний фронтенд, WASM-компоненти). WebCore/JavaScriptCore може мати проблеми сумісності, яких в Blink просто немає, бо весь сучасний веб тестується проти Chromium.

Практичний висновок: якщо є ідея "просто підмінити WebView2 на Ultralight і воно так само програє YouTube-звук" — це, ймовірно, не спрацює з коробки. Реалістичний шлях — той, що вже закладений у проєкті через NativeAudioSession.cs: не покладатись на рушій узагалі для аудіо-декодування, а брати direct audio URL і програвати його нативним MediaPlayer/WASAPI в обхід HTML5 <audio> елемента. Ultralight в такому разі відповідає тільки за легкий рендер сторінки (UI, DOM, JS-логіка сайту), а не за сам звук.

Крок 0 — Go/No-Go тест (зробити ДО будь-якого рефакторингу коду)

Не чіпати TabManager.cs одразу. Спочатку окремим ізольованим експериментом перевірити, чи Ultralight взагалі відкриває YouTube прийнятно:

  1. Завантажити офіційний Ultralight SDK, знайти в ньому Sample #8 ("Browser") — це вже готовий мінімальний браузер на чистому Ultralight.
  2. Відкрити в ньому youtube.com, спробувати програти будь-яке відео.
  3. Зафіксувати чесно: чи взагалі вантажиться сторінка, чи є звук, чи є відео, наскільки стабільно (не падає/не висне при скролі списку рекомендацій).
  4. Порівняти RAM одного відкритого таба в Sample #8 з тим, що зараз показує watchdog для WebView2 на тій самій сторінці.

Якщо на кроці 3 YouTube взагалі не вантажиться або аудіо не програється — не переходити до Кроку 1. У такому разі єдиний life-виправданий сценарій — Ultralight як рушій тільки для легких некомплексних сторінок (власний UI, налаштування, прості сайти), а YouTube/аудіо йде повністю через NativeAudioSession (direct URL, без рендеру самої сторінки взагалі, або з окремим легким HTML-плеєром власної розробки). Це суттєво звужує роль Ultralight у проєкті — задокументувати це чесно, а не підганяти висновок під бажаний результат.

Стек і бібліотеки для .NET

Офіційний API Ultralight — тільки C/C++. Готових офіційних .NET-бібліотек від самої Ultralight Inc немає — є community-підтримувані байндинги:

  • UltralightNet / UltralightNet.Bundle (NuGet) — керовані байндинги до C API Ultralight + AppCore (windowing, font loader, filesystem, logger), з нативними бінарниками для win-x64 вже в пакеті.
    dotnet add package UltralightNet.Bundle
    
  • ⚠️ На момент цього гайду UltralightNet.Bundle таргетить .NET 10, а поточний проєкт — .NET 8. Перед стартом перевірити актуальну версію пакета на nuget.org і чи є білд під .NET 8, або чи є сенс піднімати проєкт до .NET 10 заради цього (окреме рішення, не робити мовчки за замовчуванням).
  • Пакет — тонка обгортка над нативним C API, тобто код виглядає не по-WPF-івськи (renderer.CreateView(), ручний update/render loop), а не як CoreWebView2 — буде помітно більше низькорівневого коду, ніж зараз з WebView2.

Ліцензування — важливо для будь-якого комерційного релізу

Ultralight розповсюджується за "ULTRALIGHT FREE LICENSE AGREEMENT — V1":

  • Free/Limited Commercial Distribution дозволена тільки якщо юрособа-ліцензіат не мала обороту понад US$100,000 за останній фінансовий рік.
  • Якщо оборот перевищує цей поріг у будь-якому наступному році — усі права на комерційну дистрибуцію автоматично анулюються, і потрібна окрема платна ліцензія напряму з Ultralight Inc.
  • Для приватного/некомерційного use case (як зараз, судячи з проєкту) це не проблема, але задокументувати цей поріг, щоб не зʼясувати це post-factum при спробі щось випустити комерційно.
  • Заборонено reverse engineering, декомпіляція, спроби дістатись сирців пропрієтарної частини (UltralightCore, Ultralight view/compositor) — сама WebCore (layout engine, форк WebKit) відкрита під LGPL/BSD.

Архітектурні відмінності від WebView2, які треба врахувати в коді

  • Single process, без IPC — на відміну від WebView2/Chromium, де кожен renderer — окремий процес (msedgewebview2.exe per tab/GPU), Ultralight працює в одному процесі без міжпроцесної ізоляції. Це означає: (а) менше overhead per-tab у теорії, (б) немає природної sandbox-ізоляції — крашнута/зависла вкладка може завалити весь застосунок, а не тільки один child-процес. Поточний watchdog (MemoryWatchdog.cs) писався в припущенні окремих WebView2-процесів — цю логіку треба переосмислити під single-process модель.
  • Рендер: GPU-текстура або CPU pixel buffer, керується вручну через renderer.Update() / renderer.Render() у власному циклі — на відміну від WebView2, де WPF-хостинг рендер-циклу ховає це від вас. Треба буде інтегрувати цей update loop у WPF CompositionTarget.Rendering або окремий таймер, і подавати результат як WriteableBitmap/текстуру у WPF Image-контрол.
  • WebResourceRequested-подібного firewall у тому вигляді, що є зараз (перехоплення мережевих запитів по host/URL) — треба перевірити, чи є еквівалент у Ultralight API (AppCore filesystem/network hooks), задокументована частина цього не гарантована так само детально, як у WebView2.

Рекомендований план дій для агента

  1. Крок 0 (Go/No-Go тест вище) — обов'язково перший, і чесно задокументувати результат у цьому файлі чи окремому ULTRALIGHT_EVAL_RESULTS.md, включно з цифрами RAM.
  2. Якщо результат прийнятний — не переписувати TabManager.cs одразу поверх існуючого. Зробити паралельний Core/UltralightTabManager.cs (або аналог) як окрему гілку/фіче-флаг, щоб WebView2-шлях лишався робочим fallback, поки Ultralight-шлях не доведено стабільним на реальних сценаріях (не тільки YouTube — плейлисти, перемикання вкладок, тривала фонова робота годинами).
  3. Портувати спочатку тільки non-media сторінки (власний UI, прості сайти) на Ultralight, лишаючи медіа-плеєр окремо через NativeAudioSession (direct URL) незалежно від того, який рушій рендерить решту.
  4. Watchdog і suspend-логіку переписати під single-process модель Ultralight — старі пороги (850 MB soft-reload) писались під конкретну поведінку WebView2/Chromium і, ймовірно, невалідні напряму.
  5. Повторно виміряти реальний виграш по RAM (не по відчуттю) на тому самому сценарії, що і в NEXT_AGENT_GUIDE.md — одна довгограюча медіа-вкладка годинами — і чесно порівняти з поточними цифрами WebView2-версії.

Головний ризик, який не можна замовчати

Якщо Крок 0 покаже, що YouTube на Ultralight банально не працює (немає звуку, ламається UI, падає рушій) — це не привід "трохи допрацювати", а сигнал, що для головного use case проєкту (легкий фоновий плеєр для YouTube/музики) Ultralight як основний рушій не підходить, і чесний наступний крок — залишити WebView2 для медіа-сторінок, а Ultralight розглядати хіба що для легких допоміжних вікон (налаштування, non-media UI), де сумісність з сучасним вебом не критична.