Ранее уже была публикация, которая демонстрировала как использовать Symfony2 и RequireJS с помощью бандла HearsayRequireJSBundle. Способ имеет место быть, знаю из первого ряда, потому как принимал непосредственное участие в разработке второй версии этого бандла. Тем не менее, этот бандл не использую. Клиентскую часть чаще разрабатываю как SPA и нашел более простой способ, о нем и пойдет речь.
Главная идея способа состоит в том, чтобы поместить исходники клиентской части в публичную директорию, доступную из Web. В Symfony2 это директория web. Как результат, без каких-либо проблем можно очень просто настроить r.js оптимизатор, нужно лишь объяснить Symfony2 как отдавать исходники клиентской части в зависимости от окружения приложения и написать довольно простой конфиг для r.js оптимизатора.
Мы будем использовать Bower для установки необходимых JavaScript-зависимостей и gulp.js (возможен вариант Grunt, но мне больше нравится gulp.js) для сборки клиентской части, поэтому нам потребуются установленные Node.js и NPM.
Будем считать, что Bower и gulp.js уже установлены, теперь нам нужно добавить для них конфигурационные файлы, положим их в корень проекта:
bower.json
Выше мы указали, что нам нужен almond (легковесный AMD-загрузчик для prod окружения, замена для RequireJS), RequireJS и r.js оптимизатор.
package.json
Выше мы указали, что нам нужен gulp.js и yargs.
gulpfile.js
Выше мы указали следующие задачи:
Теперь нам нужно установить необходимые Node.js пакеты и JavaScript-зависимости, запустим для этого следующие команды:
Основные подготовительные работы окончены. Осталось объяснить Symfony2 как отдавать исходники клиентской части в зависимости от окружения приложения и написать довольно простой конфиг для r.js оптимизатора. Сделаем это следующим образом:
src/AppBundle/Resources/views/Default/index.html.twig
Добавим конфиг для RequireJS
web/app/main.js
Добавим конфиг для r.js оптимизатора
web/app/app.build.js
web/app/src/app.js
web/app/src/config.js
Для сборки клиентской части для prod окружения нужно добавить в деплой следующую команду:
Также не забываем добавить в .gitignore следующие строки:
Готово!
P.S. В репозитории symfony-standard на GitHub можно найти пример этого Hello-приложения.
Главная идея способа состоит в том, чтобы поместить исходники клиентской части в публичную директорию, доступную из Web. В Symfony2 это директория web. Как результат, без каких-либо проблем можно очень просто настроить r.js оптимизатор, нужно лишь объяснить Symfony2 как отдавать исходники клиентской части в зависимости от окружения приложения и написать довольно простой конфиг для r.js оптимизатора.
Мы будем использовать Bower для установки необходимых JavaScript-зависимостей и gulp.js (возможен вариант Grunt, но мне больше нравится gulp.js) для сборки клиентской части, поэтому нам потребуются установленные Node.js и NPM.
Будем считать, что Bower и gulp.js уже установлены, теперь нам нужно добавить для них конфигурационные файлы, положим их в корень проекта:
bower.json
{ "name": "symfony-standard-requirejs", "private": true, "ignore": [ "**/.*", "node_modules", "bower_components", "test", "tests" ], "dependencies": { "almond": "0.3.0", "requirejs": "2.1.15", "rjs": "2.1.15" } }
Выше мы указали, что нам нужен almond (легковесный AMD-загрузчик для prod окружения, замена для RequireJS), RequireJS и r.js оптимизатор.
package.json
{ "name": "symfony-standard-requirejs", "private": true, "dependencies": { "gulp": "3.8.8", "yargs": "1.3.2" } }
Выше мы указали, что нам нужен gulp.js и yargs.
gulpfile.js
var gulp = require('gulp'), exec = require('child_process').exec, argv = require('yargs').argv; gulp.task('copy', function () { // almond gulp.src('bower_components/almond/almond.js') .pipe(gulp.dest('web/app/vendor/almond')); // requirejs gulp.src('bower_components/requirejs/require.js') .pipe(gulp.dest('web/app/vendor/requirejs')); // rjs gulp.src('bower_components/rjs/dist/r.js') .pipe(gulp.dest('.')); }); gulp.task('rjs', function (cb) { var env = argv.env ? argv.env : 'dev', cmd = [ 'php app/console cache:clear --env=' + env, 'php app/console assets_version:increment --env=' + env, 'php app/console assetic:dump --env=' + env, 'node r.js -o web/app/app.build.js' ]; exec(cmd.join(' && '), function (err, stdout, stderr) { console.log(stdout); console.log(stderr); cb(err); }); }); gulp.task('build', ['copy', 'rjs']); gulp.task('default', ['build']);
Выше мы указали следующие задачи:
- copy — скопирует JavaScript-зависимости из директории bower_components в публичную директорию web/app/vendor
- rjs — очистит кеш Symfony2, инкрементирует версию ассетов для prod окружения (нужно не забыть установить бандл KachkaevAssetsVersionBundle), дампнет ассеты и запустит r.js оптимизатор
- build — алиас для задач, указанных выше
- default — алиас для задачи build
Теперь нам нужно установить необходимые Node.js пакеты и JavaScript-зависимости, запустим для этого следующие команды:
npm install bower install
Основные подготовительные работы окончены. Осталось объяснить Symfony2 как отдавать исходники клиентской части в зависимости от окружения приложения и написать довольно простой конфиг для r.js оптимизатора. Сделаем это следующим образом:
src/AppBundle/Resources/views/Default/index.html.twig
{% extends "AppBundle::layout.html.twig" %} {% block javascripts %} {% if app.environment == 'prod' %} <script src="{{ asset('app/dist/main.js') }}"></script> {% else %} <script>var require = {urlArgs: 'bust=' + (new Date()).getTime()};</script> <script data-main="app/main" src="{{ asset('app/vendor/requirejs/require.js') }}"></script> {% endif %} <script> requirejs.config({ config: { 'src/config': { user: { id: 1, username: 'John Doe' } } } }); </script> {% endblock %}
Здесь следует отметить, что клиентская часть имеет некоторую структуру в файловой системе и чтобы было меньше вопросов, вкратце о ней напишу. Исходники расположены в публичной директории web, а именно в директории web/app, которая имеет следующую структуру:
├── app.build.js ├── dist │ └── .gitkeep ├── main.js ├── specs │ └── .gitkeep ├── src │ ├── app.js │ └── config.js └── vendor
Добавим конфиг для RequireJS
web/app/main.js
requirejs.config({ baseUrl: 'app' }); require([ 'src/app', 'src/config' ], function (App, config) { App.start(config); });
Добавим конфиг для r.js оптимизатора
web/app/app.build.js
({ baseUrl: '.', mainConfigFile: 'main.js', wrapShim: true, name: 'vendor/almond/almond', include: 'main', out: 'dist/main.js', findNestedDependencies: true, preserveLicenseComments: false })
В файле example.build.js можно прочесть подробнее о каждом параметре.Давайте напишем простое Hello-приложение:
web/app/src/app.js
define([ ], function () { 'use strict'; var App = {}; App.start = function (config) { console.log('Hello, ' + config.user.username + '!'); }; window.App = App; return App; });
web/app/src/config.js
define([ 'module' ], function (module) { 'use strict'; return module.config(); });
Для Symfony2 могут потребоваться дополнительные правки в контроллере, в примере я использую Symfony Standard Edition.Откроем в браузере главную страницу приложения, в консоле браузера должно появится сообщение «Hello, John Doe!».
Для сборки клиентской части для prod окружения нужно добавить в деплой следующую команду:
npm install bower install gulp build --env=prod
Также не забываем добавить в .gitignore следующие строки:
/bower_components/ /node_modules/ /web/app/dist/ /web/app/vendor/ /r.js
Готово!
P.S. В репозитории symfony-standard на GitHub можно найти пример этого Hello-приложения.
