Encore: Настройка вашего проекта

Дата обновления перевода: 2023-01-17

Encore: Настройка вашего проекта

После установки Encore, ваше приложение уже имеет по одному файлу CSS и JS, организованных в каталоге assets/:

  • assets/app.js
  • assets/bootstrap.js
  • assets/controllers.json
  • assets/styles/app.css
  • assets/controllers/hello_controller.js

С Encore вам нужно думать о вашем файле app.js, как об отдельном приложении JavaScript: он будет требовать все необходимые ему зависимости (например, jQuery или React), включительно с любыми CSS. Ваш файл app.js уже делает это с утверждением JavaScript import:

1
2
3
4
// assets/app.js
// ...

import './styles/app.css';

Работа Encore (через Webpack) простая: читать и следовать всем утверждениям require() и создавать один финальный app.jsapp.css), который содержит все нужное вашему приложению. Encore может делать намного больше: минимизировать файлы, предварительно обрабатывать Sass/LESS, поддерживать React, Vue.js, и т.д.

Другие файлы - bootstrap.js, controllers.json и hello_controller.js относятся к теме, о которой вы скоро узнаете: Stimulus и Symfony UX.

Конфигурация Encore/Webpack

Всё в Encore конфигурируется через файл webpack.config.js в корне вашего проекта. Он уже содержит необходимую вам базовую конфигурацию:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// webpack.config.js
const Encore = require('@symfony/webpack-encore');

Encore
    // каталог, где будут храниться все скомпилированные ресурсы
    .setOutputPath('public/build/')

    // публичный путь, используемый веб-сервером для доступа к предыдущему каталогу
    .setPublicPath('/build')

    .addEntry('app', './assets/app.js')

    // раскомментируйте это, если вы хотите использовать jQuery в следующем примере
    .autoProvidejQuery()
;

// ...

Ключевой частью является addEntry(): он сообщает Encore, что нужно загрузить файл assets/app.js и следовать всем утверждениям require(). Затем он запакует все вместе и - благодаря первому аргументу - выведет финальные файлы app.js и app.css в каталог public/build.

Чтобы создать ресурсы, выполните следующее, если вы используете менеджер пакетов Yarn:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# скомпилировать ресурсы и автоматически перекомпилировать их при изменении файлов
$ yarn watch
# или
$ npm run watch

# или, запустить сервер dev, который может иногда обновлять ваш код без обновления страницы
$ yarn dev-server
# или
$ npm run dev-server

# скомпилировать ресурсы единожды
$ yarn dev
# или
$ npm run dev

# при развёртывании, создать компоновку производства
$ yarn build
# или
$ npm run build

Все эти команды - например, dev или watch - это ярлыки, которые определены в вашем файле package.json.

Note

Останавливайте и перезапускайте encore каждый раз, когда обновляете свой файл webpack.config.js.

Поздравляем! Теперь у вас три новых файла:

  • public/build/app.js (содержит весь JavaScript для вашей записи "app")
  • public/build/app.css (содержит весь CSS для вашей записи "app")
  • public/build/runtime.js (файл, помогающий Webpack работать)

Note

В реальности, у вас наверное есть ещё пару файлов в public/build. Некоторые из них из-за разделения кода, оптимизации, которая помогает производительности, но не влияет на то, как всё работает. Другие - помогают Encore делать свою работу.

