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

Дата обновления перевода 2024-07-25

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

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

  • assets/app.js
  • assets/styles/app.css

С 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, и т.д.

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 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
# скомпилировать ресурсы и автоматически перекомпилировать их при изменении файлов
$ npm run watch

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

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

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

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

Tip

Если вы используете инструмент Symfony CLI, вы можете настроить работников так, чтобы они
автоматически запускались вместе с веб-сервером. Более подробную информацию вы можете найти в документации Работники Symfony CLI .

Caution

Останавливайте и перезапускайте 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
$ 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, сначала установите StimulusBundle:

1
$ composer require symfony/stimulus-bundle

Рецепт Flex должен добавить несколько файлов/каталогов:

  • assets/bootstrap.js - инициализирует Stimulus;
  • assets/controllers/ - каталог, где вы разместите ваши контроллеры Stimulus;
  • assets/controllers.json - файл, который помогает загружать контроллеры Stimulus из пакетов UX, которые вы установите.

Давайте рассмотрим простой пример 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
$ 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
>   Error: Установите sass-loader и sass, чтобы использовать enableSassLoader()

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

1
2
$ npm install sass-loader@^13.0.0 sass --save-dev
$ npm run watch

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

Компиляция только 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 .