Components on the Web: Frontend NE

Components on the Web: Frontend NE

Aea964cf59c0c81fff752896f070cbbb?s=128

Jack Franklin

April 05, 2018
Tweet

Transcript

  1. @Jack_Franklin 1

  2. @Jack_Franklin 2

  3. A component is a self contained element made up of

    HTML, CSS and JavaScript. We can combine lots of components together to create user interfaces. @Jack_Franklin 3
  4. The plan 1. The road to components ! 2. The

    theory of components " 3. The approaches and challenges of building good components ✅ 4. How to introduce components to your project/ product/app/site $ @Jack_Franklin 4
  5. All of today's talk is reasonably new, especially within the

    context of front-end development @Jack_Franklin 5
  6. Today I'm going to talk you through some of my

    experiences, but I'd love to hear yours! @Jack_Franklin 6
  7. The road to components When we didn't know any better,

    we stuck to patterns that had served us well on the server. @Jack_Franklin 7
  8. @Jack_Franklin 8

  9. @Jack_Franklin 9

  10. APIs and JSON /api/cat-pics [ { "id": 1, "name": "Fluffy",

    "age": 5 }, { "id": 2, "name": "Mittens", "age": 7 } ] @Jack_Franklin 10
  11. @Jack_Franklin 11

  12. @Jack_Franklin 12

  13. MVC doesn't fit frontend development @Jack_Franklin 13

  14. <p>This is a paragraph element (or...<em>component?</em>).</p> <h1>This is a heading</h1>

    <ul> <li>this is a list item</li> </ul> @Jack_Franklin 14
  15. And what if we could extend the box of bricks?

    1 <thread-user-avatar src="/img/jack.png"></thread-user-avatar> 1 https://developers.google.com/web/fundamentals/web-components/customelements @Jack_Franklin 15
  16. And what if we built frameworks around this idea, rather

    than the MVC approach? @Jack_Franklin 16
  17. The Theory @Jack_Franklin 17

  18. @Jack_Franklin 18

  19. A page is a series of components Made up of

    HTML, CSS and JavaScript 2 2 not necessarily all three @Jack_Franklin 19
  20. Pages will reuse the same components Common elements such as

    buttons, form inputs, user avatars, tweets, etc. @Jack_Franklin 20
  21. As it turns out, this approach works pretty well. @Jack_Franklin

    21
  22. @Jack_Franklin 22

  23. The ideas in React are more important than React itself.

    And now exist in a plethora of front end frameworks. @Jack_Franklin 23
  24. I'm using React today because it's what I know best.

    —But this talk is not framework specific and can apply to any form of components. —Whether we're talking Angular, Ember, Vue, web components, or any other system. @Jack_Franklin 24
  25. Approaches and challenges of building good components ✅ @Jack_Franklin 25

  26. Components are designed to be a black box @Jack_Franklin 26

  27. "I want a carousel on my website" <jacks-custom-fancy-carousel speed="1000" infinite-playback>

    </jacks-custom-fancy-carousel> I don't need to care about how the carousel works in order to use it. @Jack_Franklin 27
  28. You should strive for "black box" components. @Jack_Franklin 28

  29. The "black box" approach enables working in isolation @Jack_Franklin 29

  30. @Jack_Franklin 30

  31. @Jack_Franklin 31

  32. @Jack_Franklin 32

  33. You can focus in on one component and one component

    only, without fear of breaking other parts of the site. You and your brain can focus in on the problem area and shut everything else out. @Jack_Franklin 33
  34. We keep all our component code in one folder, to

    help keep things isolated and to avoid directory jumping. @Jack_Franklin 34
  35. Avoid business logic @Jack_Franklin 35

  36. Your components should focus on presentations and interactions class SignUpToNewsletterForm

    extends Component { signUserUp() { // lots of // code here // to sign the user up // to your newsletter } render() { return ( <form> ... </form> ) } } @Jack_Franklin 36
  37. Pull any standalone logic out of your components so you

    can focus on the presentation. import { signUserUp } from '...' class SignUpToNewsletterForm extends Component { signUserUp() { signUserUp(...) } render() { return ( <form> ... </form> ) } } @Jack_Franklin 37
  38. You should keep your components reusable @Jack_Franklin 38

  39. Reusable components have to be configurable @Jack_Franklin 39

  40. ! Hey, please build me a component to view an

    item of clothing on Thread.com @Jack_Franklin 40
  41. class ThreadItem extends Component { render() { return ( <div>

    <ItemImage item={this.props.item} /> <h5>{this.props.item.title}</h5> <ItemPrice item={this.props.item} /> <ItemSentiment item={this.props.item} liked={this.props.item.liked === true} /> </div> ) } } @Jack_Franklin 41
  42. <ThreadItem item={...} /> ! Job done! " @Jack_Franklin 42

  43. Oh, can we make this page show ten different items?

    <ul> <li><ThreadItem item={...} /></li> <li><ThreadItem item={...} /></li> <li><ThreadItem item={...} /></li> <li><ThreadItem item={...} /></li> <li><ThreadItem item={...} /></li> </ul> ! Job done! " @Jack_Franklin 43
  44. OK but now can we make it so it shows

    the brand as well as the title <ThreadItem item={...} showBrand={true} /> ! Job done! " @Jack_Franklin 44
  45. Oh and also if it's on sale we want to

    show the old price alongside the new price <ThreadItem item={...} showBrand={true} showOldPriceBeforeSale={true} /> ! Job done! " @Jack_Franklin 45
  46. And we need to be able to not show the

    item sentiment sometimes <ThreadItem item={...} showBrand={true} showOldPriceBeforeSale={true} showSentiment={false} /> ! Job done... @Jack_Franklin 46
  47. For some items we want to show the brand instead

    of the name <ThreadItem item={...} showBrand={true} showBrandInsteadOfName={true} showOldPriceBeforeSale={true} showSentiment={false} /> ! Job done... @Jack_Franklin 47
  48. ! <ThreadItem item={...} showBrand={false} showBrandInsteadOfName={true} showOldPriceBeforeSale={true} showSentiment={false} /> Good luck

    understanding all these options in six months time... @Jack_Franklin 48
  49. @Jack_Franklin 49

  50. You will constantly play configurability off against maintainability. You as

    a developer and as a team will need to come up with a set of rules that suit you. @Jack_Franklin 50
  51. Optimise for developer readability @Jack_Franklin 51

  52. CSS @Jack_Franklin 52

  53. Every component should provide its styling. @Jack_Franklin 53

  54. @Jack_Franklin 54

  55. And none of them should conflict with each other. @Jack_Franklin

    55
  56. Approaches to CSS —Class names per component —Enforced uniqueness via

    CSS Modules —CSS-in-JS @Jack_Franklin 56
  57. This is a big topic that I can only talk

    briefly about @Jack_Franklin 57
  58. Class names .jacks-carousel { } .jacks-carousel ul { } .jacks-carousel

    li { } /* and so on */ @Jack_Franklin 58
  59. All it takes is one slip... <!-- this is not

    a carousel but the styling is pretty similar and I'm under time pressure so I'll just use it anyway --> <div class="jacks-carousel"> @Jack_Franklin 59
  60. @Jack_Franklin 60

  61. 1. Define our CSS as normal. 2. Import our CSS

    (with a build tool like Webpack in the middle). 3. Use the classnames as generated at build time. @Jack_Franklin 61
  62. Class names are guaranteed to be unique. @Jack_Franklin 62

  63. CSS in JavaScript @Jack_Franklin 63

  64. const Button = styled.button` color: red; background: green; ` class

    TweetButton extends React.Component { render() { return ( <Button> New tweet! </Button> ) } } @Jack_Franklin 64
  65. https://javascriptplayground.com/introduction-to- styled-components-react/ @Jack_Franklin 65

  66. It's up to your team to decide what's best for

    you and your project There are many different solutions and many different libraries; experiment with a few and pick the ones that works best :) @Jack_Franklin 66
  67. When to break components down @Jack_Franklin 67

  68. Should this component actually be two? @Jack_Franklin 68

  69. Components are cheap, but not free —You pay in maintenance;

    more code and UI to maintain —You pay in complexity; another component that exists in your application —You pay in communication; this component will have to talk to others to get data @Jack_Franklin 69
  70. Components should be small, and you should have lots. @Jack_Franklin

    70
  71. But how to know when a component is too big?

    —How many lines of code is it? —How many different HTML elements are there? —How hard is this file to understand? —Does the name have (or should have) an And in it? ItemNameAndPrice. @Jack_Franklin 71
  72. Allowing components to vary slightly ! @Jack_Franklin 72

  73. @Jack_Franklin 73

  74. Similarities Differences The icons Slight visual variations The like/dislike logic

    They are displayed next to each other Basically everything is the same but no the designer knows best 3 3 you should discuss if the variations make sense, but I guarantee you that they will at least some of the time @Jack_Franklin 74
  75. How do you have components that are 95% the same?

    @Jack_Franklin 75
  76. Explicitly allow component variants const SENTIMENT_VARIANTS = { QUICKVIEW_BUTTONS, MOBILE_ICONS,

    FADING_ICONS, } <ThreadSentiment variant={SENTIMENT_VARIANTS.FADING_ICONS} /> @Jack_Franklin 76
  77. The key here is to explicitly allow just a few

    And you can apply CSS classes accordingly. .itemSentiment { ... } .itemSentimentVariantFadingIcons { ... } @Jack_Franklin 77
  78. Always favour explicit code over implicit knowledge @Jack_Franklin 78

  79. Beware breaking the abstraction @Jack_Franklin 79

  80. We've talked about how components should be black boxes. @Jack_Franklin

    80
  81. A good way to figure out if you're sticking to

    this is this: Could you take a brand new project, and place your component into it, with no other set up required? @Jack_Franklin 81
  82. But the answer cannot always be yes @Jack_Franklin 82

  83. Some of your components will have to talk to the

    rest of your application. The trick is minimising how many and coming up with a structure to it. Don't allow any component to implicitly rely on some data. @Jack_Franklin 83
  84. Giving components data. @Jack_Franklin 84

  85. 3 approaches —Components fetch data from your server via an

    API call —Components are given data from the server when it renders the HTML —Components parse data left for them in script tags @Jack_Franklin 85
  86. APIs 1. Component initially renders a loading spinner (or nothing)

    2. Component fetches from /your/api/some- endpoint.json 3. Component updates to show the data it has. 4. Component updates to show an error if anything went wrong. @Jack_Franklin 86
  87. APIs ✅ ❌ Ensures we always have the most up

    to date data Adds extra loading state Easy to re-fetch the data if we need to Introduces chance of error Component is network dependent Component will be slower to show data to the user @Jack_Franklin 87
  88. Data from the server <jacks-carousel items="{JSON from server}"> </jacks-carousel> @Jack_Franklin

    88
  89. <thread-product-sentiment item-id="13191186" add-dislike="/xhr/structured-feedback2/13191186/negative" remove-dislike="/xhr/structured-feedback2/13191186/negative/delete" add-like="/xhr/structured-feedback2/13191186/positive" remove-like="/xhr/structured-feedback2/13191186/positive/delete" dislike-reasons-url="/api/negative-feedback-tags/13191186" sentiment="neutral"> </thread-product-sentiment> @Jack_Franklin

    89
  90. Data from server ✅ ❌ We get the data immediately

    from our server Data might be out of date if the user has performed an action since rendering Fewer states to worry about (no loading or error) Creates long strings of JSON in HTML @Jack_Franklin 90
  91. Data in script tags @Jack_Franklin 91

  92. Write a small util around your global config import {

    getConfigValue } from 'lib/global-config' const userIsLoggedIn = getConfigValue('user.authenticated', false) @Jack_Franklin 92
  93. ✅ ❌ Useful only for data that needs to be

    globally available Can lead to a huge set of config if used too much. A good way of setting data that can be accessed from anywhere on the site. Won't be updated if the data changes. @Jack_Franklin 93
  94. Think carefully about all the different approaches and the ones

    that work best for each component individually. Type Situation APIs Good for data that changes and needs to be up to date Data from server Good for component specific data that won't change Global config Good for data that any component might need, and that won't change. @Jack_Franklin 94
  95. The path to components today ! @Jack_Franklin 95

  96. It's easy to introduce some of these ideas to an

    existing project. @Jack_Franklin 96
  97. Not everything has to be a single page application Servers

    are still useful. @Jack_Franklin 97
  98. @Jack_Franklin 98

  99. Take Thread, for example —~5 years old, built as a

    server side Django app that renders HTML via templates to the client. —JavaScript is layered on top via plain old JavaScript and jQuery. —We now have ~50 components (give or take) and that number is going up all the time. @Jack_Franklin 99
  100. @Jack_Franklin 100

  101. Wrapping with web elements 4 4 https://github.com/PixelsCommander/ReactiveElements @Jack_Franklin 101

  102. In our JavaScript: import ThreadItemCard from './components/item-card.jsx' document.registerReact('thread-item-card', ThreadItemCard) In

    our server's templates: <thread-item-card item="{...}"></thread-item-card> @Jack_Franklin 102
  103. We can introduce React and our component system without having

    to rewrite a lot of functionality that we already have on the server. And when we don't need JavaScript, we can still just render HTML and CSS via our server (!) ! @Jack_Franklin 103
  104. Dealing with legacy code CollectPlusAPI.initialise( $('.collect-plus-widget'), { ... } )

    @Jack_Franklin 104
  105. Wrap it in a component! class ReactCollectPlus extends Component {

    componentDidMount() { // legacy JS goes here CollectPlusAPI... } } <thread-collect-plus ...></thread-collect-plus> @Jack_Franklin 105
  106. The black box abstraction can be used to hide away

    bad code in a layer of good @Jack_Franklin 106
  107. The "black boxyness" of components lets you try new technology

    @Jack_Franklin 107
  108. How we adopted CSS Modules at Thread @Jack_Franklin 108

  109. ! Hey, I think that CSS Modules might be a

    good thing, for reasons X, Y and Z @Jack_Franklin 109
  110. ! Sounds good to me, let's try it! @Jack_Franklin 110

  111. ! So I built our new component using it -

    what do you think? @Jack_Franklin 111
  112. ! Looks great, let's ship it and see how we

    find it on our next few projects. @Jack_Franklin 112
  113. After a few weeks we can decide either way. @Jack_Franklin

    113
  114. Yes, all your components should be written using the same

    set of tools and techniques. But launching one that's built differently to learn about something provides a lot of value. @Jack_Franklin 114
  115. It's easy to get distracted talking about the benefits of

    a new tool/language in theory But components let you just do it. @Jack_Franklin 115
  116. To sum up... —Keep your components small and be wary

    of too much configuration —Beware anything that breaks the black box abstraction —Prefer explicit code over implicit knowledge of how your components interact —We're all figuring this out together, as we go. @Jack_Franklin 116
  117. It's a very exciting time to be a front end

    developer! @Jack_Franklin 117
  118. FRONTENDNE for 50% off https:// javascriptplayground.com/ testing-react-enzyme-jest/ @Jack_Franklin 118

  119. Thank you. @Jack_Franklin speakerdeck.com/jackfranklin We're hiring! jack at thread dot

    com @Jack_Franklin 119