Symfony: Webpack Encore — плагин для управления ресурсами

    Позавчера обнаружил новость о том, что команда Symfony выпустила плагин Webpack Encore для интеграции замечательного инструмента Webpack в ваше приложение. Если вы не знакомы с Webpack, то я настоятельно рекомендую ознакомиться с ним, так как он возможно решит множество вопросов связанных с управлением ресурсами в вашем проекте. В любом случае даже если вы не собираетесь его использовать, знать о том что он существует будет крайне полезным. Очень хорошо этот инструмент описан тут.

    Вступление


    В свое время я опробовал множество разных подходов и инструментов для управления ресурсами. Как правило для каждого проекта приходилось выбирать, в зависимости от сложности структуры, разные решения. Но какое решение я бы не выбрал у меня всегда оставалось ощущение некоторой неудовлетворенности. Всегда оставался либо какой-то костыль, либо приходилось подстраиваться под решение.

    Два дня назад я попробовал плагин для Symfony проекта Webpack Encore. Всего два дня и возможно через некоторое время я изменю свое мнение по поводу этого плагина, но сейчас находясь под впечатлением я хочу показать вам те возможности, которые он предлагает.

    Необходимые инструменты


    Вам потребуется какой-либо тестовый проект на Symfony >= 3.3, NodeJS и менеджер пакетов Yarn. Вы можете использовать Npm, но в данном посте примеры будут с использованием Yarn.

    Для теста мы будем подключать к проекту FontAwesome, Jquery, Bootstrap и какие-то свои выдуманные ресурсы.

    Установка


    Сначала установим плагин Webpack Encore. В корне приложения:

    yarn add @symfony/webpack-encore --dev
    

    Мы будем использовать SASS, поэтому добавим пару пакетов:

    yarn add sass-loader node-sass --dev
    

    Не забудьте добавить в .gitignore каталог node_modules.

    Подготовка ресурсов


    Я создам в корне приложения каталог assets/ куда положу все необходимые ресурсы. В результате мой каталог будет выглядеть так:

    +-assets/
    ---+ dist/
    ------+ fontawesome/
    ------+ jquery/
    ------+ bootstrap/
    

    Дополнительно я создам в корне assets/ файл app.scss, который будет главным файлом ресурсов. Вовсе не обязательно иметь каталог dist с библиотеками, их можно установить с помощью Yarn. Я выбрал такой путь для большей наглядности.

    Теперь необходимо создать инструкции для плагина. Для этого в корне приложения создадим файл webpack.config.js со следующим содержимым:

    /* подключим плагин */
    var Encore = require('@symfony/webpack-encore');
    
    Encore
       /* Установим путь куда будет осуществляться сборка */
       .setOutputPath('web/build/')
       /* Укажем web путь до каталога web/build */
       .setPublicPath('/build')
       /* Каждый раз перед сборкой будем очищать каталог /build */
       .cleanupOutputBeforeBuild()
       /* Добавим наш главный файл ресурсов в сборку */
       .addStyleEntry('styles', './assets/app.scss')
       /* Включим поддержку sass/scss файлов */
       .enableSassLoader()
       /* В режиме разработки будем генерировать карту ресурсов */
       .enableSourceMaps(!Encore.isProduction());
    
    /* Экспортируем финальную конфигурацию */
    module.exports = Encore.getWebpackConfig();
    

    Теперь можно заняться ресурсами. Отредактируем наш файл app.scss:

    @import "dist/fontawesome/css/font-awesome";
    @import "dist/bootstrap/css/bootstrap";
    /* Тут можно определить свои стили или подключить собственные библиотеки */
    

    Запускаем билд. В корне приложения:

    ./node_modules/.bin/encore dev
    

    Если все прошло гладко, вы увидите в каталоге web/build файл styles.css, а так же папку fonts, куда скопированы все шрифты font-awesome на которые ссылается font-awesome.css. Если вы прописали какие-то свои стили, которые используют изображения, то эти изображения так же подтянутся в папку web/build/images. В результирующих файлах стилей все пути соответственно будут переписаны.

    Благодаря сгенерированным картам ресурсов, мы можем комфортно использовать отладчик в браузере. Помимо стилей, в каталоге web/builds появится файл manifest.json, о нем чуть позже.

    Сейчас необходимо подключить JavaScript, который нам необходим. Для этого добавим в каталог assets/ файл app.js со следующим содержимым:

    var $ = require('./dist/jquery/jquery-3.2.1');
    require('./dist/bootstrap/js/bootstrap');
    

    Теперь отредактируем немного наш файл webpack.config.js:

    /* подключим плагин */
    var Encore = require('@symfony/webpack-encore');
    
    Encore
       /* Установим путь куда будет осуществляться сборка */
       .setOutputPath('web/build/')
       /* Укажем web путь до каталога web/build */
       .setPublicPath('/build')
       /* Каждый раз перед сборкой будем очищать каталог /build */
       .cleanupOutputBeforeBuild()
    
       /* --- Добавим основной JavaScript в сборку --- */
       .addEntry('scripts', './assets/app.js')
    
       /* Добавим наш главный файл ресурсов в сборку */
       .addStyleEntry('styles', './assets/app.scss')
       /* Включим поддержку sass/scss файлов */
       .enableSassLoader()
       /* В режиме разработки будем генерировать карту ресурсов */
       .enableSourceMaps(!Encore.isProduction());
    
    /* Экспортируем финальную конфигурацию */
    module.exports = Encore.getWebpackConfig();
    

    Теперь перезапустим сборку:

    ./node_modules/.bin/encore dev
    

    Если все прошло гладко, вы получите файл scripts.js в каталоге web/builds.

    У вас может возникнуть проблема со скриптами, которые ожидают, что JQuery будет доступен глобально. Когда вы делаете var $ = require(some.js), то просто подключаете скрипт в текущий контекст, а не глобально. Поэтому скрипты, которые вы определяете в шаблонах, а так же некоторые другие библиотеки, ожидающие глобального JQuery работать не будут.

    Есть несколько вариантов решения проблемы. Для всех пакетов, которые вы подключаете через require, обеспечить доступ к $ или JQuery, можно добавив в файл webpack.config.js такую инструкцию:

    /* подключим плагин */
    var Encore = require('@symfony/webpack-encore');
    
    Encore
       /* Установим путь куда будет осуществляться сборка */
       .setOutputPath('web/build/')
       /* ... */
      
       .autoProvidejQuery()
    
       /* В режиме разработки будем генерировать карту ресурсов */
       .enableSourceMaps(!Encore.isProduction());
    
    /* Экспортируем финальную конфигурацию */
    module.exports = Encore.getWebpackConfig();
    

    Теперь все в порядке, однако скрипты, которые вы определяете в шаблонах по прежнему не будут видеть JQuery. В таком случае вероятно вам понадобится вручную добавить библиотеку в глобальную область видимости. Для этого отредактируем файл app.js:

    var $ = require('./dist/jquery/jquery-3.2.1');
    global.$ = global.jQuery = $;
    require('./dist/bootstrap/js/bootstrap');
    

    Еще раз запустим сборку и теперь у нас все очень компактно упаковано, разложено по каталогам, мы имеем один файл стилей и один файл скриптов. Все зависимости (шрифты, картинки) скопированы в соответствующие места.

    Включение версионирования:


    /* webpack.config.js */
    // ...
    .enableVersioning()
    // ...
    

    Если вы включили данную функцию, то вам потребуется внести некоторые настройки в конфигурацию вашего Symfony проекта:

    # app/config/config.yml
    framework:
        # ...
        assets:
            # Функционал доступен начиная с Symfony 3.3
            json_manifest_path: '%kernel.project_dir%/web/build/manifest.json'
    

    Файл manifest.json, хранит карту соответствия файлов ресурсов их версионным аналогам. Теперь подключая в вашем Twig шаблоне стиль:

    <link href="{{ asset('build/styles.css') }}" rel="stylesheet" />
    

    на самом деле будет подключен файл вида: build/styles.c1a32e.css

    Подключение стилей через JavaScript:


    Вы вполне можете себе позволить импортировать файлы стилей через JavaScript. На примере нашего проекта можно было бы сделать так в app.js:

    require('./app.scss');
    
    var $ = require('./dist/jquery/jquery-3.2.1');
    global.$ = global.jQuery = $;
    require('./dist/bootstrap/js/bootstrap');
    

    В этом случае, в webpack.config.js не нужно добавлять addStyleEntry. После сборки автоматически будет создан js файл и одноименный css файл со всеми запрошенными стилями в данном скрипте.

    Деплой


    Достаточно холиварная тема, но я все-таки затрону ее. Если вы предпочитаете производить сборку на стороне сервера, тогда вам стоит добавить в .gitignore каталог web/build и на продакшн сервере выполнять:

    ./node_modules/.bin/encore production
    

    В режиме production ваши скрипты и стили будут дополнительно минифицированы.

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

    Заключение


    Данный материал не претендует на использование в реальных условиях. В каждой конкретной ситуации будут свои подходы и настройки. Я лишь хотел показать еще один вариант управления ресурсами в проекте. Те кто знаком с webpack, вероятно найдут для себя полезной информацию о том, что появился такой плагин от разработчиков Symfony. Кто не знаком с webpack возможно заинтересуются этим инструментом.

    Многие вещи хотелось бы описать более подробно, но сколько я ни пытался, все равно получался слишком раздутый пост. Я готов доработать материал, если будет адекватная критика. Ниже привожу ссылки, где можно более глубоко ознакомиться с данными инструментами:

    Официальный сайт webpack
    Документация к плагину

    Спасибо за внимание.
    Поделиться публикацией
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама
    Комментарии 7
    • +2
      Полезная фишка, судя по всему вдохновленная Laravel Mix/Laraver Elixir
      • 0

        Так и есть, в документации указано влияние)

      • 0

        Большое спасибо. Очень интересный материал

        • 0
          Стоит отметить, что релизнута была поддержка TypeScript, что делает этот интсрумент еще более интересным.
          • 0
            Про Webpack в целом можно много написать. Данный пост относится именно к плагину для Symfony — Webpack Encore. Насколько я знаю TypeScript уже давно прикрутили.
            • +1
              я именно про Encore и говорю, поддержка TypeScript была вмержена 5 дней назад
              • +1
                Точно. Как-то я пропустил. Спасибо, добавлю в пост информацию.

          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.