Story summary
Read full storyhttp://triskweline.de/unpoly-rugb/#/ It's not you, it's us We're breaking up with JavaScript frontends Henning Koch, makandra GmbH @triskweline Give it 10 minutes. Context * makandra is a Ruby on Rails consultancy * We start a new application every 3 months * We maintain apps for a really long time + 50+ apps in maintenance + Oldest app is from 2007 * Will we be able to do this for another 10 years? Tweet from 2025 [future_twe] Complexity Server Client Based on chart by @ryanstout Complexity in 2005 Authorization Routing Models Controllers Views Dependencies Server Client Based on chart by @ryanstout Complexity in 2008 Authorization Routing Models Controllers Views Dependencies Server RandomJS Dependencies Client Based on chart by @ryanstout Complexity in 2009 API Authorization Routing Models Controllers Views Dependencies Server RandomJS Dependencies Client Based on chart by @ryanstout Complexity in 2011 Asset packing API Authorization Routing Models Controllers Views Dependencies Server RandomJS Dependencies Client Based on chart by @ryanstout Complexity in 2013 Asset packing API Authorization Routing Models Controllers Views Dependencies Server Models / API client Controllers Views Dependencies Client Based on chart by @ryanstout Complexity in 2014 Asset packing API Authorization Routing Models Controllers Views Dependencies Server Authorization Routing Models / API client Controllers Views Dependencies Client Based on chart by @ryanstout Complexity in 2015 Prerendering Asset packing API Authorization Routing Models Controllers Views Dependencies Server Virtual DOM Authorization Routing Models / API client Controllers Views Dependencies Client Based on chart by @ryanstout A look back at the 7 AngularJS projects that we wrote from 2013-2016: 1 2 3 4 5 6 7 In hindsight, these are the projects that should have been a SPA: 1 2 3 4 5 6 7 YMMV. Learnings from 3 years of SPAs 1. SPAs are a good fit for a certain class of UI. For us that class is the exception, not the default. 2. There's a trade-off between UI fidelity and code complexity. 3. We think we can fix most of the problems with server-side apps and find a new sweet spot in that trade-off. [trade_off] What server-side apps do well 1. Wide choice of great and mature languages 2. Low complexity stack 3. Synchronous data access 4. Time to first render 5. Works on low-end devices What server-side apps don't do well 1. Slow interaction feedback 2. Page loads destroy transient state (scroll positions, unsaved form values, focus) 3. Layered interactions are hard (modals, drop-downs, drawers) 4. Animation is complicated 5. Complex forms Demo of server-side app issues Link to demo app (press Start Classic on first page) Things to try and observe: * Navigate between cards in the left pane Scroll positions get lost in both panes * Open the second page ("More cards" link at the bottom of the left pane) Card in the right pane gets lost * Edit a card, change the title, then change the pattern Unsaved form content is gone when returning from the pattern selection How to fix server-side apps? A thought experiment [html6] Imagine HTML6 was all about server-side apps What features would be in that spec? Partial page updates? Animated transitions? Layered interactions? We can polyfill all of that! Because it's 2016 and JavaScript is now fast. [unpoly] * 25 new HTML attributes to write modern UI, but keep logic on the server * Works with existing code little to no changes required on the server side * Works with any backend language or framework although we have some nice Rails bindings * In development for two years and in production with multiple apps Demo of Unpoly-enhanced app Link to demo app (press Start Enhanced on first page) Things to try and observe: 1. Navigate between cards, open and cancel the form Page transitions are animated 2. Navigate between cards in the left pane Scroll positions are kept in both panes 3. Open the second page ("More cards" link at the bottom of the left pane) New page slides in smoothly Card in the right pane is kept 4. Edit a card, change the title, then change the pattern Pattern selection happens in a modal dialog, preserving unsaved form values 5. Inspect links and see attributes with up-* prefix See docs for [up-target] and [up-modal] Classic page flow [fragment_flow_vanilla] Server renders full pages on every request. Any state that's not in the URL gets lost when switching pages. Unpoly page flow [fragment_flow_unpoly] Server still renders full pages, but we only use fragments. This solves most of our problems with transient state being destroyed. Layers Document http://app/list Modal http://app/new Popup http://app/search Unpoly apps may stack up to three HTML pages on top of each other Each layer has its own URL and can navigate without changing the others Use this to keep context during interactions [gmail] [gmail_laye] Layers Replace fragment Open fragment in dialog Open fragment in dropdown Links in a layer prefer to update fragments within the layer Changing a fragment behind the layer will close the layer Navigation * All fragment updates change the browser URL by default. * Back/Forward buttons work as expected. Even scroll positions are restored. * Linking to a fragment will scroll the viewport to reveal the fragment. Unpoly is aware of fixed navigation bars and will scroll further/ less. * Links to the current URL get an .up-current class automatically. But I have this really custom JavaScript / jQuery library / behavior that I need to integrate Don't worry, we actually allow for massive customization: * Pairing JavaScript snippets with HTML elements * Integrating libraries (WYSIWYG editor, jQuery plugins, ...) * Passing structured data to JavaScript snippets * Reuse existing Unpoly functionality from your own code * Invent your own UJS syntax * Configure defaults Activating JS snippets Every app needs a way to pair JavaScript snippets with certain HTML elements: * A textarea.wysiwyg should activate Redactor on load * An input[type=search] field should automatically request new results when the user types something * A button.toggle-all should toggle all checkboxes when clicked * A .map should render a map via the Google Maps JS API Activating JS snippets Random.js
Story summary
Read full storyThis text won't change
full.html * Unpoly requests full.html via AJAX * Server renders a full HTML page * Unpoly extracts the fragment that matches .story * Unpoly swaps the old and new fragment * Unpoly changes the browser URL to http://host/full.html Open fragment in modal dialog without JavaScript Run example on unpoly.comStory summary
Read full storyStory summary
Read full storyStory summary
Read full story