С момента публикации статьи Основы разработки на языке Elm (руководство по инструментарию для начинающих) прошло полтора года. За это время в инструментарии для языка разработки веб-интерфейсов Elm произошли многочисленные изменения: появилась более удобная система сборки с возможностью генерации нового проекта; для редактора Atom набор дополнений в некоторых отношениях теперь лучше, чем для популярного тогда среди разработчиков на Elm редактора LightTable; заработал инспектор состояния приложения. Давайте пройдёмся по этому набору на простом примере.
Базовые средства Elm
Elm можно установить как пакет NPM:
npm install -g elm
Есть и другие способы установить Elm. Они описываются в официальном руководстве.
Проверим версию только что установленного Elm:
elm --version
0.18.0
elm
является обёрткой для вызова отдельных утилит:
elm-make
: сборка кода на Elm;elm-package
: управление пакетами на Elm;elm-reactor
: утилита слежения за кодом на Elm для перекомпиляции и перезагрузки его в браузере;elm-repl
: REPL для Elm.
Управление кодом на Elm с помощью Brunch
Одним из удобнейших средств управления кодом на Elm представляется Brunch. Устанавливается Brunch как пакет NPM:
npm install -g brunch
Проверим версию только что установленного Brunch:
brunch --version
2.10.12
Вызовем Brunch для генерации кода нашего примера проекта на Elm:
brunch new --skeleton MattCheely/elm-brunch-skeleton demo-application
После генерации кода Brunch также сразу загрузит все необходимые NPM- и Elm-пакеты.
Рассмотрим сгенерированное дерево каталогов:
app\
: исходные тексты приложения
assets\
:index.html
: минимальный документ HTML5, который будет контейнером для нашего приложенияcss\
:style.css
: стили для примера приложенияelm\
: исходные тексты на ElmMain.elm
: главный модуль приложения на Elmjs\
: код на JavaScriptapp.js
: пример кода, работающего отдельно от кода на Elm
elm-stuff\
: загруженные пакеты на Elmnode_modules\
: загруженные NPM-пакеты.gitignore
README.md
brunch-config.js
: настройки для Brunch с учётом поддержки Elmelm-packages.json
: настройки для Elm, в том числе список используемых пакетовpackage-lock.json
: список зависимостей NPM (сгенерирован NPM автоматически)package.json
: настройки для NPM
Уже сейчас мы можем собрать наш проект:
cd demo-application
npm build
После сборки проекта появится также папка public
, в которой разместятся все части нашего веб-приложения.
Давайте запустим приложение в режиме отладки:
npm start
Откроем в браузере ссылку http://localhost:3333/
и полюбуемся на прекрасное веб-приложение:
В правом нижнем углу находится интерфейс инспектора состояния приложения. Щёлкнем на нём. Сейчас счётчик value
имеет значение 0
:
Пощёлкаем на кнопках +1
и -1
и понаблюдаем как меняется состояние:
Мы можем вернуться к любому предыдущему состоянию:
И даже вернуться к последнему, просто нажав на кнопку Resume
.
Неискушённому зрителю читателю наверное будет интересно также узнать, как устроено приложение на Elm, но сначала давайте настроим редактор, чтобы изучать исходный код приложения было приятней и удобней.
Настройка Atom для работы с Elm
Поддержка разработки на Elm есть для многих редакторов, однако здесь мы рассмотрим только один, Atom, так как на взгляд автора для него существует самый функциональный набор дополнений, облегчающий работу с Elm. Будем исходить из того, что Atom у вас уже установлен (хотя, подскажу откуда его можно загрузить).
Перво наперво установим дополнение language-elm:
apm install language-elm
Это дополнение предоставит базовую поддержку Elm, такую как синтаксическая подсветка кода.
Для поддержки переходов к определениям и всплывающим подсказкам с типами выражений установим пакет atom-ide-ui.
apm install atom-ide-ui
Для поддержки автодополнения поставим autocomplete-plus:
apm install autocomplete-plus
Если используете сокращённый набор кода, поставьте snippets:
apm install snippets
Наконец мы готовы установить Elmjutsu:
apm install elmjutsu
Теперь мы можем открыть наш проект в Atom:
Для руководства по настройке и функциям Elmjutsu обязательно зайдите на страничку этого дополнения, и не забудьте задать все необходимые параметры в Atom.
Дополнительный, но важный инструментарий
Пожалуй самый важный инструмент из дополнительных это elm-format. С помощью этой утилиты можно приводить внешний вид программы к стандартному (общепринятому) виду. Установим его:
npm install -g elm-format
Также установим соответствующее дополнение для Atom elm-format:
apm install elm-format
Благодаря этому дополнению, каждый раз, как мы будем сохранять наш код, elm-format будет его форматировать. Если в коде будет синтаксическая ошибка, то утилита её обнаружит, и мы об этом узнаем, хотя, для выяснения наличия ошибок всё же лучше использовать компилятор. А в этом нам будет помогать дополнение для Atom linter-elm-make.
Поставим его:
apm install linter
apm install linter-elm-make
Не забудьте также зайти в настройки этих дополнений и задать все необходимые параметры.
Дополнение elm-lens показывает прямо в коде для функций и типов экспонируются ли они или являются локальными, а также сколько раз на них ссылаются. Для установки дополнения просто вызовите:
apm install elm-lens
Для поддержки REPL в Atom можно установить дополнение elm-instant:
apm install elm-instant
Если вы хотите работать с терминалом прямо в Atom, рекомендую установить дополнение platformio-ide-terminal:
apm install platformio-ide-terminal
Поэкспериментируем
Для начала откроем окно терминала в Atom, нажав кнопку +
в нижней части окна, и запустим слежение за нашим кодом на Elm:
npm start
Давайте внесём ошибку в код:
Можно заметить, что во-первых ошибка была обнаружена без ручного запуска компиляции, во-вторых были предложены варианты для исправления ошибки.
Для непосвящённых
Как и обещал, немного расскажу, как устроен код приложения на Elm. Давайте взглянем на тот исходный код, который нам сгенерировал Brunch:
module Main exposing (main)
import Html exposing (Html, text, div, button)
import Html.Attributes exposing (class)
import Html.Events exposing (onClick)
main : Program Never Model Msg
main =
Html.beginnerProgram
{ model = initalModel
, update = update
, view = view
}
-- Model
type alias Model =
{ value : Int
}
initalModel : Model
initalModel =
{ value = 0
}
-- Update
type Msg
= Increment
| Decrement
update : Msg -> Model -> Model
update msg model =
case msg of
Increment ->
{ model | value = model.value + 1 }
Decrement ->
{ model | value = model.value - 1 }
-- View
view : Model -> Html Msg
view model =
div []
[ div [ class "counter" ]
[ text (toString model.value) ]
, div [ class "controls" ]
[ button [ onClick Increment ] [ text "+1" ]
, button [ onClick Decrement ] [ text "-1" ]
]
]
Приложение на Elm оформляется как модуль Main
, экспонирующий функцию main
. Это мы видим в первой строке кода. Далее идёт импорт модулей. Некоторые модули импортируются по умолчанию, но модули Html
, Html.Attributes
и Html.Events
нужно импортировать. Здесь они импортируются с экспонированием отдельных функций и типов. Это делается, чтобы не квалифицировать имя модуля, например, вместо Html.Attributes.class
будем писать просто class
.
Ниже объявляется и определяется функция main
. В объявлении задаётся её тип. Тип функции указывается после символа :
, определение происходит после знака =
. Как увидим ниже, указание имён параметров и их типов осуществляется раздельно. Elm поддерживает вывод типов, однако для функций верхнего уровня хорошим тоном считается ручное указание типа.
В нашем случае функция main
вызывает функцию Html.beginnerProgram
, которая получает на вход структуру с тремя полями: model
, update
, view
. Эта функция запустит цикл обработки сообщений. Параметр model
получает начальное состояние приложения, которое задано в функции initialModel
. Функция update
вызывается всякий раз, когда происходит какое-то событие и передаётся соответствующее сообщение. После обработки сообщения вызывается функция view
, занимающаяся формированием нового дерева DOM.
Далее определяется тип Model
, точнее синоним типа структуры, состоящей из поля value
типа Int
. Тип Int
, как нетрудно догадаться, представляет целые числа.
Как уже было сказано, функция initialModel
возвращает начальное значение состояния, которое содержит одно поле value
со значением 0
. Типом состояния может быть любой тип, не только структура.
Далее определяется тип сообщения Msg
. Это тип-перечисление с двумя возможными значениями: Increment
и Decrement
.
Функция update
получает на вход сообщение и состояние приложения. Обычно код этой функции включает в себя оператор сопоставления с образцом case .. of ..
. Здесь происходит изменение состояния в зависимости от пришедшего сообщения: значение поля value
либо увеличивается на 1
, либо уменьшается на 1
.
Наконец, функция view
принимает состояние приложения и формирует с помощью функций модулей Html
, Html.Attributes
и Html.Events
требуемое дерево DOM.
Установка дополнительных пакетов Elm
И последнее, но не менее важное: чтобы установить дополнительные пакеты Elm, нужно вызвать команду elm-package
. Например, установим пакет elm-community/list-extra
:
elm package install elm-community/list-extra
Обратите внимание, что идентификатор пакета состоит из двух частей, то есть не просто list-extra
, а elm-community/list-extra
.
С этой командой связан файл проекта elm-package.json
. В него записываются названия и версии устанавливаемых пакетов в разделе dependencies
. Например, сгенерированный Brunch файл elm-package.json
выглядит так:
{
"version": "1.0.0",
"summary": "helpful summary of your project, less than 80 characters",
"repository": "https://github.com/user/project.git",
"license": "BSD3",
"source-directories": ["app/elm"],
"exposed-modules": [],
"dependencies": {
"elm-lang/core": "5.0.0 <= v < 6.0.0",
"elm-lang/dom": "1.1.1 <= v < 2.0.0",
"elm-lang/html": "2.0.0 <= v < 3.0.0"
},
"elm-version": "0.18.0 <= v < 0.19.0"
}
Репозиторий пакетов можно просматривать здесь.
Что дальше
Пожалуй лучший источник информации об Elm это его родной сайт:
Вероятно стоит также перечитать статью Основы разработки на языке Elm (руководство по инструментарию для начинающих).
Опрос
Как и в прошлый раз проведу опрос, но немного его переориентирую, если можно так сказать. Ведь в прошлый раз автор приглашал к опросу только тех, кто уже программирует на функциональных языках, теперь же аудитория расширяется до всех, кто разрабатывает веб-приложения.
Подведу также итоги прошлого опроса. Итак, на вопрос "Если Вы программируете на функциональных языках, то каково Ваше мнение об Elm" расклад был получен такой:
- 28.2%: первый раз слышу, но выглядит годным
- 21.1%: не нужен
- 20.5%: годный, я на нём уже программирую
- 15.8%: сыроват для продакшн
- 14.1%: годный, но писать на нём не собираюсь
Проголосовало 170, воздержалось 147. Прочитало статью 13,9k, добавило в закладки 51.
Интересно, наверное, будет сравнить с результатами голосования, зафиксированными автором через неделю после публикации той статьи:
- 31%: не нужен
- 18%: первый раз слышу, но выглядит годным
- 18%: сыроват для продакшн
- 18%: годный, но писать на нём не собираюсь
- 15%: годный, я на нём уже программирую
Проголосовало 99, воздержалось 76. Прочитало статью 5,5k, добавило в закладки 41.
Заметен рост благосклонности к Elm, существенно уменьшилось число тех, кто считал, что Elm не нужен, также заметно выросло число тех, кто на нём уже программирует. При этом также увеличилось число тех, кто считает язык годным, но писать на нём не собирается.
Сообщество
С момента публикации прошлой версии статьи (30 мая 2016) существует рускоязычное сообщество во Вконтакте. Число участников сообщества на момент написания этой статьи 179. Присоединяйтесь!
Ссылки
© Симоненко Евгений, 2018
Комментарии (11)
j_wayne
29.01.2018 15:27Я — бэкендер, который был вынужден также тащить и фронтенд. Фуллстек разработчиком себя не считаю в виду слабого знания фронтенда (и невеликой любви к нему, если честно).
Когда мне стало недоставать реактивности, я решил вместо своего привычного coffescript/jquery лапшекода, одну фичу переписать на чем-то ином. Сначала я пытался ее написать на react/redux, потом на elm и успешно написал лишь на vue.js.
Elm концептуально очень красив! React/redux в одной платформе, да еще и с проверками при компиляции… Но требует слишком больших усилий в моем случае. На react/redux я пожалуй фичу бы дописал, но не видел смысла, получалось очень страшно и громоздко.
Я не хочу сказать, что эти инструменты плохие. Это скорее я. Но они явно не для случая «accidental frontend developer».
Особенные трудности были с «нечистыми» штуками, такими, как drag and drop и уже имеющимися в проекте JS библиотеками (календари, пикеры, и пр.). Вообще, в Elm той версии был какой-то интероп с ними, но работать со всем этим мне было грустно. Также это был переходной момент (то ли от 16 к 17 версии, то ли от 17 к 18, при переходе много чего убрали/сломали, но не добавили/починили).
Еще, смущал как jsx, так и html в виде кода в Elm (у меня был отдельный верстальщик).
Не флейма ради, реально интересует этот вопрос… Получается, что для идиллии, нужно использовать только Elm-библиотеки либо писать виджеты самому?easimonenko Автор
29.01.2018 15:48Спасибо за комментарий! Всё так. Да, с готовым кодом на JavaScript он плохо сочетается. Поэтому вся надежда на развитие базы родных для Elm пакетов. На мой взгляд Elm хорошо подходит для разработки SPA, с учётом, что текущих возможностей будет достаточно, либо готовы писать какие-то вещи с нуля или писать нативные модули для использования кода на JavaScript.
potan
29.01.2018 17:43Я тоже бэкендер, но начал писать странички для отладки и внутреннего использования на Elm. Единственное неудобство, с которым я сталкнулся — приходится разбираться в css (все больше склоняюсь к тому, что бэкендер этого понять не может).
С js раньше сталкивался практически только как со встроенным языком в cwl, когда проходил курс на stepic. Этого мне вполне хватило, что бы я решил с ним по возможности не связываться.j_wayne
30.01.2018 13:50Вот то-то и оно, слишком много специфических прикладных знаний надо. Разные версии браузеров и т.п. Есть причины делегировать верстку верстальщику. Но чтобы он еще jsx или Elm.Html умел… утопия(
kklaustrum
30.01.2018 13:40+2Получается, что для идиллии, нужно использовать только Elm-библиотеки либо писать виджеты самому?
Есть проект порта material design на elm с неплохими демо --> debois.github.io/elm-mdl — это к вопросу о «писать виджеты самому». Другое дело, что стоит сделать шаг в сторону для ещё доков, как примеры работы с elm-mdl остаются до сих пор для v0.17, а не v0.18.
Еще, смущал как jsx, так и html в виде кода в Elm (у меня был отдельный верстальщик)
Можно не верстать прямо elm-кодом (хотя свои плюсы у такого подхода найдутся со временем), а попробовать этот сервис по переводу из «обычной» верстки --> mbylstra.github.io/html-to-elm/
Но со временем, в той или иной степени, наверно правильнее отдавать всё бОльшую и бОльшую часть верстки в elm-экосистему. Ставя с elm packages штуки вроде rtfeldman/elm-css/latest и пр. Просто иначе elm не раскроется, как мне кажется. Раз уж пал выбор на новую экосистему, то вытягивать из неё по максимуму, а не чуть-чуть.easimonenko Автор
30.01.2018 13:46+1Есть проект порта material design на elm с неплохими демо --> debois.github.io/elm-mdl — это к вопросу о «писать виджеты самому».
Использую в одном своём проекте. Хорош, если нужен сложный интерфейс, и хочешь, чтобы как в Android. В тоже время есть поддержка Bootstrap: http://elm-bootstrap.info/ https://github.com/rundis/elm-bootstrap
potan
30.01.2018 17:55У меня с elm-mdl возикли проблемы с tooltip при появлении горизонтального скролинга.
Не уверен, что смогу с ними справиться, если освою css, но есть желание попробовать.
easimonenko Автор
30.01.2018 15:49Еще, смущал как jsx, так и html в виде кода в Elm (у меня был отдельный верстальщик).
Кстати, для вставки готового HTML можно использовать пакет http://package.elm-lang.org/packages/evancz/elm-markdown/latest
j_wayne
30.01.2018 15:50А это работает с реактивностью?
easimonenko Автор
30.01.2018 15:54Вроде нет. Может быть и есть способ покопаться в DOM, но мне не надо было.
easimonenko Автор
Уважаемые читатели, если вы знаете полезные инструменты разработчика на Elm, не упомянутые в этой статье, поделитесь информацией. Интересно также узнать от разработчиков на Elm, почему вы используете другие среды разработки, отличные от Atom и LightTable? Ну и, если обнаружите какие-либо грамматические и смысловые ошибки в статье, пишите, постараюсь исправить.