|
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