А что если сделать модуль для node.js, умеющий показывать UI в системном браузере?
Под катом расскажу о попытке — как оно, стоит ли усилий, можно ли использовать, и что в результате получилось.
Dicslaimer
В основном проект был сделан скорее как proof-of-concept: поиграться, посмотреть, проверить, как оно. Сделал на нём 3-4 заказа в стиле «хочу маленькое приложение со встроенным webview» или «хочу обёртку для сайта в окне десктоп-приложения». Может быть, кому-то мой опыт окажется полезен, поэтому выложил в паблик. Код на гитхабе. Подробно описывать нюансы кода не буду, цель — не описать код, а скорее подумать над пригодностью результата.
Как это работает
Приложение статически собирается с node.js со своей точкой входа. При запуске в ноду добавляется нативный модуль с логикой отображения окон, и управление передаётся _thirdPartyMain.js (в ноде есть такая возможность). Оттуда загружается пользовательский main.js, где подключается модуль ui. Модуль стартует http-сервер, открывает окно с заданным конфигом и направляет webview на адрес встроенного сервера, который отдаёт пользовательский контент. Окно генерирует события (перемещение, сворачивание, ...) и умеет выполнять методы (например, закрыться).
WebView
Под винды вставляется ActiveX-ный WebBrowser (это тот же MSIE, но без тубларов, адресных строк итд). По умолчанию он показывает много ненужных диалогов (которые отключаются странным образом), но в целом работает как хочется. IE, обновляется неважно, а поддержать XP надо было, поэтому для старых версий Windows предусмотрена возможность скачать вебкит (chrome embedded framework). При необходимости, если пользователь не против, приложение скачивает библиотеки, распаковывает их и работает уже с вебкитом.
Под маком всё более прозрачно, WebKit WebView по сравнению с IE в интеграции намного проще и понянтее; под линуксом есть webkit-gtk.
Упаковка приложений
Нужно было, чтобы приложения паковались в один EXE. Самым подходящим форматом оказался ZIP: он читается с конца, позволяя дописывать в исполняемый файл что угодно, и распаковывать его из себя; по этому принципу и работают SFX. Для использование из node.js, можно повесить хук на обращения к fs и перенаправить запросы к файлам, которые есть в архиве, к виртуальной файловой системе вместо чтения с диска.
Взаимодействие с браузером
IE и WebKit предлагают способы взаимодействия как из C++ в JS, так и наоборот. В IE javascript-овый объект, в том числе и функция, представляет собой объект IDispatch. Если проверить typeof такого объекта, javascript-движок отдаст unknown, это так называемые host objects (использование таких результатов оператора typeof в стандарте ES6 уже не рекомендуется, но раньше про нестандартные типы ничего не было сказано). Что-то вызвать из C++ можно, обратившись к объекту window.external, при условии, что хост реализовал этот метод.
В вебките аналогично, можно добавить свойство window как объект с методми, доступными для вызова.
Взаимодействие с node.js
В ноде процесс создания плагинов прекрасно документирован. Аналогично создаются и встроенные аддоны, но регистрируются другим макросом. После создания класса аддона, он наследуются от EventEmitter-а и умеет генерировать события, получив ссылку на метод emit.
Node.js намеренно живёт в отдельном треде, чтобы длительные операции не блокировали UI, поэтому для отправки сообщения в ноду и синхронизации используется библиотека UV.
Что получилось хорошо
Размер приложения
Он составляет 2-3 МБ (незапакованного 7). В принципе можно сделать сборку и меньшего размера, если надо только открыть страничку в приложении, без node.js (вобщем-то ради размера всё и делалось).
Время запуска
Т.к. в приложении не используются дополнительные фреймворки, запускается оно быстро в среднем 1 секунду (про время первого запуска см. ниже); добавив профилирование, можно убедиться, что основное время уходит на инициализацию браузера.
Проблемы
Первый запуск
Windows оптимизирует запуск приложений и компонентов, которые вы используете чаще. Если IE пользуются редко, время первого запуска приложения составляет где-то 3..10 секунд, в зависимости от операционки и компьютера.
Версии браузеров
Очень часто IE
Версии браузеров привязаны к операционке: для Windows XP нет IE10, для OS X Lion нет Safari 8.
Контексты javascript
Объекты node.js нельзя использовать в браузере и наоборот, взаимодействие происходит или как в классическом клиент-серверном приложении (xhr), или способом, предоставленным программой (postMessage в окне или ноде) — т.е. как в web worker, передать можно только простые данные. Можно было сделать context bridge, но это во-первых сложно и бажно, во-вторых недальновидно, потому что ES6 уже почти тут, а что делать, например, с объектом-прокси в IE10 — неизвестно.
Что есть
Есть сборка под win/mac/linux, которую в принципе можно использовать, кастомизировать итд. Я и использую её для создания кастомизированных «приложений-браузеров», когда это бывает вдруг кому-то надо. Она относительно стабильна, но до ума и релизного качества я её не доводил, потому что…
Выводы
Приложения скачиваются редко, интернет сейчас достаточно быстрый (и в случае установки приложений, EDGE действительно можно пренебречь, т.к. приложение — это не сайт, его не будут устаналивать в дороге), нерешаемые проблемы в использовании системного браузера присутствуют. В большинстве случаев сейчас игра не стоит свеч и использовать вебкит кажется более правильным. Если цель — создать маленькое приложение в основном под новые операционки — а может быть, можно и так.
Ссылки
Комментарии (16)
Igogo2012
21.06.2015 22:07Как-то раз пробовал писать на nw.js там была проблема которую я на тот момент не смог решить и отказался от данного решения.
Проблема заключалась в том что мне нужно было в контенте приложения выводить гиперссылки которые должны открываться дефолтным браузером ОС, но так как там все приложение по сути и есть браузером с веб приложением то все гиперссылки открывались в том же окне…
Как у Вас обстоят дела с таким явлением, можно ли заставить приложение открывать ссылки в дефолтном браузере которым пользуется текущий пользователь системы?Antelle Автор
21.06.2015 22:22Можно. Вроде как, и в nw.js тоже можно. На ссылку повесить обработчик, в обработчике вызвать нодовский spawn.
Bytexpert
22.06.2015 00:13+1А как решали проблему c настройками IE? Отключенный показ картинок и отключенный JS?
Я делал подобное только под Windows и использовал встроенный JavaScript из WSH, он работал в потоке приложения как основная логика, а с браузером взаимодействовал через COM-объекты проброшенные в браузер. Ноду не использовал, у меня была своя библиотека объектов доступная из скрипта для работы с сетью, zip-ами, xml, графикой и т.п. с файловой системой работал через объекты WSH. Даже приложение написал рабочее pingxpert.com Но у Вас решение более универсальное.Antelle Автор
22.06.2015 00:38IE позволяет приложению задать путь к настройкам реестра через GetOptionKeyPath (и GetOverrideKeyPath). Если реализовать его, контрол будет с дефолтовыми настройками. Там всякие настройки запрета показа отладчиков итд. (а если честно отключённые js не проверяли, посмотрю, может и нужен более хитрый метод со своим security manager-ом).
Bytexpert
22.06.2015 01:06Да я использовал этот метод и security manager, но пользователи всё-равно частенько жалуются на неработоспособность программы, может тоже где-то недотестил и сам накосячил. А ещё большая проблема с отображением контента, если старые версии IE, то Bootstrap уже нельзя использовать. Поэтому WebKit мне в этом плане надёжнее кажется. А в передаче контекста в IE мне конечно проще было значительно, я просто отдавал объекты JavaScript-а основной логики прямо в браузер через SetExternalDispatch и получал в браузере весь нужный функционал.
Antelle Автор
22.06.2015 07:52Вот примерно к такому выводу я и пришёл, поигравшись со встроенными браузерами: в большинстве случаев вебкит показалось использовать более целесообразным.
some_x
22.06.2015 08:39Экономия в 30 мб, в десктопном приложении действительно стоит таких финтов ушами?
Antelle Автор
22.06.2015 08:57+1Не думаю (о чём и написал в «проблемах» и «выводах»). Скажу даже больше: если бы работа над проектом не была оплачена, я бы не стал это делать. А так, мне давно было интересно, а что же с таким подходом получится — вот довелось попробовать.
naum
В целом — круто, спасибо, ждал когда кто-то что-то подобное реализует рано или поздно, тут действительно большой простор для фантазий.
Antelle Автор
> в 2015 году UPX
Согласен, тем более что приложения в виде «голого» exe сейчас никто не распространяет, всегда или паковщик из инсталлятора, или архив. Заказчик хотел upx, так он там и остался, как-то не подумал удалить его, спасибо что напомнили, выпилю, профита 0. Бенчмаркил и без него, и с ним, конечно. upx и другие пакеры замедляют выполнение на 200-500 мс.