Как начать писать приложения на ClojureDart

16 апреля зарелизился ClojureDart, а это значит, что для любителей Clojure открылась возможность писать мобильные, веб- и десктоп-приложения на Flutter. Зачем использовать для этого Clojure, как бы очевидно это ни было, выходит за границы фокуса статьи.

На текущий момент инструменты еще не отшлифованы, нет репла (!) и автодополнений для dart-интеропа, но пользоваться можно, и некоторые плюшки кложуры уже показали себя (например, nest-макрос, убирающий проблему вложенности, а вот код side-by-side).

В этой статье хочу рассказать, как написать свое первое flutter-приложение на Clojure, какими инструментами удобно пользоваться, где искать ответы на вопросы. Статья для тех, кто имеет хотя бы минимальный опыт работы с Clojure.

И еще, статья будет поддерживаться на гитхабе.

Tools

Ставим Flutter по официальной инструкции и cli для Clojure. Дополнительно не помешает clj-kondo, через который сейчас работают ворнинги для макроса apha/widget.

Вот как это выглядит:

fd2dbd27058e68bb1947830a168a0e0a.gif

Выбор редактор кода

На данный момент нет поддержки интеропа с дартом, и приходится использовать хаки, о которых подробнее расскажу ниже, но сперва немного о редакторах.

VSCode — быстрый старт

Я не пользователь VSCode, но насколько мне известно, это самый простой способ начать. Устанавливаем Calva, и все заработает само:

de8dbf7084ffb6ccc1e04c86b5a9916d.gif

Не помешает поставить Flutter extenstion, подробнее тут.

Плюсы:

  • скорость и простота использования;

  • уникальный плагин Joyride, позволяющий писать настройки редактора с реплом на Clojure.

Intellij Idea — ожидаем поддержку

Результат, на который можно рассчитывать сейчас:

fc31dc714785e72aca3737d35af5f3b8.png

Есть автодополенения для Clojure (пример с reduce- выше), но интеропа с дартом нет и отключить эти ворнинги нельзя.

Плюсы:

  • почти ничего не нужно настраивать и чинить;

  • поддержка придет в ближайшем будущем, и все заработает без вашего участия.

Минусы:

  • экстремально медленно открывается проект (до минуты на hello-world на моем air-е, с вимом я жду 125 мс);

  • нет возможности настроить подсветку и автодополнения (только выключить);

Чтобы настроить поддержку *.cljd, необходимо указать расширение для clojure:
preferences -> editor -> filetypes -> clojure file -> file patterns -> + -> *.cljd
Поддержка Flutter настраивается плагинами для Дарта и Флаттера, подробнее тут.
Поддержка ворнингов clj-kondo работает с плагином clojure-extras.

Vim — кастомизация

Тот же пример с reduce-

d5407143d7264e3b5127b5f3dc5c172d.png

Плюсы:

  • скорость открытия, возможность открывать с десяток (сотню) проектов одновременно за миллисекунды;

  • расширенная кастомизация;

  • репл сам интегрируется в работу с выходом репла для ClojureDart;

  • возможность писать конфиги на лиспе (см. ниже).

Минусы:

  • нужно научиться пользоваться вимом;

  • нужно потратить время и настроить все самому;

  • иногда нужно заниматься починкой после обновления плагинов и самого вима.

Есть несколько опций, как завести вим для ClojureDart.

Nvim с lsp

Ставим плагин и 2 сервера — для Clojure и Flutter (полезные для флаттер-разработки команды + базовый функционал для работы с дартом).
Прописываем настройку для распознавания *.cljd как Clojure:

au! BufRead,BufNewFile *.cljd setfiletype clojure

Я сейчас пользуюсь такой конфигурацией, и за исключением интеропа с дартом в ней есть практически все (рефакторинг, goto definition, find usages, автодополнения, документация, чистка неймспесов) .

Мой конфиг описан на Fennel. Подробный разбор за рамками статьи, но если все же захочется использовать лисп, то я бы посоветовал начать с плагина aniseed и дотфайлов автора. В качестве начального конфига так же можно взять этот проект, либо готовую сборку nyoom.

Vim/nvim с плагином VimIced

Нужно настроить VimIced по инструкции и подключить clj-kondo в качестве линтера (по этой инструкции). Пока еще нет ClojureDart-репла, большей частью функционала будет пользоваться нельзя.

Fireplace

Не проверял этот плагин, но наверняка будет работать сопоставимо с VimIced, если где-то в виме прописать, что cljd → это кложур.

au! BufRead,BufNewFile *.cljd setfiletype clojure

Emacs

Разработчики ClojureDart пользуются Emacs, в Clojure-mode уже добавили распознавание *.cljd. На мой взгляд, плюсы и минусы сопоставимы с вимом, а остальное — на любителя.

Workflow

Рекомендую начать с hello-world, чтобы убедиться, что все работает.

В процессе работы удобно держать открытыми (под рукой) 3 окна:

  1. Любой файл на дарте (можно создать дарт-файл в директории lib/), чтобы тут же экспериментировать, смотреть сигнатуры, методы, поля и пр.

  2. Терминал, чтобы видеть логи и взаимодействовать с проектом.

  3. Эмулятор (по моему опыту андроид-эмулятор стабильнее и быстрее веб-версии). Самый простой способ настроить его — установить AndroidStudio, и воспользоваться Tools→DeviceManagement.

После запуска «watcher»-а:
сlj -M -m cljd.build flutter
Входим в петлю интерактивной разработки: пишем код, сохраняем файл, видим результат, снова пишем код…

Если нужен hot-reload, сохраняем файл.
Если нужен hot-restart, жмем Enter в терминале.
Если все перестает работать, удаляем папку .clojuredart/ и перезапускаем «watcher».

Использование библиотек

Как и в обычным Flutter-проекте, добавляем библиотеки в pubspec.yaml файл. Импортируем строкой, как и в *.dart файлах в формате, как в обычном Clojure:

(:require
    [clojure.string :refer [join]]
    ["package:graphql/client.dart" :as g])

Единственный способ использовать свои dart-классы — выложить их отдельный проектом и добавить в pubspec.yaml. Возможно, в будущем добавят поддержку.

Подход в построении дерева виджетов отличается от Flutter на Dart

Практически всегда имеет смысл создать функцию (как в примерах:2 от авторов), а не объявить класс с deftype (как я сделал тут:4). Для создания же StatefulWidget удобнее всего использовать макрос alpha/widget.

ClojureDart отличается от Clojure

В первую очередь, рекомендую прочесть доку от авторов.

Другое отличие, с которым вы обязательно столкнетесь, это отсутствие библиотек, которые бы переводили данные в старые-добрые кложуровские PersistentHashMap. В примере (3) с GraphQL я написал функцию для перевода дартовой Map в кложуровую PersistentHashMap.

Куда идти с вопросами?

Сообщество сидит в слеке clojurians, канал #clojuredart. Большую часть вопросов уже задали, и можно «загуглить» их в чате. Авторы активно помогают, отвечают на все вопросы. Можно даже залить проект на гитхаб, и попросить совета/помощи в чате. Кто-то обязательно посмотрит.

Полезные ресурсы

  1. Официальная документация по ClojureDart.

  2. Примеры кода от авторов.

  3. Пример приложения c GraphQL и TEA-архитектурой.

  4. Пример написания кастомных виджетов с deftype.

  5. Сообщество в Слеке — clojurians, канал #clojuredart

© Habrahabr.ru