Encore: Налаштування вашого проекту

Дата оновлення перекладу 2022-12-15

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.js (та app.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
// 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
# скомпілювати ресурси один раз
$ yarn encore dev
# або
$ npm run watch

# або автоматично рекомпілювати ресурси при зміні файлів
$ yarn encore dev --watch
# або
$ npm run dev-server

# при розгортанні, створити збірку промислового коду
$ yarn encore production
# або
$ npm run build

Якщо ви використовуєте менеджер пакетів npm, виконайте замість цього наступні команди:

1
2
3
4
5
6
7
8
# скомпілювати ресурси один раз
$ npm run dev

# або автоматично рекомпілювати ресурси при зміні файлів
$ npm run watch

# при розгортанні, створити збірку промислового коду
$ npm run build

Всі ці команди - наприклад, dev або watch - є скороченнями, визначеними у вашому файлі package.json.

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
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

Або перегляньте Turbo 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

Тепер ваш застосунок підтримує Sass. Encore також підтримує LESS та Stylus. Див. Предпроцессоры 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.