- PVSM.RU - https://www.pvsm.ru -
В этой статье, я хотел бы рассказать об альтернативном способе организации фронтенда для приложений на Ruby on Rails. В основном я работаю на бэкенде, но время от времени появляются задачи на фронтенде и то, что зачастую приходится там видеть, не внушает никакого оптимизма для дальнейшей работы.
Каждый разработчик на свое усмотрение организовывает файловую структуру для хранения CSS и JavaScript кода, для HTML представлений у Rails есть кое-какие соглашения [1]. Возможно кому-то приходилось сталкиваться с приложениями в которых CSS и JavaScript ограничиваются чуть ли не единственными application
файлами, тогда содержимое этих файлов может представлять из себя даже не "портянки", а целые "простыни" кода. С представлениями тоже не все просто, особенно это касается partials
, когда они используются для создания отдельных UI компонент: модальных окон, меню, подвалов и т.д. Порой надо сильно исхитриться, чтобы использовать такой UI компонент в разных представлениях с разными параметрами и/или логикой.
В итоге получается, что CSS, JavaScript, HTML представления и UI компоненты (на основе partials
) лежат в разных каталогах и каждая технология имеет свою файловую структуру. При таком подходе, фронтенд в средних и больших приложениях тяжело поддерживать, из всех этих технологий получается очень гремучая смесь, которая может просто [2] рвануть в любой неподходящий момент.
В идеале хотелось, чтобы фронтенд состоял из отдельных UI компонент и имел понятную файловую структуру. Для решения подобных проблем уже давно существует методология БЭМ [3], поэтому именно она была взята за основу при создании гема Bemer [4].
Bemer позволяет:
Более подробную информацию можно найти здесь [5].
Файловая структура для UI компонент [6] отличается от той, которая используется в методологии БЭМ [7]. Каждый UI компонент имеет свой каталог, но файлы технологий называются index
(индексные файлы):
Пример файловой структуры при использовании Sprockets [8].
app/
├── assets/
| ├── javascripts/
| | └── application.coffee
| └── stylesheets/
| └── application.scss
├── bemer_components/
| ├── modal/
| | ├── index.html.slim
| | ├── index.bemhtml.slim
| | ├── index.coffee
| | └── index.scss
| └── ...
└── ...
Пример файловой структуры при использовании Webpacker [9].
app/
├── javascript/
| ├── bemer_components/
| | ├── modal/
| | | ├── index.html.slim
| | | ├── index.bemhtml.slim
| | | ├── index.coffee
| | | └── index.scss
| | └── ...
| ├── packs/
| | ├── application.js
| | └── ...
| └── ...
└── ...
С помощью Bemer-a можно создавать различного вида UI компоненты [10]. В этом примере будет рассмотрен способ, при котором можно использовать BEMHTML шаблоны. За основу будет взят компонент Modal из Bootstrap [11], со следующей HTML структурой:
<div class="modal fade" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title">Modal title</h4>
</div>
<div class="modal-body">
<p>Modal body</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
В начале, необходимо создать структуру (дерево) компонента с помощью хелпера define_component
(только для такого рода UI компонент можно использовать BEMHTML шаблоны). Возможный вариант структуры (дерева) компонента Modal:
/ Содержимое файла app/bemer_components/modal/index.html.slim
= define_component bem_cascade: false, tag: :div do |component|
= component.block :modal, cls: 'modal fade', role: :dialog, tabindex: -1 do |modal|
= modal.elem :dialog, role: :document, cls: 'modal-dialog'
= modal.elem :content, cls: 'modal-content'
= modal.elem :header, cls: 'modal-header'
= component.block :close, type: :button, tag: :button, cls: 'close', 'data-dismiss': :modal
span aria-hidden='true' ×
= modal.elem :title, tag: :h4, cls: 'modal-title'
= modal.elem :body, cls: 'modal-body'
= modal.elem :footer, cls: 'modal-footer'
Структура (дерево) компонента состоит из блоков и элементов (узлов), они выступают в роли меток, используя которые, можно изменять компонент с помощью BEMHTML шаблонов, а также получать css классы из методологии БЭМ. В данном случае, генерация данных из методологии БЭМ не нужна, поэтому ее можно отключить с помощью параметра bem_cascade: false
.
Теперь, в любом представлении можно вызвать компонент Modal и применить к нему необходимые BEMHTML шаблоны:
/ Кнопка для показа модального окна
button.btn.btn-primary.btn-lg data-target="#my-modal" data-toggle="modal" type="button"
| Launch demo modal
/ Вызов компонента Modal и применение BEMHTML шаблонов
= render_component :modal do |template|
= template.block :modal do |modal|
= modal.add_attrs id: 'my-modal'
= modal.specify(elem: :dialog).add_cls 'modal-lg'
= modal.specify(elem: :title).content 'Modal title'
= modal.specify(elem: :body).content
p Modal body
= modal.specify(elem: :footer).content
button.btn.btn-default data-dismiss="modal" type="button" Close
button.btn.btn-primary type="button" Save changes
/ Эквивалентный результат
= render_component :modal do |template|
= template.block(:modal).add_attrs id: 'my-modal'
= template.elem(:dialog).add_cls 'modal-lg'
= template.elem(:title).content 'Modal title'
= template.elem(:body).content
p Modal body
= template.elem(:footer).content
button.btn.btn-default data-dismiss="modal" type="button" Close
button.btn.btn-primary type="button" Save changes
Перед использованием в своих проектах, внимательно ознакомьтесь с документацией [5] и исходным кодом [4], чтобы понимать все плюсы и минусы данного подхода.
Возможно кому-нибудь Bemer поможет:
Rails >= 3.2.22
)В заключении, хочу сказать спасибо всей команде БЭМ-а за быструю обратную связь и в частности tadatuta [13] и miripiruni [14] за развернутые ответы на вопросы по методологии БЭМ и шаблонизатору bem-xjst [15].
Автор: stiverb
Источник [18]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/ruby/277172
Ссылки в тексте:
[1] есть кое-какие соглашения: http://rusrails.ru/layouts-and-rendering-in-rails#rendering-po-umolchaniyu-soglasheniya-po-konfiguratsii-v-deystvii
[2] просто: https://habrahabr.ru/post/348406/
[3] методология БЭМ: https://ru.bem.info/methodology/
[4] Bemer: https://github.com/vill/bemer
[5] здесь: https://github.com/vill/bemer/wiki
[6] Файловая структура для UI компонент: https://github.com/vill/bemer/wiki/%D0%A4%D0%B0%D0%B9%D0%BB%D0%BE%D0%B2%D0%B0%D1%8F-%D1%81%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%B0
[7] используется в методологии БЭМ: https://ru.bem.info/methodology/filestructure/
[8] Sprockets: https://github.com/rails/sprockets-rails
[9] Webpacker: https://github.com/rails/webpacker
[10] различного вида UI компоненты: https://github.com/vill/bemer/wiki/%D0%A1%D0%BE%D0%B7%D0%B4%D0%B0%D0%BD%D0%B8%D0%B5-%D0%B8-%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-UI-%D0%BA%D0%BE%D0%BC%D0%BF%D0%BE%D0%BD%D0%B5%D0%BD%D1%82
[11] компонент Modal из Bootstrap: https://getbootstrap.com/docs/3.3/javascript/#modals
[12] bemer-bootstrap: https://github.com/vill/bemer-bootstrap
[13] tadatuta: https://habrahabr.ru/users/tadatuta/
[14] miripiruni: https://habrahabr.ru/users/miripiruni/
[15] шаблонизатору bem-xjst: https://github.com/bem/bem-xjst
[16] Пример приложения: https://github.com/vill/bemer-example
[17] Organizing large Rails projects with namespaces: https://blog.makandra.com/2014/12/organizing-large-rails-projects-with-namespaces/
[18] Источник: https://habrahabr.ru/post/352938/?utm_campaign=352938
Нажмите здесь для печати.