...

вторник, 29 апреля 2014 г.

Наследование HTML файлов в xslt-стиле

Проблема




Однажды, в ходе переписывания большого проекта, возникла необходимость улучшить механизм кастомизации html шаблонов под разные версии нашего web-приложения. В старой версии кастомизация выглядела подобным образом:

{{if app.version==versions.main}}
<!--один html код-->
{{else if app.version==versions.custom1}}
<!--другой html код-->
{{else if app.version==versions.custom2}}
<!--и ещё html код-->
{{endif}}




И подобной лапшой был пронизан весь проект. Такой код сложно поддерживать и изменять, при активном использовании шаблоны превращаются в непонятную кашу, где бизнес логика отображения отдельных блоков переплетается с кастомизацией под разные версии.

Привыкнув к удобным методам управления версиями приложения с помощью инъекции зависимостей, когда в зависимости от версии используются разные реализации интерфейсов, я решил изобрести свой велосипед для XSLT-подобного управления версиями html файлов: grunt-html-inheritance. Он позволяет подменять кусочки базового html-файла с помощью маленьких патчей.



При переписывании проекта в качестве фреймворка был выбран AngularJS, поэтому вёрстка в приложении хранится в виде множества html файлов, подгружаемых при необходимости, что позволило легко внедрить систему сборки этих файлов с кастомизацией под разные версии приложения.


Пример




Давайте представим, что у нас имеется следующий кусок вёрстки в HTML файле «myfile.html»:

<div>
Blah blah blah
<div>Main version</div>
</div>


И, как часто бывает в разных версиях приложения, нам понадобилось, чтобы в версии «myversion» вместо одного текста «Main version» отображался другой: «My version». Чтобы сделать это с помощью html-inheritance, нужно сделать 2 простых шага:


1. Добавить к кастомизируемому тегу аттрибут, начинающийся на «bl-»:


<div>
Blah blah blah
<div bl-mytag>Main version</div>
</div>


2. Создать файл «myfile.myversion.html» с патчем к родительскому файлу:


<div bl-mytag="replace">Custom version</div>


Всё! При билде проекта все html файлы будут аккуратно сложены в указанную папку с разбивкой по версиям:



dist
|
main/
myfile.html
myversion/
myfile.html



Теперь достаточно указать вашему приложению, откуда грузить html файлы в зависимости от версии, и всё будет работать само по себе!

Установка




Чтобы добавить grunt-html-inheritance в ваш проект, нужно установить npm модуль командой

npm install grunt-html-inheritance --save-dev



или добавить зависимость в package.json, загрузить задачу в Gruntfile.js командой

grunt.loadNpmTasks('grunt-html-inheritance');



и настроить задачу следующим образом:


grunt.initConfig({
html_inheritance: {
main: {
files: {
src: "**.html" //селектор для файлов
},
options: {
modules: ["version1", "version2"], //список модулей
dstDir: "../dist", //папка, в которую будут складываться скомпиленные файлы
},
},
},
});




В AngularJS приложении важным условием легкого переключения между версиями HTML файлов является использование хелпера для построения путей к файлам шаблонов вместо жёсткого прописывания этих путей в директивах и роутингах.

Преимущества




Самое интересное преимущество такой системы кастомизации — основную версию проекта можно использовать без компиляции html файлов, так как bl-аттрибуты не мешают браузеру отображать исходный файл. Так же для использования такого метода не нужно изучать новый синтаксис какого-либо шаблонизатора, вся логика реализуется с помощью обычных html-аттрибутов, знакомых каждому разработчику.

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




Кроме замены базового тега в патче, описанного в примере выше, так же доступны следующие режимы:


  1. Удаление — удаление в патче родительского элемента

  2. Вставка — вставка в патче элемента, тогда как в основной версии элемента не будет

  3. Модификация аттрибутов — удаление и добавление аттрибутов к родительскому элементу, удаление и добавление классов.




Полная документация доступна на странице пакета или в репозитории на github. Модуль покрыт тестами и нуждается в дальнейшем совершенстовании. Приглашаю сообщество помочь в развитии, присылайте pull-реквесты!

This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


Комментариев нет:

Отправить комментарий