Pragmatic frontend for Symfony developers

Pragmatic frontend for Symfony developers

364d59ac0b4b4e5eee8aeb27a127d176?s=128

Titouan Galopin

February 28, 2020
Tweet

Transcript

  1. Pragmatic frontend for Symfony developers Titouan GALOPIN

  2. 2 Titouan Galopin Product Manager SymfonyInsight insight.symfony.com

  3. 3 The Why

  4. 4 Why is frontend development so complex?

  5. 5 Thinking about modern software architectures requires frontend choices

  6. 6 Let’s discuss!

  7. Agenda 1. A bit of history 2. Modern frontend 3.

    The least complex technology possible 4. Approaches to frontend with Symfony 7
  8. 8 1. A bit of history

  9. 9 1990–1995 HTML, CSS and JavaScript are invented

  10. 10 1996–1999 Standardization efforts begin Browser compliance is terrible

  11. 2000–2004 CSS frameworks begin to emerge jQuery is born 11

  12. 2005–2009 W3C specification is met Responsive designs and frameworks introduced

    12
  13. 13 2010–2015 JS frameworks are born (Backbone, Ember, Angular, React,

    Vue, ...) HTML5 is announced
  14. 14 2016–2020 New technologies and platforms built around modern frontend

    emerge: GraphQL, Service Workers, Cordova, Electron, React Native, …
  15. 15 Modern frontend development is a direct consequence of this

    history
  16. 16 What is Modern Frontend?

  17. 17 2. Modern frontend

  18. 18 Modern frontend is supposed to be about user experience

  19. 19 “Nowadays, users expect more from websites (performance, help, productivity,

    …)”
  20. 20 Ever wondered whether a loader was actually loading or

    was broken?
  21. 21 Ever been frustrated about a Back button click returning

    to the wrong page?
  22. 22 Ever been disappointed by a link you couldn’t open

    in a new tab?
  23. 23 Ever been angered by a website you couldn’t open

    in multiple tabs without messing with the data?
  24. 24 Ever had to disable your adblocker to make a

    website work?
  25. 25 Ever had to use a screen reader on a

    full Javascript interface?
  26. 26 Full-page apps (for instance create-react-app) is not an answer

    to the UX problem
  27. 27 It’s easy to do it really wrong and hurts

    UX a lot
  28. 28 Modern frontend != Full-page app

  29. 29 Full-page app is a solution to a different problem

  30. 30 How to build a website and a mobile application

    with the same backend?
  31. 31 3. The least complex technology possible

  32. How many times did you experience PHP failing between a

    function call and the first line of the function? 32
  33. How many times did you experience an AJAX call failing

    between the request and the response? 33
  34. 34 The network is a huge source of complexity

  35. How many times did you develop your own session system

    in PHP? 35
  36. How many times did you develop your own session history

    stack in PHP? 36
  37. 37 Not using the features of the browser is a

    source of complexity
  38. How many developers in your team know perfectly well both

    React and Symfony? 38
  39. 39 Dealing with backend vs with interfaces are two different

    jobs: human complexity
  40. KISS Keep It Super Simple 40

  41. By default, use the simplest option available Migrate to something

    more complex only if necessary 41
  42. The simplest option = HTML + CSS built with PHP

    42
  43. But it’s sometimes not enough... 43

  44. 44 4. Approaches to frontend with Symfony

  45. 45 No JS Misses the real UX gain of Javascript,

    but still possible
  46. 46 Full-page app + API Has a lot of drawbacks

    but is the only option for multiple clients (web + mobile)
  47. 47 Progressive enhancement A pragmatic in-between

  48. 48 Most recent JS frameworks (React, Vue, …) can be

    used in limited parts of the page
  49. 49 What about using React only where it brings actual

    improvements?
  50. 50 Using React to enhance your Symfony application

  51. 51 1. Develop your application as usual

  52. 52 {# index.html.twig #} {% extends 'base.html.twig' %} {% block

    body %} <div> Hello world <div> <input type="text" placeholder="Color in hexadecimal" /> </div> </div> {% endblock %}
  53. 53 {# index.html.twig #} {% extends 'base.html.twig' %} {% block

    body %} <div> Hello world <div> <input type="text" placeholder="Color in hexadecimal" /> </div> </div> {% endblock %} This could be a Symfony Form field
  54. 54 2. Add React only where it’s useful

  55. 55 composer req --dev webpack yarn install https://symfony.com/doc/current/frontend.html

  56. 56 Webpack is a build tool It lets you manipulate

    your Javascript and CSS before using it in production (JSX, minification, …)
  57. 57 Webpack Encore wraps Webpack around a nice API to

    improve its Developer Experience
  58. 58 Webpack Encore is awesome to compile React apps to

    normal Javascript
  59. 59 yarn add @babel/preset-react react react-dom prop-types

  60. 60 // webpack.config.js Encore.enableReactPreset()

  61. 61 {# index.html.twig #} {% extends 'base.html.twig' %} {% block

    body %} <div> Hello world <div data-color-chooser> <input type="text" placeholder="Color in hexadecimal" /> </div> </div> {% endblock %} Marker to find where to inject a React component
  62. 62 // app.js import ReactDOM from 'react-dom'; import {ColorChooser} from

    './ColorChooser/ColorChooser'; $('div[data-color-chooser]').each((key, node) => { const input = $(node).find('input'); ReactDOM.render( <ColorChooser color={input.val()} onColorChange={(color) => input.attr('value', color)} />, node ); });
  63. 63

  64. 64 ✓ Allow to use great React components where it’s

    useful ✓ Do not add unnecessary complexity ✓ 100% compatible with Symfony, HTTP and default browser behaviors
  65. 65 3. How to transfer data?

  66. 66 namespace App\DataExposer; class DataExposer { private $data = [];

    public function expose(string $name, $value) { $this->data[$name] = $value; } public function getExposedData(): array { return $this->data; } }
  67. 67 namespace App\Twig; class DataExposerExtension extends AbstractExtension { private $exposer;

    public function __construct(DataExposer $exposer) { $this->exposer = $exposer; } public function getFunctions(): array { return [ new TwigFunction('expose', [$this, 'exposeData']), new TwigFunction('get_exposed_data', [$this, 'getExposedData']), ]; } // ... }
  68. 68 {# base.html.twig #} <!DOCTYPE html> <html> <head> <meta charset="UTF-8">

    <title>Welcome!</title> </head> <body> {% block body %}{% endblock %} <script type="application/json" id="exposed-data"> {{- get_exposed_data()|json_encode|raw -}} </script> {{ encore_entry_script_tags('app') }} </body> </html>
  69. 69 const data = JSON.stringify( document.getElementById('exposed-data') );

  70. 70 ✓ Easy to parse (JSON.stringify) ✓ Compatible with Content

    Security Policy ✓ Easy to use in automated testing
  71. 71 Conclusion

  72. Thanks! 72 For any question: ▪ @titouangalopin on Twitter ▪

    titouan.galopin @symfony.com