$30 off During Our Annual Pro Sale. View Details »

Symfony UX Turbo

Symfony UX Turbo

Marco Petersen

May 25, 2021
Tweet

More Decks by Marco Petersen

Other Decks in Programming

Transcript

  1. Symfony UX
    Turbo

    View Slide

  2. Tired Of Modern Web
    Development?

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  8. 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
    !

    View Slide

  9. Ever Wish You Could
    Write a modern application
    Without Writing
    JavaScript?

    View Slide

  10. Is that even possible?

    View Slide

  11. Yes.

    View Slide

  12. Thanks for listening!
    $kernel->terminate($request, $response);

    View Slide

  13. Actually, there's a bit
    more to it...

    View Slide

  14. Olá!
    !
    Marco Petersen
    "
    Software Developer @ QOSSMIC (fka SensioLabs Germany)
    #
    Berlin
    $
    %
    @ocrampete16

    View Slide

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

    View Slide

  16. Appetizer
    What is Symfony UX
    Turbo?

    View Slide

  17. View Slide

  18. View Slide

  19. What is Hotwire?
    • Turbo: modern applications without writing JavaScript
    • Stimulus: simple JS framework if you need JavaScript
    • Strada: web/native app bridge

    View Slide

  20. View Slide

  21. Installation
    composer require symfony/ux-turbo symfony/ux-turbo-mercure
    yarn install --force
    yarn encore dev

    View Slide

  22. Main Course
    Drive, Frames &
    Streams

    View Slide

  23. Turbo Drive navigates
    to new pages without
    full page reloads.

    View Slide

  24. 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 and merges .
    5. Updates browser history with history.pushState.

    View Slide

  25. Clicking Links
    Create Room
    Create Room

    View Slide

  26. 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]);
    }

    View Slide

  27. Learn more about Turbo Drive at
    https://turbo.hotwire.dev/
    handbook/drive

    View Slide

  28. Turbo Frames are
    independent content
    blocks.

    View Slide

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

    View Slide

  30. Scoping Content and Actions
    Rooms

    Create Room


    {% for room in rooms %}
    {{ include('fragments/_room_list_item.html.twig', {room: room}) }}
    {% endfor %}

    View Slide



  31. Create Room


    Create New Room

    {{ form(form) }}

    View Slide



  32. Create Room


    Create New Room

    {{ form(form) }}

    View Slide



  33. {{ form(form) }}


    Create New Room

    {{ form(form) }}

    View Slide

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

    View Slide

  35. Lazily Loading a Frame
    id="latest-news"
    src="{{ fragment_uri(controller('App\\Controller\\NewsController::latest')) }}">

    https://symfony.com/doc/current/http_cache/esi.html

    View Slide

  36. Turbo Streams stream
    server-side changes
    to your users'
    browsers.

    View Slide

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

    View Slide

  38. View Slide

  39. Listening on Streams

    {% for room in rooms %}
    {{ include('fragments/_room_list_item.html.twig', {room: room}) }}
    {% endfor %}

    View Slide

  40. 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]);
    }

    View Slide

  41. HTML Fragment






    View Slide

  42. 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.)

    View Slide

  43. Dessert
    Example Application

    View Slide

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

    View Slide

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

    View Slide

  46. Thanks for listening! (for real
    now)
    $kernel->terminate($request, $response);

    View Slide