Далее, добавьте их в ваш базовый файл шаблона. Два помощника Twig ищ WebpackEncoreBundle могут сделать большинство работы за вас:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
{# templates/base.html.twig #}
<!DOCTYPE html>
<html>
    <head>
        <!-- ... -->

        {% block stylesheets %}
            {# 'app' должен совпадать с первым аргументом addEntry() в webpack.config.js #}
            {{ encore_entry_link_tags('app') }}

            <!-- Отображает тег ссылки (если ваш модуль требует любого CSS)
                 <link rel="stylesheet" href="/build/app.css"> -->
        {% endblock %}

        {% block javascripts %}
            {{ encore_entry_script_tags('app') }}

            <!-- Отображает app.js и файл webpack runtime.js
                <script src="/build/runtime.js" defer></script>
                <script src="/build/app.js" defer></script>
                See note below about the "defer" attribute -->
        {% endblock %}
    </head>

    <!-- ... -->
</html>

Вот и всё! Когда вы обновите свою страницу, весь JavaScript из assets/app.js - а также любые другие файлы JavaScript, которые он имел - будет выполнен. Все файлы CSS, которые были обязательными, также будут отображены.

Функции encore_entry_link_tags() и encore_entry_script_tags() читают из файла entrypoints.json, который генерируется Encore, чтобы знать точное(ые) имя(на) для отображения. Этот файл особенно полезен, так как вы можете включить версионирование или указать ресурсам на CDN не внося никаких изменений в ваш шаблон: пути в entrypoints.json всегда будут финальными, правильными путями. А если вы используете splitEntryChunks() (где Webpack разделяет вывод в большее количество равных файлов), все необходимые теги script и link будут отображены автоматически.

Если вы не используете Symfony, вы можете игнорировать файл entrypoints.json и указать на финальный созданный файл напрямую. entrypoints.json требуется только для некоторых необязательных функций.

1.9.0

Атрибут defer в тегах script откладывает выполнение JavaScript пока загружается страница (похоже на размещение script внизу страницы). Способность всегда добавлять этот атрибут была представлена в WebpackEncoreBundle 1.9.0 и она автоматически включена в рецепте этого пакета в файле config/packages/webpack_encore.yaml. См. WebpackEncoreBundle Configuration, чтобы узнать больше деталей.

Требование модулей JavaScript

Webpack - это модульный упаковщик, что означает, что вы можете import другие файлы JavaScript. Для начала, создайте файл, экспортирующий функцию:

1
2
3
4
// assets/greet.js
export default function(name) {
    return `Yo yo ${name} - welcome to Encore!`;
};

Мы будем использовать jQuery, чтобы напечатать это сообщение на странице. Установите его через:

1
2
3
4
5
# если вы используете менеджер пакетов Yarn
$ yarn add jquery --dev

# если вы используете менеджер пакетов npm
$ npm install jquery --save-dev

Отлично! Используйте import, чтобы импортировать jquery и greet.js:

1
2
3
4
5
6
7
8
9
10
11
12
13
// assets/app.js
  // ...

+ // загружает пакет jquery из node_modules
+ import jquery from 'jquery';

+ // импортировать функцию из greet.js (расширение .js необязательно)
+ // ./ (or ../) means to look for a local file
+ import greet from './greet';

+ $(document).ready(function() {
+     $('body').prepend('<h1>'+greet('jill')+'</h1>');
+ });

Вот и всё! Если вы ранее выполняли encore dev --watch, ваши финальные, созданные файлы, уже были обновлены: jQuery и greet.js были автоматически добавлены к файлу вывода (app.js). Обновите, чтобы увидеть сообщение!

Stimulus и Symfony UX

Каким бы простым не был пример выше, вместо создания вашего приложения внутри app.js, мы рекомендуем Stimulus: маленький фреймворк JavaScript, который облегчает прикрепление поведения к HTML. Он мощный и вы в него влюбитесь! Symfony даже предоставляет пакеты, чтобы добавить больше функций в Stimulus. Они называются пакетами Symfony UX.

Если вы следовали инструкциям установки, у вас уже должен быть Stimulus, установленный и готовый к работе! На самом деле, в этом цель файла assets/bootstrap.js: инициализировать Stimulus и автоматически загрузить все "контроллеры" из каталога assets/controllers/.

Давайте рассмотрим простой пример Stimulus. В шаблоне Twig, предположите, что у вас есть:

1
2
3
4
5
6
7
8
9
<div {{ stimulus_controller('say-hello') }}>
    <input type="text" {{ stimulus_target('say-hello', 'name') }}>

    <button {{ stimulus_action('say-hello', 'greet') }}>
        Greet
    </button>

    <div {{ stimulus_target('say-hello', 'output') }}></div>
</div>

stimulus_controller('say-hello') отображает атрибут data-controller="say-hello". Когда этот элемент появляется на странице, Stimulus автоматически будет искать и запускать контроллер под названием say-hello-controller.js. Создайте это в вашем каталоге assets/controllers/:

1
2
3
4
5
6
7
8
9
10
// assets/controllers/say-hello-controller.js
import { Controller } from '@hotwired/stimulus';

export default class extends Controller {
    static targets = ['name', 'output']

    greet() {
      this.outputTarget.textContent = `Hello, ${this.nameTarget.value}!`
    }
}

Результат? Когда вы нажимаете на кнопку "Greet", она выводит ваше имя! А если на страницу добавлено больше элементов {{ stimulus_controller('say-hello') }} - например, через Ajax - они мгновенно будут работать: нет необходимости повторного запуска чего-либо.

Готовы узнать больше о Stimulus?

Turbo: Молниеносно быстрый опыт одностраничного приложения

Symfony поставляется с тесной интеграцией с другой библиотекой JavaScript под названием Turbo. Turbo автоматически перобразует все клики по ссылкам и отправки форм в вызов Ajax, с нулевыми (или практически нулевыми) изменениями в вашем коде Symfony! Результат? Вы получаете скорость одностраничнго приложения, без необходимости написания JavaScript.

Чтобы узнать больше, смотрите пакет symfony/ux-turbo.

Screencast

Или просмотрите Stimulus Screencast на SymfonyCasts.

JavaScript или CSS для конкретных страниц

На данный момент у вас есть только один финальный файл JavaScript: app.js.
Encore может быть разеделен на несколько файлов в целях производительности (см. разделение на куски), но весь этот код всё ещё скачивается на каждой странице.

Что, если вы хотите дополнительный JavaScript или CSS (например, для производительности), который вы хотите добавить только на конкретные страницы?

Ленивые контроллеры

Одним очень хорошим решением, если вы используете Stimulus, будет использование ленивых контроллеров. Чтобы активировать это в контроллере, добавьте специальный stimulusFetch: 'lazy' над вашим классом контроллера:

1
2
3
4
5
6
7
// assets/controllers/lazy-example-controller.js
import { Controller } from '@hotwired/stimulus';

/* stimulusFetch: 'lazy' */
export default class extends Controller {
    // ...
}

Это всё! Код контроллера - и всех модулей, которые он импортирует - будет разделён на отдельные файлы Encore. Затем, эти файлы не будут скачаны, пока совпадающий элемент (например, <div data-controller="lazy-example">) не появится на странице!

Note

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

Множественные записи

Ещё одна опция - создание JavaScript или CSS для определённой страницы (например, оформление покупок, аккаунт и т.д.). Чтобы справиться с этим, создайте новый файл "записи" JavaScript для каждой страницы:

1
2
// assets/checkout.js
// пользовательский код для вашей страницы оформления покупок
1
2
// assets/account.js
// пользовательский код для вашей страницы аккаунта

Далее, используйте addEntry(), чтобы указать Webpack прочитать эти два новых файла во время компоновки:

1
2
3
4
5
6
7
// webpack.config.js
  Encore
      // ...
      .addEntry('app', './assets/app.js')
+     .addEntry('checkout', './assets/checkout.js')
+     .addEntry('account', './assets/account.js')
      // ...

И так как вы только что изменили файл webpack.config.js, убедитесь в том, что остановили и перезапустили Encore:

1
2
3
4
5
# если вы используете менеджер пакетов Yarn
$ yarn watch

# если вы используете менеджер пакетов npm
$ npm run watch

Webpack теперь выведет новый файл checkout.js и новый файл account.js в вашем каталоге компоновки. И, если любой из этих файлов требует/импортирует CSS, Webpack также выведет файлы checkout.css и account.css.

Наконец, добавьте теги script и link на отдельных страницах, где они вам нужны:

1
2
3
4
5
6
7
8
9
10
11
12
{# templates/.../checkout.html.twig #}
  {% extends 'base.html.twig' %}

+ {% block stylesheets %}
+     {{ parent() }}
+     {{ encore_entry_link_tags('checkout') }}
+ {% endblock %}

+ {% block javascripts %}
+     {{ parent() }}
+     {{ encore_entry_script_tags('checkout') }}
+ {% endblock %}

Теперь, страница завершения покупок будет содержать весь JavaScript и CSS для записи app (так как он добавлен в base.html.twig и есть вызов {{ parent() }}) и вашей записи checkout. С этим, JavaScript и CSS, необходимые для каждой страницы, могут жить внутри записи app, а код, необходимый только для страницы завершения покупок - внутри checkout.

Использование Sass/LESS/Stylus

Вы уже освоили основы Encore. Отлично! Но существует много других функций, которые вы можете решить использовать, если они вам понадобятся. Например, вместо использования обычного CSS, вы можете также использовать Sass, LESS или Stylus. Чтобы использовать Sass, переименуйте файл app.css в app.scss и обновите утверждение import:

1
2
3
// assets/app.js
- import './styles/app.css';
+ import './styles/app.scss';

Затем, сообщите Encore включить предварительный процессор Sass:

1
2
3
4
5
6
// webpack.config.js
  Encore
      // ...

+    .enableSassLoader()
  ;

Так как вы только что изменили ваш файл webpack.config.js, вам понадобится перезапустить Encore. Когда вы это сделаете, вы увидите ошибку!

1
2
>   Error: Установите sass-loader и sass, чтобы использовать enableSassLoader()
>     yarn add sass-loader@^12.0.0 sass --dev

Encore поддерживает множество функций. Но, вместо того, чтобы насиловать вас ими, когда вам нужна будет функция, Encore сообщит вам, что нужно установить. Выполните:

1
2
3
4
5
6
7
# если вы используете менеджер пакетов Yarn
$ yarn add sass-loader@^12.0.0 sass --dev
$ yarn encore dev --watch

# если вы используете менеджер пакетов npm
$ npm install sass-loader@^12.0.0 sass --save-dev
$ npm run watch

Your app now supports Sass. Encore also supports LESS and Stylus. See Предпроцессоры CSS: Sass, LESS, Stylus, и др..

Компиляция только CSS-файла

Caution

Использование addStyleEntry() поддерживается, но не рекомендуется. Лучшей опцией будет следовать паттерну выше: использовать addEntry(), чтобы указать на файл JavaScript, а затем затребовать необходимый CSS изнутри.

Если вы хотите только скомпилировать CSS-файл, это возможно через addStyleEntry():

1
2
3
4
5
6
// webpack.config.js
Encore
    // ...

    .addStyleEntry('some_page', './assets/styles/some_page.css')
;

Это выведет новый some_page.css.

Продолжайте!

Encore поддерживает еще множество функций! Чтобы увидеть весь список того, что вы можете сделать, см. файл Encore's index.js. Или вернитесь к списку статей Encore.