[Из песочницы] Как мы готовим React, Require и Backbone

Как следует из официальной документации, React.js — V из MVC, и, как правило, вместе с ним применяются другие решения, в данном случае — Backbone.js и Require.js. А еще Jasmine, Karma и Grunt. Сегодня я поделюсь наброском проекта с применением этих инструментов.Ссылка для нетерпеливых.

ХотелкиПрозрачная структура проекта; Автоматизация всей рутинной работы; Автоматизация тестирования; Модульность; Повторное использования кода; Производительность. Чего добились Примерно так выглядит «дерево» проекта: . ├── app │ ├── app.js # Главный файл приложения │ ├── bower_components # Зависимости, описанные в bower.json │ │ └── … │ ├── index.html │ ├── scripts │ │ ├── controllers # Backbone контроллеры │ │ │ └── src │ │ │ ├── hello.jsx │ │ │ ├── main.jsx │ │ │ └── notfound.jsx │ │ ├── router.js # Конфигурация роутинга │ │ └── ui-components # React компоненты │ │ └── src │ │ └── panel │ │ ├── panel.jsx │ │ └── panel.less │ └── styles # Стили │ └── src │ └── main.less ├── bower.json # Описание зависимостей ├── Gruntfile.js ├── install-deps.bat # Скрипты, ├── install-deps.sh # устанавливающие ├── install-env.bat # зависимости ├── install-env.sh # и окружение ├── package.json # зависимости рабочего окружения node.js, на продакшене не нужны (Конечно, если серверная часть не на node.js) ├── server └── test # Тесты ├── test.config.js └── ui-components └── src └── panel.test.jsx А так код Подробно рассматривать весь исходный код не вижу смысла, для этого есть гитхаб, остановлюсь на ключевых моментах: /* * app/app.js * Только этот файл подключается в index.html, все остальное делает require * Описывает пути к файлам проекта и запускает роутинг (Backbone). */ 'use strict'; requirejs.config ({ baseUrl: './', paths: { app: './scripts', controllers: './scripts/controllers/dest', // dest — папки с результатами «компиляции» .jsx и .less ui: './scripts/ui-components/dest', // В системе контроля версий не хранятся underscore: './bower_components/underscore/underscore', backbone: './bower_components/backbone/backbone', jquery: './bower_components/jquery/dist/jquery.min', react: './bower_components/react/react' } }); Собственно, сам роутинг. Комментарии, думаю, излишни.

/* * app/scripts/router.js */ 'use strict'; define (function (require) { var Backbone = require ('backbone');

var AppRouter = Backbone.Router.extend ({ routes: { '': 'MainCtrl', 'hello/: name (/)': 'HelloCtrl', '*actions': 'NotFoundCtrl' },

MainCtrl: require ('controllers/main'), HelloCtrl: require ('controllers/hello'), NotFoundCtrl: require ('controllers/notfound') });

return new AppRouter (); }); В ui-components описываются обычные React-компоненты в синтаксисе .jsx и таблицы стилей для каждого отдельного компонента. Есть нечто общее с БЭМ. Каждый компонент лежит в отдельной папке и зависит только от самого React’а.

Не только компоненты интерфейса, но и контроллеры пишутся в синтаксисе .jsx, чтобы можно было сделать вот так:

/* * app/scripts/controllers/src/hello.jsx */ 'use strict'; define (['react', 'ui/panel/panel'], function (React, Panel){ /* Аргумент из строки запроса */ return function (name){ /* * Реализуем логику приложения, например, отправляя запрос к серверу. * А потом рендерим компонент (ы). */ React.render (

Hello, {name}!

, document.body); }; }); .Тесты Тестировать UI сложно, поэтому Facebook любезно предоставил TestUtils специально для тестирования React компонентов, тесты для которых могут выглядеть как-то так: Код, который мы будем тестировать. Компонент, который рисует bootstrap панель с заголовком и содержимым.

/* * app/scripts/ui-components/src/panel.jsx */ define (['react'], function (React){ 'use strict'; var Panel = React.createClass ({ render: function (){ return (

{this.props.title}

{this.props.children}
); } });

return Panel; }); А это — тесты для panel, написанные с применением Jasmine, можно использовать любой фреймворк который вам нравится, например, разработчики React используют Jest. Тесты запускаются при помощи Karma, к сожалению пока и не смог завести PhantomJS для этих тестов, так что приходится мириться с постоянно всплывающим хромом.

/* * test/ui-components/src/panel.test.jsx */ 'use strict'; define (['react', 'ui/panel/panel'], function (React, Panel) { describe ('Panel behaviour tests', function () { var TestUtils = React.addons.TestUtils; var panel; var p; /* * Аналог this.setUp () из xxxUnit */ beforeEach (function (){ panel = TestUtils.renderIntoDocument ((

Paragraph content

)); });

/* Проверяем что компонент вообще рендерится */ it ('Should render itself into DOM', function (){ expect (TestUtils.isCompositeComponent (panel)).toBe (true); });

/* И что заголовок, переданный атрибутом отображается */ it ('Should render title from props', function (){ var h1 = TestUtils.findRenderedDOMComponentWithTag (panel, 'h1'); expect (h1.getDOMNode ().innerHTML).toBe ('Test'); }); /* А также потомки никуда не исчезли */ it ('Should render children from props', function (){ var paragraph = TestUtils.findRenderedDOMComponentWithTag (panel, 'p'); /* * Specific react feature, it does not render text node directly, * but renders Paragraph content */ expect (paragraph.getDOMNode ().innerHTML).toContain ('Paragraph content'); });

}); }); Кстати, index.html выглядит довольно коротко и аккуратно:

React+Backbone

Автоматизация С ней прекрасно справляется grunt который «компилирует» less и jsx, прогоняет тесты, обновляет страничку в браузере при сохранении файлов и делает еще много прикольных вещей.Повторное использование и модульность В принципе, любой компонент UI можно просто взять и скопировать в другой проект, вместе со стилями и тестами (разумеется, там тоже нужен React). И он (компонент) заработает сразу, без лишних телодвижений. Особенно это актуально это для админок и типовых компонентов, там даже стили менять не надо.И зачем все это нужно? Во-первых, хотелось собрать все нужные инструменты в одном месте, чтобы они еще и работали. Во-вторых, я очень люблю React, использовать его с Backbone, наверное, стоит, оба легкие, шустрые и расширяемые, а Require может сделать структуру приложения прозрачнее. В-третьих получился (хочется верить) небольшой «шаблон» типового проекта, начиная разработку можно просто стянуть репозиторий и «всё сразу заработает ©».И что дальше? Всё и сразу пока не работает. В ближайших планах реализовать сборку проекта на продакшен, с минификацией всего, что можно минифицировать. В чуть более далеких — написание yoman генератора для скаффолдинга котроллеров и компонентов.

© Habrahabr.ru