Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Symfony UX Turbo

Symfony UX Turbo

Marco Petersen

May 25, 2021
Tweet

More Decks by Marco Petersen

Other Decks in Programming

Transcript

  1. You build your backend that exposes some kind of API.

    You build a Single-Page Application that consumes your API.
  2. You build your backend that exposes some kind of API.

    You build a Single-Page Application that consumes your API. You make sure the backend doesn't send data the frontend doesn't expect (and vice versa).
  3. You build your backend that exposes some kind of API.

    You build a Single-Page Application that consumes your API. You make sure the backend doesn't send data the frontend doesn't expect (and vice versa). You coordinate releases to make sure neither side causes trouble in production.
  4. You build your backend that exposes some kind of API.

    You build a Single-Page Application that consumes your API. You make sure the backend doesn't send data the frontend doesn't expect (and vice versa). You coordinate releases to make sure neither side causes trouble in production. You fight with Webpack and Babel.
  5. You build your backend that exposes some kind of API.

    You build a Single-Page Application that consumes your API. You make sure the backend doesn't send data the frontend doesn't expect (and vice versa). You coordinate releases to make sure neither side causes trouble in production. You fight with Webpack and Babel. And all you wanted was to give your users that modern web experience !
  6. Olá! ! Marco Petersen " Software Developer @ QOSSMIC (fka

    SensioLabs Germany) # Berlin $ % @ocrampete16
  7. Today's Menu • Appetizer: The Back Story - What is

    Symfony UX Turbo? • Main Course: 3 Building Blocks - Drive, Frames & Streams • Dessert: Turbo In Action: Example Application
  8. What is Hotwire? • Turbo: modern applications without writing JavaScript

    • Stimulus: simple JS framework if you need JavaScript • Strada: web/native app bridge
  9. Turbo Drive 1. User clicks on a link or submits

    a form. 2. intervenes and stops the default action (visit new page). 3. fetches the page using fetch in the background. 4. Replaces <body> and merges <head>. 5. Updates browser history with history.pushState.
  10. Handling Forms #[Route('/rooms/create', name: 'create_room')] public function create(Request $request, EntityManagerInterface

    $entityManager): Response { $room = new Room(); $form = $this->createForm(RoomType::class, $room); $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { $entityManager->persist($form->getData()); $entityManager->flush(); return $this->redirectToRoute('rooms', [], Response::HTTP_SEE_OTHER); } return $this->renderForm('room/create.html.twig', ['form' => $form]); }
  11. Turbo Frames • quite similar to iframes • lets a

    part of the page have their own "context" • clicking links & submitting forms inside a frame only replaces the content inside that frame • pages can contain multiple frames
  12. Scoping Content and Actions <h1>Rooms</h1> <turbo-frame id="create-room"> <a href="{{ path('create_room')

    }}">Create Room</a> </turbo-frame> <ul id="room-list"> {% for room in rooms %} {{ include('fragments/_room_list_item.html.twig', {room: room}) }} {% endfor %} </ul>
  13. <!-- Current page --> <turbo-frame id="create-room"> <a href="{{ path('create_room') }}">Create

    Room</a> </turbo-frame> <!-- Response body --> <h1>Create New Room</h1> <turbo-frame id="create-room"> {{ form(form) }} </turbo-frame>
  14. <!-- Current page --> <turbo-frame id="create-room"> <a href="{{ path('create_room') }}">Create

    Room</a> </turbo-frame> <!-- Response body --> <h1>Create New Room</h1> <turbo-frame id="create-room"> {{ form(form) }} </turbo-frame>
  15. <!-- Current page --> <turbo-frame id="create-room"> {{ form(form) }} </turbo-frame>

    <!-- Response body --> <h1>Create New Room</h1> <turbo-frame id="create-room"> {{ form(form) }} </turbo-frame>
  16. Turbo Frames and ESI • Just like in Rails, Turbo

    Frames can also lazily load frames on the client-side. • The Symfony integration takes advantage of the already existing ESI features Symfony brings.
  17. Turbo Streams • easily add real-time capabilities to your application

    • HTML fragments are streamed to the browser • server pushes changes to connected users using a real-time protocol (like Mercure or Websocket) • Symfony integration uses Mercure
  18. Listening on Streams <ul id="room-list" {{ turbo_stream_listen('my_stream_key') }}> {% for

    room in rooms %} {{ include('fragments/_room_list_item.html.twig', {room: room}) }} {% endfor %} </ul>
  19. Publishing Changes #[Route('/rooms/create', name: 'create_room')] public function create( Request $request,

    EntityManagerInterface $entityManager, HubInterface $hub ): Response { // create form $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { $entityManager->persist($form->getData()); $entityManager->flush(); $hub->publish( new Update( 'my_stream_key', $this->renderView('room/new.stream.html.twig', ['room' => $room]) ) ); return $this->redirectToRoute('view_room', ['id' => $room->getId()], Response::HTTP_SEE_OTHER); } return $this->renderForm('room/rename.html.twig', ['form' => $form]); }
  20. Doctrine Integration • Symfony UX Turbo makes it easy to

    publish changes from Doctrine entities. • Maker bundle supports generating the necessary files (entity w/ attribute, fragment template etc.)
  21. Why I Like (Symfony UX) Turbo • Promising abstractions •

    React introduced components ➡ large client-side applications now maintainable • Drive, Frames & Streams are useful primitives that can be used together in various combinations • first-class integration with Symfony
  22. But It's Still Early Days • Hotwire has only been

    out for a few months. • Only large-scale user is Basecamp. • No established community best practices yet.