|
1 | | -# WebpackEncoreBundle: Symfony integration with Webpack Encore! |
| 1 | +WebpackEncoreBundle: Symfony integration with Webpack Encore! |
| 2 | +============================================================= |
2 | 3 |
|
3 | 4 | This bundle allows you to use the `splitEntryChunks()` feature |
4 | | -from [Webpack Encore](https://symfony.com/doc/current/frontend.html) |
5 | | -by reading an `entrypoints.json` file and helping you render all of |
6 | | -the dynamic `script` and `link` tags needed. |
| 5 | +from [Webpack Encore][1] by reading an `entrypoints.json` file |
| 6 | +and helping you render all of the dynamic `script` and `link` |
| 7 | +tags needed. |
7 | 8 |
|
8 | | -Install the bundle with: |
| 9 | +[Read the documentation][2] |
9 | 10 |
|
10 | | -``` |
11 | | -composer require symfony/webpack-encore-bundle |
12 | | -``` |
13 | | - |
14 | | -## Configuration |
15 | | - |
16 | | -If you're using Symfony Flex, you're done! The recipe will |
17 | | -pre-configure everything you need in the `config/packages/webpack_encore.yaml` |
18 | | -file: |
19 | | - |
20 | | -```yaml |
21 | | -# config/packages/webpack_encore.yaml |
22 | | -webpack_encore: |
23 | | - # The path where Encore is building the assets - i.e. Encore.setOutputPath() |
24 | | - # if you customize this, you will also need to change framework.assets.json_manifest_path (it usually lives in assets.yaml) |
25 | | - output_path: '%kernel.project_dir%/public/build' |
26 | | - # If multiple builds are defined (as shown below), you can disable the default build: |
27 | | - # output_path: false |
28 | | - |
29 | | - # Set attributes that will be rendered on all script and link tags |
30 | | - script_attributes: |
31 | | - defer: true |
32 | | - # referrerpolicy: origin |
33 | | - # link_attributes: |
34 | | - # referrerpolicy: origin |
35 | | - |
36 | | - # if using Encore.enableIntegrityHashes() and need the crossorigin attribute (default: false, or use 'anonymous' or 'use-credentials') |
37 | | - # crossorigin: 'anonymous' |
38 | | - |
39 | | - # preload all rendered script and link tags automatically via the http2 Link header |
40 | | - # preload: true |
41 | | - |
42 | | - # Throw an exception if the entrypoints.json file is missing or an entry is missing from the data |
43 | | - # strict_mode: false |
44 | | - |
45 | | - # if you have multiple builds: |
46 | | - # builds: |
47 | | - # frontend: '%kernel.project_dir%/public/frontend/build' |
48 | | - |
49 | | - # pass the build name" as the 3rd argument to the Twig functions |
50 | | - # {{ encore_entry_script_tags('entry1', null, 'frontend') }} |
51 | | - |
52 | | - # Cache the entrypoints.json (rebuild Symfony's cache when entrypoints.json changes) |
53 | | - # Available in version 1.2 |
54 | | - # Put in config/packages/prod/webpack_encore.yaml |
55 | | - # cache: true |
56 | | -``` |
57 | | - |
58 | | -If you're not using Flex, [enable the bundle manually](https://symfony.com/doc/current/bundles.html) |
59 | | -and copy the config file from above into your project. |
60 | | - |
61 | | -## Usage |
62 | | - |
63 | | -The "Split Chunks" functionality in Webpack Encore is enabled by default |
64 | | -with the recipe if you install this bundle using Symfony Flex. Otherwise, |
65 | | -enable it manually: |
66 | | - |
67 | | -```diff |
68 | | -// webpack.config.js |
69 | | -// ... |
70 | | - .setOutputPath('public/build/') |
71 | | - .setPublicPath('/build') |
72 | | - .setManifestKeyPrefix('build/') |
73 | | - .addEntry('entry1', './assets/some_file.js') |
74 | | - |
75 | | -+ .splitEntryChunks() |
76 | | -// ... |
77 | | -``` |
78 | | - |
79 | | -When you enable `splitEntryChunks()`, instead of just needing 1 script tag |
80 | | -for `entry1.js` and 1 link tag for `entry1.css`, you may now need *multiple* |
81 | | -script and link tags. This is because Webpack ["splits" your files](https://webpack.js.org/plugins/split-chunks-plugin/) |
82 | | -into smaller pieces for greater optimization. |
83 | | - |
84 | | -To help with this, Encore writes an `entrypoints.json` file that contains |
85 | | -all of the files needed for each "entry". |
86 | | - |
87 | | -For example, to render all of the `script` and `link` tags for a specific |
88 | | -"entry" (e.g. `entry1`), you can: |
89 | | - |
90 | | -```twig |
91 | | -{# any template or base layout where you need to include a JavaScript entry #} |
92 | | -
|
93 | | -{% block javascripts %} |
94 | | - {{ parent() }} |
95 | | -
|
96 | | - {{ encore_entry_script_tags('entry1') }} |
97 | | -
|
98 | | - {# or render a custom attribute #} |
99 | | - {# |
100 | | - {{ encore_entry_script_tags('entry1', attributes={ |
101 | | - defer: true |
102 | | - }) }} |
103 | | - #} |
104 | | -{% endblock %} |
105 | | -
|
106 | | -{% block stylesheets %} |
107 | | - {{ parent() }} |
108 | | -
|
109 | | - {{ encore_entry_link_tags('entry1') }} |
110 | | -{% endblock %} |
111 | | -``` |
112 | | - |
113 | | -Assuming that `entry1` required two files to be included - `build/vendor~entry1~entry2.js` |
114 | | -and `build/entry1.js`, then `encore_entry_script_tags()` is equivalent to: |
115 | | - |
116 | | -```twig |
117 | | -<script src="{{ asset('build/vendor~entry1~entry2.js') }}"></script> |
118 | | -<script src="{{ asset('build/entry1.js') }}"></script> |
119 | | -``` |
120 | | - |
121 | | -If you want more control, you can use the `encore_entry_js_files()` and |
122 | | -`encore_entry_css_files()` methods to get the list of files needed, then |
123 | | -loop and create the `script` and `link` tags manually. |
124 | | - |
125 | | -## Rendering Multiple Times in a Request (e.g. to Generate a PDF) |
126 | | - |
127 | | -When you render your script or link tags, the bundle is smart enough |
128 | | -not to repeat the same JavaScript or CSS file within the same request. |
129 | | -This prevents you from having duplicate `<link>` or `<script>` tags |
130 | | -if you render multiple entries that both rely on the same file. |
131 | | - |
132 | | -In some cases, however, you may want to render the script & link |
133 | | -tags for the same entry multiple times in a request. For example, |
134 | | -if you render multiple Twig templates to create multiple PDF files |
135 | | -during a single request. |
136 | | - |
137 | | -In that case, before each render, you'll need to "reset" the internal |
138 | | -cache so that the bundle re-renders CSS or JS files that it previously |
139 | | -rendered. For example, in a controller: |
140 | | - |
141 | | -```php |
142 | | -// src/Controller/SomeController.php |
143 | | - |
144 | | -use Symfony\WebpackEncoreBundle\Asset\EntrypointLookupInterface; |
145 | | - |
146 | | -class SomeController |
147 | | -{ |
148 | | - public function index(EntrypointLookupInterface $entrypointLookup) |
149 | | - { |
150 | | - $entrypointLookup->reset(); |
151 | | - // render a template |
152 | | - |
153 | | - $entrypointLookup->reset(); |
154 | | - // render another template |
155 | | - |
156 | | - // ... |
157 | | - } |
158 | | -} |
159 | | -``` |
160 | | - |
161 | | -If you have multiple builds, you can also autowire |
162 | | -`Symfony\WebpackEncoreBundle\Asset\EntrypointLookupCollectionInterface` |
163 | | -and use it to get the `EntrypointLookupInterface` object for any build. |
164 | | - |
165 | | -## Custom Attributes on script and link Tags |
166 | | - |
167 | | -Custom attributes can be added to rendered `script` or `link` in 3 |
168 | | -different ways: |
169 | | - |
170 | | -1. Via global config (`script_attributes` and `link_attributes`) - see the |
171 | | - config example above. |
172 | | - |
173 | | -1. When rendering in Twig - see the `attributes` option in the docs above. |
174 | | - |
175 | | -1. By listening to the `Symfony\WebpackEncoreBundle\Event\RenderAssetTagEvent` |
176 | | - event. For example: |
177 | | - |
178 | | -```php |
179 | | -namespace App\EventSubscriber; |
180 | | - |
181 | | -use Symfony\Component\EventDispatcher\EventSubscriberInterface; |
182 | | -use Symfony\WebpackEncoreBundle\Event\RenderAssetTagEvent; |
183 | | - |
184 | | -class ScriptNonceSubscriber implements EventSubscriberInterface |
185 | | -{ |
186 | | - public static function getSubscribedEvents() |
187 | | - { |
188 | | - return [ |
189 | | - RenderAssetTagEvent::class => 'onRenderAssetTag' |
190 | | - ]; |
191 | | - } |
192 | | - |
193 | | - public function onRenderAssetTag(RenderAssetTagEvent $event) |
194 | | - { |
195 | | - if ($event->isScriptTag()) { |
196 | | - $event->setAttribute('nonce', 'lookup nonce'); |
197 | | - } |
198 | | - } |
199 | | -} |
200 | | -``` |
201 | | - |
202 | | -## Stimulus / Symfony UX Helper |
203 | | - |
204 | | -### stimulus_controller |
205 | | - |
206 | | -This bundle also ships with a special `stimulus_controller()` Twig function |
207 | | -that can be used to render [Stimulus Controllers & Values](https://stimulus.hotwired.dev/reference/values) |
208 | | -and [CSS Classes](https://stimulus.hotwired.dev/reference/css-classes). |
209 | | -See [stimulus-bridge](https://github.com/symfony/stimulus-bridge) for more details. |
210 | | - |
211 | | -For example: |
212 | | - |
213 | | -```twig |
214 | | -<div {{ stimulus_controller('chart', { 'name': 'Likes', 'data': [1, 2, 3, 4] }) }}> |
215 | | - Hello |
216 | | -</div> |
217 | | -
|
218 | | -<!-- would render --> |
219 | | -<div |
220 | | - data-controller="chart" |
221 | | - data-chart-name-value="Likes" |
222 | | - data-chart-data-value="[1,2,3,4]" |
223 | | -> |
224 | | - Hello |
225 | | -</div> |
226 | | -``` |
227 | | - |
228 | | -If you want to set CSS classes: |
229 | | - |
230 | | -```twig |
231 | | -<div {{ stimulus_controller('chart', { 'name': 'Likes', 'data': [1, 2, 3, 4] }, { 'loading': 'spinner' }) }}> |
232 | | - Hello |
233 | | -</div> |
234 | | -
|
235 | | -<!-- would render --> |
236 | | -<div |
237 | | - data-controller="chart" |
238 | | - data-chart-name-value="Likes" |
239 | | - data-chart-data-value="[1,2,3,4]" |
240 | | - data-chart-loading-class="spinner" |
241 | | -> |
242 | | - Hello |
243 | | -</div> |
244 | | -
|
245 | | -<!-- or without values --> |
246 | | -<div {{ stimulus_controller('chart', controllerClasses = { 'loading': 'spinner' }) }}> |
247 | | - Hello |
248 | | -</div> |
249 | | -``` |
250 | | - |
251 | | -Any non-scalar values (like `data: [1, 2, 3, 4]`) are JSON-encoded. And all |
252 | | -values are properly escaped (the string `[` is an escaped |
253 | | -`[` character, so the attribute is really `[1,2,3,4]`). |
254 | | - |
255 | | -If you have multiple controllers on the same element, you can chain them as there's also a `stimulus_controller` filter: |
256 | | - |
257 | | -```twig |
258 | | -<div {{ stimulus_controller('chart', { 'name': 'Likes' })|stimulus_controller('other-controller') }}> |
259 | | - Hello |
260 | | -</div> |
261 | | -``` |
262 | | - |
263 | | -You can also retrieve the generated attributes as an array, which can be helpful e.g. for forms: |
264 | | - |
265 | | -```twig |
266 | | -{{ form_start(form, { attr: stimulus_controller('chart', { 'name': 'Likes' }).toArray() }) }} |
267 | | -``` |
268 | | - |
269 | | -### stimulus_action |
270 | | - |
271 | | -The `stimulus_action()` Twig function can be used to render [Stimulus Actions](https://stimulus.hotwired.dev/reference/actions). |
272 | | - |
273 | | -For example: |
274 | | - |
275 | | -```twig |
276 | | -<div {{ stimulus_action('controller', 'method') }}>Hello</div> |
277 | | -<div {{ stimulus_action('controller', 'method', 'click') }}>Hello</div> |
278 | | -
|
279 | | -<!-- would render --> |
280 | | -<div data-action="controller#method">Hello</div> |
281 | | -<div data-action="click->controller#method">Hello</div> |
282 | | -``` |
283 | | - |
284 | | -If you have multiple actions and/or methods on the same element, you can chain them as there's also a |
285 | | -`stimulus_action` filter: |
286 | | - |
287 | | -```twig |
288 | | -<div {{ stimulus_action('controller', 'method')|stimulus_action('other-controller', 'test') }}> |
289 | | - Hello |
290 | | -</div> |
291 | | -
|
292 | | -<!-- would render --> |
293 | | -<div data-action="controller#method other-controller#test"> |
294 | | - Hello |
295 | | -</div> |
296 | | -``` |
297 | | - |
298 | | -You can also retrieve the generated attributes as an array, which can be helpful e.g. for forms: |
299 | | - |
300 | | -```twig |
301 | | -{{ form_row(form.password, { attr: stimulus_action('hello-controller', 'checkPasswordStrength').toArray() }) }} |
302 | | -``` |
303 | | - |
304 | | -You can also pass [parameters](https://stimulus.hotwired.dev/reference/actions#action-parameters) to actions: |
305 | | - |
306 | | -```twig |
307 | | -<div {{ stimulus_action('hello-controller', 'method', 'click', { 'count': 3 }) }}>Hello</div> |
308 | | -
|
309 | | -<!-- would render --> |
310 | | -<div data-action="click->hello-controller#method" data-hello-controller-count-param="3">Hello</div> |
311 | | -``` |
312 | | - |
313 | | -### stimulus_target |
314 | | - |
315 | | -The `stimulus_target()` Twig function can be used to render [Stimulus Targets](https://stimulus.hotwired.dev/reference/targets). |
316 | | - |
317 | | -For example: |
318 | | - |
319 | | -```twig |
320 | | -<div {{ stimulus_target('controller', 'a-target') }}>Hello</div> |
321 | | -<div {{ stimulus_target('controller', 'a-target second-target') }}>Hello</div> |
322 | | -
|
323 | | -<!-- would render --> |
324 | | -<div data-controller-target="a-target">Hello</div> |
325 | | -<div data-controller-target="a-target second-target">Hello</div> |
326 | | -``` |
327 | | - |
328 | | -If you have multiple targets on the same element, you can chain them as there's also a `stimulus_target` filter: |
329 | | - |
330 | | -```twig |
331 | | -<div {{ stimulus_target('controller', 'a-target')|stimulus_target('other-controller', 'another-target') }}> |
332 | | - Hello |
333 | | -</div> |
334 | | -
|
335 | | -<!-- would render --> |
336 | | -<div data-controller-target="a-target" data-other-controller-target="another-target"> |
337 | | - Hello |
338 | | -</div> |
339 | | -``` |
340 | | - |
341 | | -You can also retrieve the generated attributes as an array, which can be helpful e.g. for forms: |
342 | | - |
343 | | -```twig |
344 | | -{{ form_row(form.password, { attr: stimulus_target('hello-controller', 'a-target').toArray() }) }} |
345 | | -``` |
346 | | - |
347 | | -Ok, have fun! |
| 11 | +[1]: https://symfony.com/doc/current/frontend.html |
| 12 | +[2]: https://symfony.com/bundles/WebpackEncoreBundle/current/index.html |
0 commit comments