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

The UI is an Application

The UI is an Application

Presented at Dutch PHP Conference on June 26, 2015.

The UI is no longer just a ragtag collection of templates, scripts & styles shoehorned in alongside "real" application code, but is now a rich, complex piece of software in and of itself.

We have a de facto standard language for UI development in JavaScript, yet too often our UI code remains tangled up in hamstrung templating languages, CSS preprocessors and whatever language or framework our back end happens to be built with.

In this talk we'll explore what happens when you treat your UI as a first class citizen, separating it from the rest of your app and replacing traditional templates & CSS with the real programming language you already know: JavaScript.

Ben Smithett

June 26, 2015
Tweet

More Decks by Ben Smithett

Other Decks in Programming

Transcript

  1. • Application logic: written in JS • Routing: written in

    JS • Templates: compiled by JS • CSS: pre- and post-processed by JS • Build tooling: powered by JS • Compile-to-JS languages: …it’s all JS
  2. assets webfonts config routes API pages app models controllers views

    API pages images icons sprites stylesheets vars mixins
  3. assets webfonts config routes API pages app models controllers views

    API pages images icons sprites stylesheets vars mixins javascripts
  4. assets webfonts config routes API pages app models controllers views

    API pages images icons sprites stylesheets vars mixins javascripts models controllers views
  5. assets webfonts config routes API pages app models controllers views

    API pages images icons sprites stylesheets vars mixins javascripts models controllers views templates
  6. assets webfonts config routes API pages app models controllers views

    API pages images icons sprites stylesheets vars mixins javascripts models controllers views templates router
  7. assets webfonts config routes API pages app models controllers views

    API pages images icons sprites stylesheets vars mixins javascripts models controllers views templates router js app routes
  8. assets webfonts config routes API pages app models controllers views

    API pages images icons sprites stylesheets vars mixins javascripts models controllers views templates router js app routes vendor
  9. assets webfonts config routes API pages app models controllers views

    API pages images icons sprites stylesheets vars mixins javascripts models controllers views templates router js app routes vendor tooling
  10. assets webfonts config routes API pages app models controllers views

    API pages images icons sprites stylesheets vars mixins javascripts models controllers views templates router js app routes vendor tooling back end tests
  11. assets webfonts config routes API pages app models controllers views

    API pages images icons sprites stylesheets vars mixins javascripts models controllers views templates router js app routes vendor tooling back end tests UI tests
  12. assets webfonts config routes API pages app models controllers views

    API pages images icons sprites stylesheets vars mixins javascripts models controllers views templates router js app routes vendor tooling back end tests UI tests deployment
  13. assets webfonts config routes API pages app models controllers views

    API pages images icons sprites stylesheets vars mixins javascripts models controllers views templates router js app routes vendor tooling back end tests UI tests deployment asset pipeline
  14. assets webfonts config routes API pages app models controllers views

    API pages images icons sprites stylesheets vars mixins javascripts models controllers views templates router js app routes vendor tooling back end tests UI tests deployment asset pipeline
  15. assets webfonts config routes API pages app models controllers views

    API pages images icons sprites stylesheets vars mixins javascripts models controllers views templates router js app routes vendor tooling back end tests UI tests deployment asset pipeline
  16. API app config api endpoint routes models controllers tooling back

    end tests deployment ui app images stylesheets webfonts config vars mixins functions javascripts models controllers views templates router vendor tests asset pipeline
  17. Embracing JavaScript as the language of UI development enables a

    focused, DRY codebase and a slick, yet fault- tolerant, end user experience.
  18. embedded language template - php <div> <?php if ($conference ==

    "DPC"): ?> Welcome to <?= $conference ?>! <?php else: ?> Wrong conference! <?php endif; ?> </div>
  19. embedded language template - ERB <div> <% if @conference ==

    "DPC" %> Welcome to <%= @conference %>! <% else %> Wrong conference! <% end %> </div>
  20. embedded language template - EJS <div> <% if (conference ===

    "DPC") { %> Welcome to <%= conference %>! <% } else { %> Boooo <% } %> </div>
  21. <div> <% if @conference == "DPC" %> <h1>DPC Speakers</h1> <ul>

    <% @speakers.each |speaker| do %> <li> <img src="<%= speaker.avatar %>" /> <strong><%= speaker.name %></strong> </li> <% end %> </ul> <% elsif @conference && @conference.name %> <strong class="error"> No speakers found for <%= @conference.name %>! </strong> <% end %> </div>
  22. <?php get_header(); ?> <div id="content" class="narrowcolumn"> <?php $querystr = "

    SELECT $wpdb->posts.* FROM $wpdb->posts, $wpdb->postmeta WHERE $wpdb->posts.ID = $wpdb->postmeta.post_id AND $wpdb->postmeta.meta_key = 'tag' AND $wpdb->posts.post_status = 'publish' ORDER BY $wpdb->posts.post_date DESC "; $pageposts = $wpdb->get_results($querystr, OBJECT); ?> <?php if ($pageposts): ?> <?php global $post; ?> <?php foreach ($pageposts as $post): ?> <?php setup_postdata($post); ?> <div class="post" id="post-<?php the_ID(); ?>"> <h2><a href="<?php the_permalink() ?>" rel="bookmark" title="Permanent Link to <?php the_title_attribute(); ?>"> <?php the_title(); ?></a></h2> <small><?php the_time('F jS, Y') ?> <!-- by <?php the_author() ?> --></small> <div class="entry"> <?php the_content('Read the rest of this entry »'); ?> </div> <p class="postmetadata">Posted in <?php the_category(', ') ?> | <?php edit_post_link('Edit', '', ' | '); ?> <?php comments_popup_link('No Comments »', '1 Comment »', '% Comments »'); ?></p> </div> <?php endforeach; ?> <?php else : ?> <h2 class="center">Not Found</h2> <p class="center">Sorry, but you are looking for something that isn't here.</p> <?php include (TEMPLATEPATH . "/searchform.php"); ?> <?php endif; ?> </div> <?php get_sidebar(); ?> Source: Wordpress Codex
  23. logic-less templates! We revolted against the spaghetti code enabled by

    embedded language templates No more logic allowed in Views!
  24. <div> {{#conference}} <h1>DPC Speakers</h1> <ul> {{#speakers}} <li> <img src="{{avatar_url}}" />

    <strong>{{speaker_name}}</strong> </li> {{/speakers}} {{^speakers}} <li>No speakers found!</li> {{/speakers}} </ul> {{/conference}} </div>
  25. React.createClass({ render () { return ( React.createElement('div', {}, React.createElement('h1', {},

    “Hi DPC!” ) ) ) } }) // <div> // <h1> // Hi DPC! // </h1> // </div>
  26. React.createClass({ render () { return ( <div> <h1> Hi DPC!

    </h1> </div> ) } }) React.createElement('div', {}, React.createElement('h1', {}, “Hi DPC!” ) )
  27. <ul> { this.props.speakers ? this.props.speakers.map((speaker) => { var name =

    speaker.name.toUpperCase() return <li>{name}</li> }) : <li>No speakers found!</li> } </ul>
  28. virtual dom real dom <div> Unread: <span id='count'>4</span> <h1>Send message:</h1>

    <textarea></textarea> </div> <div> Unread: <span id='count'>3</span> <h1>Send message:</h1> <textarea></textarea> </div>
  29. virtual dom real dom <div> Unread: <span id='count'>4</span> <h1>Send message:</h1>

    <textarea></textarea> </div> <div> Unread: <span id='count'>3</span> <h1>Send message:</h1> <textarea></textarea> </div> document.querySelector('#count').innerHTML('4') minimum possible imperative update
  30. const Header = React.createClass({ render () { return ( <div>

    <h1> Hi DPC! </h1> </div> ) } }) React.renderToString(<Header />) // "<div><h1>Hi DPC!</h1></div>"
  31. const FavButton = React.createClass({ handleClick () { Api.favourite(this.props.id) }, render

    () { return ( <button onClick={this.handleClick}> Favorite this </button> ) } })
  32. .btn { color: #f00; width: 200px; } .btn:hover { background:

    #00f; } .col-1 { width: 8.33333%; } .col-2 { width: 16.66667%; }
  33. .btn { color: #f00; width: 200px; } .btn:hover { background:

    #00f; } .col-1 { width: 8.33333%; } .col-2 { width: 16.66667%; } .btn { color: $red; width: 200px; &:hover { background: $yellow; } } @for $i from 1 through 12 { .col-#{$i} { width: 100% / ($i * 12); } }
  34. var myStyles = { color: colors.red, backgroundColor: signedInUser ? colors.green

    : colors.grey, backgroundImage: CDNPathFor('forest_bg.png'), width: Math.round(document.body.offsetWidth / 2) + 'px' }
  35. var totalCols = 12 var gridColClasses = {} for (var

    i = 1; i <= totalCols; i++) { gridColClasses['col-' + i] = { width: ((100 / totalCols) * i) + '%' } }
  36. var totalCols = 12 var gridColClasses = {} for (var

    i = 1; i <= totalCols; i++) { gridColClasses['col-' + i] = { width: ((100 / totalCols) * i) + '%' } }
  37. <div style="border: 2px solid #0f0; height: 100px; width: 100px; float:

    left;"> <img src="..." /> </div> <div style="border: 2px solid #0f0; height: 100px; width: 100px; float: left;"> <img src="..." /> </div> <div style="border: 2px solid #0f0; height: 100px; width: 100px; float: left;"> <img src="..." /> </div>
  38. <div class="thumb"> <img src="..." /> </div> <div class="thumb"> <img src="..."

    /> </div> <div class="thumb"> <img src="..." /> </div>
  39. var Thumb = React.createClass({ render () { return ( <div

    className='thumb'> <img src={this.props.src} /> </div> ) } })
  40. var Thumb = React.createClass({ render () { return ( <div

    className='thumb'> <img src={this.props.src} /> </div> ) } })
  41. var thumbStyles = { border: '2px solid #0f0', height: '100px',

    width: '100px', float: left } var Thumb = React.createClass({ render () { return ( <div className='thumb'> <img src={this.props.src} /> </div> ) } })
  42. var thumbStyles = { border: '2px solid #0f0', height: '100px',

    width: '100px', float: left } var Thumb = React.createClass({ render () { return ( <div style={thumbStyles}> <img src={this.props.src} /> </div> ) } })
  43. why not use inline styles? • Because it isn’t DRY!


    It can be, if you stop writing the same HTML multiple times
  44. why not use inline styles? • Because it isn’t DRY!


    It can be, if you stop writing the same HTML multiple times • Performance?
  45. why not use inline styles? • Because it isn’t DRY!


    It can be, if you stop writing the same HTML multiple times • Performance?
 Maybe… but probably not enough for you to worry about!
  46. import styles from './profile.css'; var Profile = React.createClass({ render() {

    return <div className={styles.wrapper}> <img className={styles.image} src="..." /> <span className={styles.username}>...</span> </div> } }