Slide 1

Slide 1 text

Pragmatic frontend for Symfony developers Titouan GALOPIN SymfonyLive Paris 2020

Slide 2

Slide 2 text

2 Titouan Galopin Product Manager SymfonyInsight insight.symfony.com

Slide 3

Slide 3 text

3 The Why

Slide 4

Slide 4 text

4 Why is frontend development so complex?

Slide 5

Slide 5 text

5 Thinking about modern software architectures requires frontend choices

Slide 6

Slide 6 text

6 Let’s discuss!

Slide 7

Slide 7 text

Agenda 1. A bit of history 2. Modern frontend 3. The least complex technology possible 4. Approaches to frontend with Symfony 7

Slide 8

Slide 8 text

8 1. A bit of history

Slide 9

Slide 9 text

9 1990–1995 HTML, CSS and JavaScript are invented JavaScript aims at improving UX

Slide 10

Slide 10 text

10 1996–1999 Standardization efforts begin Browser compliance is terrible

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

13 2010–2015 JS frameworks are born (Backbone, Ember, Angular, React, Vue, ...) HTML5 is announced

Slide 14

Slide 14 text

14 2016–2020 New technologies and platforms built around modern frontend emerge: GraphQL, Service Workers, Cordova, Electron, React Native, …

Slide 15

Slide 15 text

15 Modern frontend development is a direct consequence of this history

Slide 16

Slide 16 text

16 What is Modern Frontend?

Slide 17

Slide 17 text

17 2. Modern frontend

Slide 18

Slide 18 text

18 Modern frontend is supposed to be about user experience

Slide 19

Slide 19 text

19 “Nowadays, users expect more from websites (performance, help, productivity, …)”

Slide 20

Slide 20 text

20 Ever wondered whether a loader was actually loading or was broken?

Slide 21

Slide 21 text

21 Ever been frustrated about a Back button click returning to the wrong page?

Slide 22

Slide 22 text

22 Ever been disappointed by a link you couldn’t open in a new tab?

Slide 23

Slide 23 text

23 Ever been angered by a website you couldn’t open in multiple tabs without messing with the data?

Slide 24

Slide 24 text

24 Ever had to disable your adblocker to make a website work?

Slide 25

Slide 25 text

25 Ever had to use a screen reader on a fully Javascript interface?

Slide 26

Slide 26 text

26 Full-page apps (for instance create-react-app) is not an answer to the UX problem

Slide 27

Slide 27 text

27 It’s easy to do it really wrong and hurts UX a lot

Slide 28

Slide 28 text

28 Modern frontend != Full-page app

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

30 How to build a website and a mobile application with the same backend?

Slide 31

Slide 31 text

31 3. The least complex technology possible

Slide 32

Slide 32 text

How many times did you experience PHP failing between a function call and the first line of the function? 32

Slide 33

Slide 33 text

How many times did you experience an AJAX call failing between the request and the response? 33

Slide 34

Slide 34 text

34 The network is a huge source of complexity

Slide 35

Slide 35 text

How many times did you develop your own session system in PHP? 35

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

37 Not using the features of the browser is a source of complexity

Slide 38

Slide 38 text

How many developers in your team know perfectly well both React and Symfony? 38

Slide 39

Slide 39 text

39 Backend and Frontend are two different jobs: human complexity

Slide 40

Slide 40 text

KISS Keep It Super Simple 40

Slide 41

Slide 41 text

By default, use the simplest option available Migrate to something more complex only if necessary 41

Slide 42

Slide 42 text

The simplest option = HTML + CSS built with PHP 42

Slide 43

Slide 43 text

But it’s sometimes not enough... 43

Slide 44

Slide 44 text

44 4. Approaches to frontend with Symfony

Slide 45

Slide 45 text

45 No JS Misses the real UX gain of Javascript, but still possible

Slide 46

Slide 46 text

46 Full-page app + API Has a lot of drawbacks but is the only option for multiple clients (web + mobile)

Slide 47

Slide 47 text

47 Progressive enhancement A pragmatic in-between

Slide 48

Slide 48 text

48 Basing Javascript behaviors on HTTP and HTML

Slide 49

Slide 49 text

49 Most recent JS frameworks (React, Vue, …) can be used in limited parts of the page

