Привет, коллеги!
В этой статье я сделаю обзор 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.
Установка
Что нам потребуется для установки?
PHP 8.1
Laravel 10 и выше
npm
Linux либо MacOs.
Давайте с помощью 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.
При запуске в режиме разработки можем посмотреть на наше творение