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

Drupaldelphia 2018: Drupal Unhitched: The CMS in Decoupled Architectures

Drupaldelphia 2018: Drupal Unhitched: The CMS in Decoupled Architectures

dirtystylus

April 27, 2018
Tweet

More Decks by dirtystylus

Other Decks in Technology

Transcript

  1. Drupal Unhitched
    The CMS in Decoupled
    Architectures
    Drupaldelphia 2018
    Drupal Unhitched / @dirtystylus 1

    View Slide

  2. Hi.
    Mark Llobrera
    Technology Director, Bluecadet Philadelphia
    @dirtystylus
    @bluecadet
    Drupal Unhitched / @dirtystylus 2

    View Slide

  3. Drupal Unhitched / @dirtystylus 3

    View Slide

  4. Drupal Unhitched / @dirtystylus 4

    View Slide

  5. Drupal Unhitched / @dirtystylus 5

    View Slide

  6. Descriptive, Not
    Prescriptive
    I’m not telling you how to do this
    stuff. But I hope all of this helps.
    Drupal Unhitched / @dirtystylus 6

    View Slide

  7. 3 Things
    Drupal Unhitched / @dirtystylus 7

    View Slide

  8. 3 Things
    1. What is a decoupled CMS?
    Drupal Unhitched / @dirtystylus 7

    View Slide

  9. 3 Things
    1. What is a decoupled CMS?
    2. Decoupled Scenarios
    Drupal Unhitched / @dirtystylus 7

    View Slide

  10. 3 Things
    1. What is a decoupled CMS?
    2. Decoupled Scenarios
    3. Decoupling Drupal
    Drupal Unhitched / @dirtystylus 7

    View Slide

  11. 1. What is a
    Decoupled CMS?
    Drupal Unhitched / @dirtystylus 8

    View Slide

  12. What is a decoupled CMS?
    Drupal Unhitched / @dirtystylus 9

    View Slide

  13. What is a decoupled CMS?
    —An architecture for websites and applications
    where the CMS is not used to render the user-
    facing site or application.
    Drupal Unhitched / @dirtystylus 9

    View Slide

  14. Stop me if you’ve heard
    this one before
    Drupal Unhitched / @dirtystylus 10

    View Slide

  15. Separating
    CONTENT
    from
    PRESENTATION
    Drupal Unhitched / @dirtystylus 11

    View Slide

  16. 2. Decoupled
    Scenarios
    Drupal Unhitched / @dirtystylus 12

    View Slide

  17. CMS (Drupal 8)
    +
    Touchscreen Interactive (React)
    +
    JS Website (React)
    Drupal Unhitched / @dirtystylus 13

    View Slide

  18. Drupal Unhitched / @dirtystylus 14

    View Slide

  19. Drupal Unhitched / @dirtystylus 15

    View Slide

  20. Drupal Unhitched / @dirtystylus 16

    View Slide

  21. Drupal Unhitched / @dirtystylus 17

    View Slide

  22. Drupal Unhitched / @dirtystylus 18

    View Slide

  23. CMS (Drupal 8)
    +
    CMS-rendered Website
    +
    Digital Signage (React)
    Drupal Unhitched / @dirtystylus 19

    View Slide

  24. Drupal Unhitched / @dirtystylus 20

    View Slide

  25. Drupal Unhitched / @dirtystylus 21

    View Slide

  26. Drupal Unhitched / @dirtystylus 22

    View Slide

  27. Drupal Unhitched / @dirtystylus 23

    View Slide

  28. CMS
    +
    CMS-rendered Website
    +
    React components
    Drupal Unhitched / @dirtystylus 24

    View Slide

  29. Drupal Unhitched / @dirtystylus 25

    View Slide

  30. Drupal Unhitched / @dirtystylus 26

    View Slide

  31. CMS
    +
    Statically Published React (GatsbyJS)
    Drupal Unhitched / @dirtystylus 27

    View Slide

  32. Drupal Unhitched / @dirtystylus 28

    View Slide

  33. Drupal Unhitched / @dirtystylus 29

    View Slide

  34. Drupal Unhitched / @dirtystylus 30

    View Slide

  35. Drupal Unhitched / @dirtystylus 31

    View Slide

  36. CMS (Drupal 7)
    +
    CMS-rendered Website
    +
    Touch Wall (Cinder/C++)
    +
    2 Touchscreen Interactives (AngularJS)
    +
    iOS / Android Native Applications
    Drupal Unhitched / @dirtystylus 32

    View Slide

  37. Drupal Unhitched / @dirtystylus 33

    View Slide

  38. Drupal Unhitched / @dirtystylus 34

    View Slide

  39. Drupal Unhitched / @dirtystylus 35

    View Slide

  40. Drupal Unhitched / @dirtystylus 36

    View Slide

  41. Drupal Unhitched / @dirtystylus 37

    View Slide

  42. Drupal Unhitched / @dirtystylus 38

    View Slide

  43. PROS
    and
    CONS
    Drupal Unhitched / @dirtystylus 39

    View Slide

  44. Pros
    Drupal Unhitched / @dirtystylus 40

    View Slide

  45. Pros
    —Back and Front End systems are swappable
    Drupal Unhitched / @dirtystylus 40

    View Slide

  46. Pros
    —Back and Front End systems are swappable
    —Teams can divide and conquer
    Drupal Unhitched / @dirtystylus 40

    View Slide

  47. Cons
    Drupal Unhitched / @dirtystylus 41

    View Slide

  48. Cons
    —Larger tech stack (Drupal, JS, multiple
    environments)
    Drupal Unhitched / @dirtystylus 41

    View Slide

  49. Cons
    —Larger tech stack (Drupal, JS, multiple
    environments)
    —Maintenance
    Drupal Unhitched / @dirtystylus 41

    View Slide

  50. Cons
    —Larger tech stack (Drupal, JS, multiple
    environments)
    —Maintenance
    —For websites you lose built-in functionality of
    CMS: menus/routing/accessibility/SEO
    Drupal Unhitched / @dirtystylus 41

    View Slide

  51. 3. Decoupling
    Drupal
    Drupal Unhitched / @dirtystylus 42

    View Slide

  52. Start with Content
    Drupal Unhitched / @dirtystylus 43

    View Slide

  53. Start with Content
    —Getting content ready to travel
    Drupal Unhitched / @dirtystylus 43

    View Slide

  54. Start with Content
    —Getting content ready to travel
    —NO Presentation specific names NO
    Drupal Unhitched / @dirtystylus 43

    View Slide

  55. Start with Content
    —Getting content ready to travel
    —NO Presentation specific names NO
    —Decouple your mind
    Drupal Unhitched / @dirtystylus 43

    View Slide

  56. Start with Content
    —Getting content ready to travel
    —NO Presentation specific names NO
    —Decouple your mind
    —Content in many forms/faces
    Drupal Unhitched / @dirtystylus 43

    View Slide

  57. Two Content Types
    Drupal Unhitched / @dirtystylus 44

    View Slide

  58. Two Content Types
    —Author
    Drupal Unhitched / @dirtystylus 44

    View Slide

  59. Two Content Types
    —Author
    —Book
    Drupal Unhitched / @dirtystylus 44

    View Slide

  60. Author
    Drupal Unhitched / @dirtystylus 45

    View Slide

  61. Book
    Drupal Unhitched / @dirtystylus 46

    View Slide

  62. HOW??
    Drupal Unhitched / @dirtystylus 47

    View Slide

  63. HOW??
    —Core: RESTful Web Services
    Drupal Unhitched / @dirtystylus 47

    View Slide

  64. HOW??
    —Core: RESTful Web Services
    —Custom Controller
    Drupal Unhitched / @dirtystylus 47

    View Slide

  65. HOW??
    —Core: RESTful Web Services
    —Custom Controller
    —JSON API
    Drupal Unhitched / @dirtystylus 47

    View Slide

  66. HOW??
    —Core: RESTful Web Services
    —Custom Controller
    —JSON API
    —GraphQL
    Drupal Unhitched / @dirtystylus 47

    View Slide

  67. RESTful Web Services
    Two basic approaches:
    Drupal Unhitched / @dirtystylus 48

    View Slide

  68. RESTful Web Services
    Two basic approaches:
    —Core RESTful Services
    Drupal Unhitched / @dirtystylus 48

    View Slide

  69. RESTful Web Services
    Two basic approaches:
    —Core RESTful Services
    —REST Exports
    Drupal Unhitched / @dirtystylus 48

    View Slide

  70. Core RESTful Services
    Drupal Unhitched / @dirtystylus 49

    View Slide

  71. Core RESTful Services
    —Core REST Module
    Drupal Unhitched / @dirtystylus 49

    View Slide

  72. Core RESTful Services
    —Core REST Module
    —REST UI Module https://drupal.org/project/restui
    Drupal Unhitched / @dirtystylus 49

    View Slide

  73. Request:
    /node/1?format=json
    Drupal Unhitched / @dirtystylus 50

    View Slide

  74. {
    "nid": [
    {
    "value": 1
    }
    ],
    "uuid": [
    {
    "value": "3036ea2d-7502-4c64-8bc6-2e9ee3a0f897"
    }
    ],
    "vid": [
    {
    "value": 1
    }
    ],
    "langcode": [
    {
    "value": "en"
    }
    ],
    "type": [
    {
    "target_id": "book",
    "target_type": "node_type",
    "target_uuid": "a3c32842-68b2-46fd-b70e-d6ed9e71ee2d"
    }
    ],
    "revision_timestamp": [
    {
    "value": "2018-04-23T18:10:59+00:00",
    "format": "Y-m-d\\TH:i:sP"
    }
    ],
    "revision_uid": [
    {
    "target_id": 1,
    "target_type": "user",
    "target_uuid": "a7484c09-d013-402e-b070-46c0d84a7b28",
    "url": "/user/1"
    }
    ],
    "revision_log": [],
    "status": [
    {
    "value": true
    }
    ],
    "title": [
    {
    "value": "The Fifth Season"
    }
    ],
    "uid": [
    {
    "target_id": 1,
    "target_type": "user",
    "target_uuid": "a7484c09-d013-402e-b070-46c0d84a7b28",
    "url": "/user/1"
    }
    ],
    "created": [
    {
    "value": "2018-04-23T18:10:29+00:00",
    "format": "Y-m-d\\TH:i:sP"
    }
    ],
    "changed": [
    {
    "value": "2018-04-23T18:10:59+00:00",
    "format": "Y-m-d\\TH:i:sP"
    }
    ],
    "promote": [
    {
    "value": true
    }
    ],
    "sticky": [
    {
    "value": false
    }
    ],
    "default_langcode": [
    {
    "value": true
    }
    ],
    "revision_translation_affected": [
    {
    "value": true
    }
    ],
    "path": [
    {
    "alias": null,
    "pid": null,
    "langcode": "en"
    }
    ],
    "body": [
    {
    "value": "Part one of the Broken Earth trilogy.\r\n",
    "format": "basic_html",
    "processed": "Part one of the Broken Earth trilogy.",
    "summary": ""
    }
    ]
    }
    Drupal Unhitched / @dirtystylus 51

    View Slide

  75. {
    "nid": [
    {
    "value": 1
    }
    ],
    "type": [
    {
    "target_id": "book",
    "target_type": "node_type",
    "target_uuid": "a3c32842-68b2-46fd-b70e-d6ed9e71ee2d"
    }
    ],
    "title": [
    {
    "value": "The Fifth Season"
    }
    ],
    "body": [
    {
    "value": "Part one of the Broken Earth trilogy.\r\n",
    "format": "basic_html",
    "processed": "Part one of the Broken Earth trilogy.",
    "summary": ""
    }
    ]
    }
    Drupal Unhitched / @dirtystylus 52

    View Slide

  76. REST Exports
    Drupal Unhitched / @dirtystylus 53

    View Slide

  77. REST Exports
    —Views! (! old friend)
    Drupal Unhitched / @dirtystylus 53

    View Slide

  78. REST Exports
    —Views! (! old friend)
    —“Provide a REST Export” checkbox ✅
    Drupal Unhitched / @dirtystylus 53

    View Slide

  79. Drupal Unhitched / @dirtystylus 54

    View Slide

  80. Drupal Unhitched / @dirtystylus 55

    View Slide

  81. Drupal Unhitched / @dirtystylus 56

    View Slide

  82. [
    {
    "title": "Kim Stanley Robinson",
    "body": "Author of the Mars trilogy and New York 2140.\r\n",
    "field_books": [
    "2"
    ]
    },
    {
    "title": "N. K. Jemisin",
    "body": "Hugo Award-winning author of the Broken Earth trilogy.\r\n",
    "field_books": [
    "1"
    ]
    }
    ]
    Drupal Unhitched / @dirtystylus 57

    View Slide

  83. Custom Controller
    Drupal Unhitched / @dirtystylus 58

    View Slide

  84. Custom Controller
    Drupal Unhitched / @dirtystylus 59

    View Slide

  85. Custom Controller
    —Routing (YML)
    Drupal Unhitched / @dirtystylus 59

    View Slide

  86. Custom Controller
    —Routing (YML)
    —Controller Class
    Drupal Unhitched / @dirtystylus 59

    View Slide

  87. Routing
    mann.season:
    path: 'api/season'
    defaults:
    _controller: \Drupal\mann_api\Controller\Season::api
    methods: [GET]
    requirements:
    _access: 'TRUE'
    Drupal Unhitched / @dirtystylus 60

    View Slide


  88. $a_query = \Drupal::entityQuery('node');
    $a_query->condition('status', 1);
    $a_query->condition('type', 'event');
    $entity_ids = $a_query->execute();
    $events = Node::loadMultiple($entity_ids);
    foreach ($events as $event) {
    $item['id'] = (int) $event->nid->value;
    $date = $event->field_event_date->value;
    $item['date'] = $date;
    $item['title'] = $event->title->value;
    $item['display_title'] = $event->field_display_title->value;
    $image_data = MediaAssetService::getMediaPathSingle($event, 'field_featured_image');
    $item['image'] = urldecode($image_data['image']);
    $item['image_relative'] = urldecode($image_data['image_relative']);
    $data[] = $item;
    }
    $response = new JsonResponse(['data' => $data]);
    return $response;

    Drupal Unhitched / @dirtystylus 61

    View Slide

  89. JSON API
    https://www.drupal.org/project/jsonapi
    Drupal Unhitched / @dirtystylus 62

    View Slide

  90. Out of the box:
    /jsonapi/node/[Content Type]
    for example:
    /jsonapi/node/author
    Drupal Unhitched / @dirtystylus 63

    View Slide

  91. {
    "data": [
    {
    "type": "node--author",
    "id": "88223a76-278d-4fc6-9945-0bdb56cc78d3",
    "attributes": {
    "nid": 2,
    "body": {
    "value": "Winner of the Hugo Award.\r\n",
    "format": "basic_html",
    "processed": "Winner of the Hugo Award.",
    "summary": ""
    },
    "field_display_name": {
    "value": "N. K. Jemisin",
    "format": "basic_html",
    "processed": "N. K. Jemisin"
    }
    },
    "relationships": {
    "field_books": {
    "data": [
    {
    "type": "node--book",
    "id": "e8c31c68-4fe5-4046-ab3f-1cb42e1f314f"
    }
    ],
    },
    }
    ],
    }
    Drupal Unhitched / @dirtystylus 64

    View Slide

  92. {
    "attributes": {
    "nid": 2,
    "body": {
    "value": "Winner of the Hugo Award.\r\n",
    "format": "basic_html",
    "processed": "\Winner of the Hugo Award.",
    "summary": ""
    },
    "field_display_name": {
    "value": "N. K. Jemisin",
    "format": "basic_html",
    "processed": "N. K. Jemisin"
    }
    },
    }
    Drupal Unhitched / @dirtystylus 65

    View Slide

  93. {
    "relationships": {
    "field_books": {
    "data": [
    {
    "type": "node--book",
    "id": "e8c31c68-4fe5-4046-ab3f-1cb42e1f314f"
    }
    ],
    },
    }
    Drupal Unhitched / @dirtystylus 66

    View Slide

  94. Relationships are complicated
    /jsonapi/node/[Content Type]?include=[Field Name]
    for example (we want field_books):
    /jsonapi/node/author?include=field_books
    Drupal Unhitched / @dirtystylus 67

    View Slide

  95. {
    "included": [
    {
    "type": "node--book",
    "id": "e8c31c68-4fe5-4046-ab3f-1cb42e1f314f",
    "attributes": {
    "nid": 1,
    "title": "The Fifth Season",
    "body": {
    "value": "Part one of the Broken Earth trilogy.\r\n",
    "format": "basic_html",
    "processed": "Part one of the Broken Earth trilogy.",
    "summary": ""
    }
    },
    }
    }
    Drupal Unhitched / @dirtystylus 68

    View Slide

  96. "id": "e8c31c68-4fe5-4046-ab3f-1cb42e1f314f"
    Drupal Unhitched / @dirtystylus 69

    View Slide

  97. GraphQL
    https://www.drupal.org/project/graphql
    Drupal Unhitched / @dirtystylus 70

    View Slide

  98. Installation Note
    Drupal Unhitched / @dirtystylus 71

    View Slide

  99. Installation Note
    —Download the module (or use drush dl
    graphql)
    Drupal Unhitched / @dirtystylus 71

    View Slide

  100. Installation Note
    —Download the module (or use drush dl
    graphql)
    —Run composer require webonyx/graphql-php
    at root level (error otherwise)
    Drupal Unhitched / @dirtystylus 71

    View Slide

  101. Installation Note
    —Download the module (or use drush dl
    graphql)
    —Run composer require webonyx/graphql-php
    at root level (error otherwise)
    —Enable the module
    Drupal Unhitched / @dirtystylus 71

    View Slide

  102. Explorer allows
    you to test out
    queries
    Drupal Unhitched / @dirtystylus 72

    View Slide

  103. Drupal Unhitched / @dirtystylus 73

    View Slide

  104. Auto-complete!
    Drupal Unhitched / @dirtystylus 74

    View Slide

  105. Drupal Unhitched / @dirtystylus 75

    View Slide

  106. Simple Query
    query {
    nodeQuery {
    entities {
    entityId,
    entityLabel
    }
    }
    }
    Drupal Unhitched / @dirtystylus 76

    View Slide

  107. {
    "data": {
    "nodeQuery": {
    "entities": [
    {
    "entityId": "1",
    "entityLabel": "The Fifth Season"
    },
    {
    "entityId": "2",
    "entityLabel": "New York 2140"
    },
    {
    "entityId": "3",
    "entityLabel": "N. K. Jemisin"
    },
    {
    "entityId": "4",
    "entityLabel": "Kim Stanley Robinson"
    }
    ]
    }
    }
    }
    Drupal Unhitched / @dirtystylus 77

    View Slide

  108. Node Query w/ Types (Author)
    query {
    nodeQuery {
    entities {
    ...on NodeAuthor {
    entityId
    title
    body {
    value
    }
    fieldDisplayName {
    value
    }
    fieldBooks {
    entity {
    entityId
    title
    }
    }
    }
    }
    }
    }
    Drupal Unhitched / @dirtystylus 78

    View Slide

  109. References are Easy(ish)
    fieldBooks {
    entity {
    entityId
    title
    }
    }
    Drupal Unhitched / @dirtystylus 79

    View Slide

  110. {
    "data": {
    "nodeQuery": {
    "entities": [
    {},
    {},
    {
    "entityId": "3",
    "title": "N. K. Jemisin",
    "body": {
    "value": "Hugo Award-winning author of the Broken Earth trilogy.\r\n"
    },
    "fieldDisplayName": {
    "value": "N. K. Jemisin"
    },
    "fieldBooks": [
    {
    "entity": {
    "entityId": "1",
    "title": "The Fifth Season"
    }
    }
    ]
    },
    {
    "entityId": "4",
    "title": "Kim Stanley Robinson",
    "body": {
    "value": "Author of the Mars trilogy and New York 2140.\r\n"
    },
    "fieldDisplayName": {
    "value": "Kim Stanley Robinson"
    },
    "fieldBooks": [
    {
    "entity": {
    "entityId": "2",
    "title": "New York 2140"
    }
    }
    ]
    }
    ]
    }
    }
    }
    Drupal Unhitched / @dirtystylus 80

    View Slide

  111. query {
    nodeQuery {
    entities {
    ...on NodeAuthor {
    entityId
    title
    body {
    value
    }
    fieldDisplayName {
    value
    }
    fieldBooks {
    entity {
    entityId
    title
    }
    }
    }
    ...on NodeBook {
    entityId
    title
    body {
    value
    }
    }
    }
    }
    }
    Drupal Unhitched / @dirtystylus 81

    View Slide

  112. Filter by Node Type
    query {
    nodeQuery (filter: {conditions: [{
    field: "type"
    value: "author"
    operator: EQUAL
    }]
    } ) {

    }
    }
    Drupal Unhitched / @dirtystylus 82

    View Slide

  113. query {
    nodeQuery (filter: {conditions: [{
    field: "type"
    value: "author"
    operator: EQUAL
    }]
    } ) {
    entities {
    ...on NodeAuthor {
    entityId
    title
    body {
    value
    }
    fieldBooks {
    entity {
    title
    body {
    value
    }
    }
    }
    }
    }
    }
    }
    Drupal Unhitched / @dirtystylus 83

    View Slide

  114. {
    "data": {
    "nodeQuery": {
    "entities": [
    {
    "entityId": "3",
    "title": "N. K. Jemisin",
    "body": {
    "value": "Hugo Award-winning author of the Broken Earth trilogy.\r\n"
    },
    "fieldBooks": [
    {
    "entity": {
    "title": "The Fifth Season",
    "body": {
    "value": "Part one of the Broken Earth trilogy.\r\n"
    }
    }
    }
    ]
    },
    Drupal Unhitched / @dirtystylus 84

    View Slide

  115. Bonus:
    Communication
    Drupal Unhitched / @dirtystylus 85

    View Slide

  116. We’ve tried:
    Drupal Unhitched / @dirtystylus 86

    View Slide

  117. We’ve tried:
    —Polling for changes (are we there yet?)
    Drupal Unhitched / @dirtystylus 86

    View Slide

  118. We’ve tried:
    —Polling for changes (are we there yet?)
    —NodeJS (get a server in the middle, maybe Socket
    I/O)
    Drupal Unhitched / @dirtystylus 86

    View Slide

  119. Enter Progressive Web Applications
    Drupal Unhitched / @dirtystylus 87

    View Slide

  120. Enter Progressive Web Applications
    —CMS to Application communication is a use case
    Drupal Unhitched / @dirtystylus 87

    View Slide

  121. Enter Progressive Web Applications
    —CMS to Application communication is a use case
    —PWAs have Service Workers and Push
    Notifications
    Drupal Unhitched / @dirtystylus 87

    View Slide

  122. Web Push API
    Drupal Unhitched / @dirtystylus 88

    View Slide

  123. Web Push API
    —Gives web applications the ability to receive messages
    pushed to them from a server
    Drupal Unhitched / @dirtystylus 88

    View Slide

  124. Web Push API
    —Gives web applications the ability to receive messages
    pushed to them from a server
    —Requires a subscription to be activated, but once
    allowed, the subscription is saved by the browser
    Drupal Unhitched / @dirtystylus 88

    View Slide

  125. Web Push API
    —Gives web applications the ability to receive messages
    pushed to them from a server
    —Requires a subscription to be activated, but once
    allowed, the subscription is saved by the browser
    —You can pass “messages”, but fundamentally you are
    passing data for your app or website to interpret as you
    see fit
    Drupal Unhitched / @dirtystylus 88

    View Slide

  126. Web Push API
    —Gives web applications the ability to receive messages
    pushed to them from a server
    —Requires a subscription to be activated, but once
    allowed, the subscription is saved by the browser
    —You can pass “messages”, but fundamentally you are
    passing data for your app or website to interpret as you
    see fit
    —Browsers handle pushing the data through Service
    Workers, so a third party is not required
    Drupal Unhitched / @dirtystylus 88

    View Slide

  127. Fine Print
    Drupal Unhitched / @dirtystylus 89

    View Slide

  128. Fine Print
    —Limited browser support: ✅ Chrome, ✅ Firefox, "
    Safari (coming soon?)
    Drupal Unhitched / @dirtystylus 89

    View Slide

  129. Fine Print
    —Limited browser support: ✅ Chrome, ✅ Firefox, "
    Safari (coming soon?)
    —Spec is considered experimental, so it may change
    in the future
    Drupal Unhitched / @dirtystylus 89

    View Slide

  130. Fine Print
    —Limited browser support: ✅ Chrome, ✅ Firefox, "
    Safari (coming soon?)
    —Spec is considered experimental, so it may change
    in the future
    —Great for kiosks, but in the wild, you can’t
    guarantee that a user will subscribe
    Drupal Unhitched / @dirtystylus 89

    View Slide

  131. Fine Print
    —Limited browser support: ✅ Chrome, ✅ Firefox, "
    Safari (coming soon?)
    —Spec is considered experimental, so it may change
    in the future
    —Great for kiosks, but in the wild, you can’t
    guarantee that a user will subscribe
    —Sockets for non-web-based projects (Cinder/C++,
    Unity)
    Drupal Unhitched / @dirtystylus 89

    View Slide

  132. Drupal Unhitched / @dirtystylus 90

    View Slide

  133. Where to Next?
    Drupal Unhitched / @dirtystylus 91

    View Slide

  134. Where to Next?
    —Two-way communication
    Drupal Unhitched / @dirtystylus 91

    View Slide

  135. Where to Next?
    —Two-way communication
    —Content Authoring via JS Front End (WordPress
    and Drupal)
    Drupal Unhitched / @dirtystylus 91

    View Slide

  136. Takeaways
    Drupal Unhitched / @dirtystylus 92

    View Slide

  137. Takeaways
    —Start with your Content, and make that portable
    Drupal Unhitched / @dirtystylus 92

    View Slide

  138. Takeaways
    —Start with your Content, and make that portable
    —There’s many different ways to expose your
    content
    Drupal Unhitched / @dirtystylus 92

    View Slide

  139. Takeaways
    —Start with your Content, and make that portable
    —There’s many different ways to expose your
    content
    —You can do this!
    Drupal Unhitched / @dirtystylus 92

    View Slide

  140. We’re
    hiring.
    Drupal Unhitched / @dirtystylus 93

    View Slide

  141. THANK YOU.
    Mark Llobrera
    Technology Director, Bluecadet Philadelphia
    @dirtystylus
    @bluecadet
    Drupal Unhitched / @dirtystylus 94

    View Slide