13 KiB
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 прийнятно:
- Завантажити офіційний Ultralight SDK, знайти в ньому Sample #8 ("Browser") — це вже готовий мінімальний браузер на чистому Ultralight.
- Відкрити в ньому youtube.com, спробувати програти будь-яке відео.
- Зафіксувати чесно: чи взагалі вантажиться сторінка, чи є звук, чи є відео, наскільки стабільно (не падає/не висне при скролі списку рекомендацій).
- Порівняти 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,Ultralightview/compositor) — самаWebCore(layout engine, форк WebKit) відкрита під LGPL/BSD.
Архітектурні відмінності від WebView2, які треба врахувати в коді
- Single process, без IPC — на відміну від WebView2/Chromium, де кожен renderer — окремий процес (
msedgewebview2.exeper 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 у WPFCompositionTarget.Renderingабо окремий таймер, і подавати результат якWriteableBitmap/текстуру у WPFImage-контрол. WebResourceRequested-подібного firewall у тому вигляді, що є зараз (перехоплення мережевих запитів по host/URL) — треба перевірити, чи є еквівалент у Ultralight API (AppCore filesystem/network hooks), задокументована частина цього не гарантована так само детально, як у WebView2.
Рекомендований план дій для агента
- Крок 0 (Go/No-Go тест вище) — обов'язково перший, і чесно задокументувати результат у цьому файлі чи окремому
ULTRALIGHT_EVAL_RESULTS.md, включно з цифрами RAM. - Якщо результат прийнятний — не переписувати
TabManager.csодразу поверх існуючого. Зробити паралельнийCore/UltralightTabManager.cs(або аналог) як окрему гілку/фіче-флаг, щоб WebView2-шлях лишався робочим fallback, поки Ultralight-шлях не доведено стабільним на реальних сценаріях (не тільки YouTube — плейлисти, перемикання вкладок, тривала фонова робота годинами). - Портувати спочатку тільки non-media сторінки (власний UI, прості сайти) на Ultralight, лишаючи медіа-плеєр окремо через
NativeAudioSession(direct URL) незалежно від того, який рушій рендерить решту. - Watchdog і suspend-логіку переписати під single-process модель Ultralight — старі пороги (850 MB soft-reload) писались під конкретну поведінку WebView2/Chromium і, ймовірно, невалідні напряму.
- Повторно виміряти реальний виграш по RAM (не по відчуттю) на тому самому сценарії, що і в NEXT_AGENT_GUIDE.md — одна довгограюча медіа-вкладка годинами — і чесно порівняти з поточними цифрами WebView2-версії.
Головний ризик, який не можна замовчати
Якщо Крок 0 покаже, що YouTube на Ultralight банально не працює (немає звуку, ламається UI, падає рушій) — це не привід "трохи допрацювати", а сигнал, що для головного use case проєкту (легкий фоновий плеєр для YouTube/музики) Ultralight як основний рушій не підходить, і чесний наступний крок — залишити WebView2 для медіа-сторінок, а Ultralight розглядати хіба що для легких допоміжних вікон (налаштування, non-media UI), де сумісність з сучасним вебом не критична.