Slide 50

Slide 50 text

50 What about using React only where it brings actual improvements?

Slide 51

Slide 51 text

51 Using React to enhance your Symfony application

Slide 52

Slide 52 text

52 1. Develop your application as usual

Slide 53

Slide 53 text

53 {# index.html.twig #} {% extends 'base.html.twig' %} {% block body %}
Hello world
{% endblock %}

Slide 54

Slide 54 text

54 {# index.html.twig #} {% extends 'base.html.twig' %} {% block body %}
Hello world
{% endblock %} This could be a Symfony Form field

Slide 55

Slide 55 text

55 2. Add React only where it’s useful

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

57 Webpack is a build tool It lets you manipulate your Javascript and CSS before using it in production (JSX, minification, …)

Slide 58

Slide 58 text

58 Webpack Encore wraps Webpack around a nice API to improve its Developer Experience

Slide 59

Slide 59 text

59 Webpack Encore is awesome to compile React apps to normal Javascript

Slide 60

Slide 60 text

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

Slide 61

Slide 61 text

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

Slide 62

Slide 62 text

62 {# index.html.twig #} {% extends 'base.html.twig' %} {% block body %}
Hello world
{% endblock %} Marker to find where to inject a React component

Slide 63

Slide 63 text

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( input.attr('value', color)} />, node ); });

Slide 64

Slide 64 text

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( input.attr('value', color)} />, node ); }); Using a selector library to find the node

Slide 65

Slide 65 text

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( input.attr('value', color)} />, node ); }); Replacing the content of the node by the React tree

Slide 66

Slide 66 text

66

Slide 67

Slide 67 text

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

Slide 68

Slide 68 text

68 3. How to transfer data from the backend to the frontend?

Slide 69

Slide 69 text

69 HTML5 is awesome

Slide 70

Slide 70 text

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

Slide 71

Slide 71 text

71 {# index.html.twig #} {% extends 'base.html.twig' %} {% block body %}
Hello world
{% endblock %} Option which could be coming from a Twig variable

Slide 72

Slide 72 text

72 // app.js // ... $('div[data-color-chooser]').each((key, node) => { const input = $(node).find('input'); ReactDOM.render( input.attr('value', color)} />, node ); }); Using the option from the data attribute is easy because it’s scoped to the node

Slide 73

Slide 73 text

73

Slide 74

Slide 74 text

74 ✓ Easy to use (scoped and accessible in the appropriate Javascript context) ✓ Compatible with Content Security Policy ✓ Easy automatic testing

Slide 75

Slide 75 text

75 4. How to transfer data from the frontend to the backend?

Slide 76

Slide 76 text

76 Use an API focused on your Javascript needs

Slide 77

Slide 77 text

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

Slide 78

Slide 78 text

78 Do not develop an API if you don’t need it! Keep things as simple as possible

Slide 79

Slide 79 text

79 5. Avoiding page refresh without an SPA

Slide 80

Slide 80 text

80 What is an API? A way to transfer data in a structured way

Slide 81

Slide 81 text

81 HTML contains data, in a structured way, and is already made to be displayed by the browser

Slide 82

Slide 82 text

82 What if we used our traditional HTML application instead of an API?

Slide 83

Slide 83 text

83 Turbolinks A tiny library which replace links in your application with AJAX calls to switch the HTML on the fly

Slide 84

Slide 84 text

84 yarn add turbolinks

Slide 85

Slide 85 text

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

Slide 86

Slide 86 text

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

Slide 87

Slide 87 text

87 (by the way, that’s how Github works)

Slide 88

Slide 88 text

88 Conclusion

Slide 89

Slide 89 text

KISS Keep It Super Simple 89

Slide 90

Slide 90 text

The simplest option = HTML + CSS built with PHP 90

Slide 91

Slide 91 text

It useful for UX, add Javascript in some places 91

Slide 92

Slide 92 text

Using Javascript that relies on browser features decreases complexity 92

Slide 93

Slide 93 text

Full-page apps are useful in some situations … but not a solution for UX! 93

Slide 94

Slide 94 text

Thanks! 94 For any question: ▪ @titouangalopin on Twitter ▪ titouan.galopin @symfony.com