[SymfonyLive Paris 2020] Pragmatic frontend for Symfony developers

[SymfonyLive Paris 2020] Pragmatic frontend for Symfony developers

364d59ac0b4b4e5eee8aeb27a127d176?s=128

Titouan Galopin

September 24, 2020
Tweet

Transcript

  1. Pragmatic frontend for Symfony developers Titouan GALOPIN SymfonyLive Paris 2020

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

    at improving UX
  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

    fully 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 Backend and Frontend 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 Basing Javascript behaviors on HTTP and HTML

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

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

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

  52. 52 1. Develop your application as usual

  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 %}
  54. 54 {# 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
  55. 55 2. Add React only where it’s useful

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

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

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

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

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

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

  62. 62 {# 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
  63. 63 // 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 ); });
  64. 64 // 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 ); }); Using a selector library to find the node
  65. 65 // 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 ); }); Replacing the content of the node by the React tree
  66. 66

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

    useful ✓ Do not add unnecessary complexity ✓ 100% compatible with Symfony Forms, HTTP, default browser behaviors, ...
  68. 68 3. How to transfer data from the backend to

    the frontend?
  69. 69 HTML5 is awesome

  70. 70 ✓ HTML5 is scoped: data concerning a node is

    stored as attributes of the node ✓ HTML5 is semantic: many use cases are already considered in the standard ✓ HTML5 is flexible: you can add your own attributes
  71. 71 {# index.html.twig #} {% extends 'base.html.twig' %} {% block

    body %} <div> Hello world <div data-color-chooser data-color-chooser-type="circles"> <input type="text" placeholder="Color in hexadecimal" /> </div> </div> {% endblock %} Option which could be coming from a Twig variable
  72. 72 // app.js // ... $('div[data-color-chooser]').each((key, node) => { const

    input = $(node).find('input'); ReactDOM.render( <ColorChooser type={node.getAttribute('data-color-chooser-type')} color={input.val()} onColorChange={(color) => input.attr('value', color)} />, node ); }); Using the option from the data attribute is easy because it’s scoped to the node
  73. 73

  74. 74 ✓ Easy to use (scoped and accessible in the

    appropriate Javascript context) ✓ Compatible with Content Security Policy ✓ Easy automatic testing
  75. 75 4. How to transfer data from the frontend to

    the backend?
  76. 76 Use an API focused on your Javascript needs

  77. 77 fetch() is native in most browsers Polyfills exist for

    others
  78. 78 Do not develop an API if you don’t need

    it! Keep things as simple as possible
  79. 79 5. Avoiding page refresh without an SPA

  80. 80 What is an API? A way to transfer data

    in a structured way
  81. 81 HTML contains data, in a structured way, and is

    already made to be displayed by the browser
  82. 82 What if we used our traditional HTML application instead

    of an API?
  83. 83 Turbolinks A tiny library which replace links in your

    application with AJAX calls to switch the HTML on the fly
  84. 84 yarn add turbolinks

  85. 85 // app.js import Turbolinks from 'turbolinks'; Turbolinks.start();

  86. 86 ✓ Same “no-refresh” effect as SPA ✓ Fully compatible

    with browser history, sessions, cache, … ✓ Better SEO (HTML rendered on the server) ✓ No added complexity over traditional Symfony apps
  87. 87 (by the way, that’s how Github works)

  88. 88 Conclusion

  89. KISS Keep It Super Simple 89

  90. The simplest option = HTML + CSS built with PHP

    90
  91. It useful for UX, add Javascript in some places 91

  92. Using Javascript that relies on browser features decreases complexity 92

  93. Full-page apps are useful in some situations … but not

    a solution for UX! 93
  94. Thanks! 94 For any question: ▪ @titouangalopin on Twitter ▪

    titouan.galopin @symfony.com