Обзор NativePHP. Инструмент для создания собственных нативных desktop приложений на Laravel
В этой статье я сделаю обзор NativePHP, который появился на Laracon US 2023. Видеообзор, который я сделал, вызвал большой интерес у аудитории, и я решил оформить статью про NativePHP, для тех кто любит читать. Кто больше любит видео, то оно тут:
Что из себя представляет NativePHP? Перед нами фреймворк, который позволяет нам писать нативные десктоп приложения, используя PHP. Приложения кроссплатформенные - можно писать под Mac, Windows и Linux. И все это с использованием нашего любимого PHP с использованием Laravel. Но как обещают разработчики в будущем появятся и другие драйверы.
В целом вы просто пишете приложение на Laravel, устанавливаете NativePHP и компилируете его в десктоп приложение. Далее прямо в операционной системе запускаете приложение и перед вами откроется тот же самый проект, который Вы писали. Под капотом используется Electron или Tauri. Пока что у нас NativePHP в Альфа версии, и пока что доступен только Electron.
Electron - это фреймворк для разработки десктопных приложений с использованием HTML, CSS и JavaScript. В Electron уже встроены Chromium и Node.js, и это позволяет вам поддерживать только JavaScript код и создавать кроссплатформенные приложения, которые будут работать как на Windows, так и на macOS и Linux без необходимости иметь собственный опыт разработки.
Что под капотом - мы используем веб-технологии HTML, JS, CSS, чтобы скомпилировать итоговое приложение. И если мы говорим о Electron, то под капотом будет использоваться Chromium и Node.js, поэтому приложение в целом получится объемное, так как каждый раз будет подтягиваться Chromium и размер итоговой аппки будет большой. С появлением Tauri тут уже получше, использоваться будет встроенный браузер, webview и в итоге получится более легковесное и быстрое приложение. Но пока работаем с Electron.
Еще в NativePHP есть поддержка базы данных SQLite - мы когда скомпилируем приложение будем использовать внутреннюю базу и это также интересно.
Для создания нативного приложения я буду использовать свой проект MoonShine.
Установка
Что нам потребуется для установки?
Давайте с помощью Composer для начала установим NativePHP:
composer require nativephp/electron
Далее нас просят выполнить следующую команду по установке NativePHP уже внутри фреймворка Laravel:
php artisan native:install
С помощью npm за нас установят Electron и прочие зависимости которые требуются (необходимо подтвердить свое согласие выбрав “Yes”). После этого нас спрашивают запустить ли NativePHP сервер? Следуем рекомендациям и выбираем “No”. Установка выполнена, смотрим на результат (публикации confrg и serviceProvider).
Давайте посмотрим на конфиг (/config/nativephp.php) - тут можно кастомизировать наше приложение.
Заглянем в ServiceProvider (/Providers/NativeAppServiceProvider.php) - здесь будет твориться вся магия.
Видим Window::Open, то есть как только мы запустим наше приложение, у нас откроется окошко, в котором будет соответственно та веб-версия, которую мы написали на Laravel.
Возвращаемся к процессу установки и следующая команда как раз запускает сервер в режиме разработки:
php artisan native:serve
Приложение запускается! В правом нижнем углу на MacOS отобразится иконка Electron. Пока наше приложение выглядит не очень:
Для отображения приложения используется Chromium, одновременно демонстрируется devtools в правой части браузера с HTML, CSS, JS. Видим ошибку:
Нет таблицы. Есть ощущение что миграции не выполнены. В консоли предупреждение, что DataBase миграции пока пропущены, выполните для миграций команду вручную.
Странно, что про это ничего не сказано в разделе установка. И если бы не заглянул в терминал, ничего бы не понял. В доке в разделе Database нашел что надо делать. Выполняем команду (с опцией seed):
php artisan native:migrate --seed
Отображается ошибка о наличии миграции.
Догадался, что проблема в Telescope. Отключаем его:
Пробуем выполнить миграции еще раз. Не помогло. Пробую выполнить другую команду:
а native:migrate_fresh
На момент написания статьи команда native:migrate_fresh
вызывает ошибку самой команды т.е. команда не работает. Давайте разберемся. Найдем эту команду в NativeServiceProvider.php - обнаруживаем, что команда вообще не объявлена! То есть в документации есть - пользуйтесь ребята, но в самом релизе она отсутствует. Давайте добавим её сами, вручную.
И выполним еще раз:
а native:migrate_fresh
Разбираемся что не так. Исходя из содержимого FreshCommand.php - видно, что база данных database хранится в определенном файле из конфига и при fresh она просто удаляется.
Находим файл с базой sqlite (database/nativephp.sqlite) и попросту удаляем его.
Выполняем команду
native:migrate
Сервис провайдер сервиса Telescope при регистрации своего провайдера выполняет миграции. Убираем его, чтобы не мешал.
Выполняем команду
composer:update
Далее удаляем базу данных nativephp.sqlite из /database.
Еще раз пробуем выполнить миграции. В терминале выполняем
native:migrate
Миграции выполнены. Открываем приложение, видим что оно не обновилось. Но если начать что-либо менять в nativePhpServiceProvider, то произойдет hard reload и мы вынудим приложение обновиться. Давайте изменим ширину окна:
Открываем приложение, видим что произошла перезагрузка. Отлично что-то нарисовалось.
Видим главную страницу и devtools. Давайте скроем его. Для этого установим параметр:
ShowDevTools:false
Открываем приложение. DevTools пропал, видим главное окно сайта. Давайте через роут изменим стартовую страницу приложения и заодно размеры окна.
Давайте попробуем залогиниться. Не получается. Миграции мы сделали, но не сделали сиды. Выполним команду:
a native:migrate --seed
Проверяем. Отлично, авторизация выполнена.
Видим, что база данных работает и мы попадаем в админ-панель. Всё доступно и работает.
Заголовок и меню
Согласно документации мы можем кастомизировать окно с приложением. Давайте поменяем заголовок:
Window::open()
->title(title:'MoonShine');
Видим что тайтл изменился на заданный нами.
Меню бар (меню сверху, справа)
Практически пока не работает и вызывает кучу багов.
MenuBar::create();
В результате у нас появляется вверху пункт при клике на который появляется главная страница (т.е. содержимое меню сверху у нас формируется за счет определенного роута нашего веб-приложения, по умолчанию - главная страница).
также будет присутствовать метод route()
при помощи которого мы можем задать что-то другое.
Давайте посмотрим что еще можно сделать с MenuBar:
-
отобразить
MenuBar::show();
-
скрыть
MenuBar::hide();
-
изменить label
MenuBar::label('Status: Online');
Давайте протестируем:
Как результат появляется лейбл справа от иконки
Кроме того доступны команды:
-
изменить url
MenuBar::create()->url('https://google.com');
-
изменить route
MenuBar::create()->route('home');
-
изменить иконку
MenuBar::create()-> icon(storage_path('app/menuBarIconTemplate.png'));
-
изменить размер
MenuBar::create()->width(800)->height(600);
-
постоянно отображать сверху
MenuBar::create()->alwaysOnTop();
-
есть возможность добавлять контекстное меню
Через метод ->withContextMenu
указываем, что присутствует контекстное меню и добавляем пункты меню с помощью объекта Menu: ставим лэйблы, разделители, можно сделать активную ссылку.
Меню приложения
Меню которое обычно вверху окна. Вставляем код из примера в документации и посмотрим что получится.
В результате получаем application menu - наименования и пункт меню который добавили Native PHP и ссылку на документацию (при клике на которую переходим на страницу с документацией). Прикольно:
Диалоги
Можем открывать диалог по выбору файла из файловой системы. Мы можем вызывать события и тем самым открывать диалог прямо из NativePHP. Берем код
use Native\Laravel\Dialog;
Dialog::new()
->title('Select a file')
->open();
Приложение перезагружается и при запуске приложения теперь открывается файловый менеджер системы с диалогом выбора файла.
Нативные уведомления
На тестируемом приложении MoonShine есть уведомления: например при сохранении записи в базу данных. Давайте так же вместе с ним вызовем уведомление через нативное приложение. Открываем код и в метод с flash уведомлением добавим Notification из NativePHP (не забываем добавить use Native\Laravel\Facades\Notification;)
Давайте перейдем в статьи и нажмем сохранить. Видим, что уведомление появилось и контент как раз соответствует тому который указан по умолчанию. Работает.
Горячие клавиши
Как раз здесь таится ответ на вопрос о том что вообще делать с диалогами и прочим? Как вообще взаимодействовать с Native PHP? Взаимодействие происходит через события, а события у нас простые - те же самые ивенты, которые мы используем в Laravel. И скажем вот как в данном примере: мы объявляем горячие клавиши, затем когда они срабатывают, вызывается event, а уже в нём мы открываем дополнительное окошко с dialog, notification т.е. все то, что нам необходимо для взаимодействия с нашим приложением.
Итоговый Building
Скомпилируем наше приложение в итоговый файл и посмотрим сколько этот файл будет занимать места. В документации указано, что при Building поддерживается Electron/Tauri (но пока только Electron) и кроссплатформенность MacOS, Windows, Linux (Windows пока нет).
Останавливаем наше приложение в режиме разработки и выполним команду для запуска процесса компиляции, при этом копируется приложение в указанную в настройках директорию (у меня это dist):
php artisan native:build win
По результату скомпилированное приложение занимает более 1Gb, что чрезвычайно много для простого web приложения.
Посмотрим на саму аппку:
Проблема большого веса простейшего приложение скорее всего заключается в Electron т.к. он подтягивает Chromium - огромный браузер. Пробуем запустить приложение, оно запускается довольно шустро.
При попытке войти возникает проблема из которой становится понятно, что при компиляции не были выполнены seed (думаю что это из-за alfa версии). Со временем появятся дополнительные опции и при компиляции мы сможем выполнять seed.
При запуске в режиме разработки можем посмотреть на наше творение 🙂 Все работает!
Итоги
Интересный проект. Но еще сыроватый - в процессе тестирования вылезло очень много багов. Сделать нативное приложение получилось, но пришлось попотеть. Понятно, что еще альфа версия, но рассчитывал на более стабильную работу.
Также заметил, что последний месяц нет активности в репозитории проекта NativePHP, настораживает.
В завершение статьи хотел бы у вас спросить - а как вы думаете, есть ли будущее у проекта и какие можно задачи решать с его помощью? Давайте обсудим в комментариях.
Данил Щуцкий, автор проекта CutCode.