Using VueJS in front of Drupal 8

2114c58e94a67d3fb1b516053f97158f?s=47 Brian Ward
November 10, 2015

Using VueJS in front of Drupal 8

Learn how to create beautiful, maintainable and de-coupled applications with Drupal 8.

Source code: https://github.com/briward/examples/tree/master/using-vuejs-in-front-of-drupal-8

More: http://briward.com

2114c58e94a67d3fb1b516053f97158f?s=128

Brian Ward

November 10, 2015
Tweet

Transcript

  1. Using Vue.js in front of Drupal 8 @brian_ward 1

  2. Hello, i’m Bri(an) • Twitter: @brian_ward • Drupal: drupal.org/u/briward •

    Website: briward.com 2 @brian_ward
  3. Yeah, well, that's just, like, your opinion, man.

  4. None
  5. It’s finally here(ish)! 8 It’s now easier than ever to

    get off the island. 5 @brian_ward
  6. “But we already have a theme-layer in Drupal?” 6 @brian_ward

    But we already have a theme-layer in Drupal?
  7. Remember, you don’t have to make it fully headless @brian_ward

    But we already have a theme-layer in Drupal? 7
  8. Drupal system Complex user form Interactive feature Pages Listings Game?!

  9. benefits? • Flexibility. • Decoupled architecture. • (easily) Upgradable/changeable front-end.

    • Dedicated/Focused teams. • Happy front-end developers. 9 @brian_ward But we already have a theme-layer in Drupal? What are the
  10. So what do we get out of the box? 10

    @brian_ward So what do we get out of the box?
  11. RESTful Web Services RESTful Web Services exposes entities and other

    resources as a RESTful web API. Required 11 @brian_ward So what do we get out of the box?
  12. Serialization Serialization module provides a service for (de)serializing data to/from

    formats such as JSON and XML Required 12 @brian_ward So what do we get out of the box?
  13. HAL Serializes entities using Hypertext Application Language (HAL) Optional 13

    @brian_ward So what do we get out of the box?
  14. RESTUI Provides a user interface for managing REST resources. Recommended

    14 @brian_ward So what do we get out of the box?
  15. 3 ways to create a REST API with D8 15

    @brian_ward 3 ways to create a REST API with D8
  16. 16 @brian_ward 3 ways to create a REST API with

    D8 Using the core RestResources Using View REST exports Create custom REST resources Option #1 Option #2 Option #3
  17. Using the core REST resources /node/{node} /entity/block/{block} /comment/{comment} /entity/comment_type/{comment_type} @brian_ward

    17 Option #1 Using the core REST resources
  18. Demonstration @brian_ward 18 Short Using the core REST resources

  19. None
  20. Pros & Cons @brian_ward 20 ✓ Straight out of the

    box. ✓ Requires almost no setup. ✓ No custom code necessary. - Exposes system information. - Absolutely no flexibility. - Lacks ability to version. - Unable to limit output. Using the core REST resources
  21. Using views REST export Views is now in core and

    also comes bundled with REST support out of the box. 21 @brian_ward Option #2 Using views REST export
  22. @brian_ward 22 Demonstration Short Using views REST export

  23. 23 @brian_ward Pros & Cons ✓ Straight out of the

    box. ✓ Familiar to developers. ✓ Manageable within the UI. - Returns data with incorrect types. - More flexibility, but still limited in various areas. - Authentication issues. Using views REST export
  24. Creating custom REST resources Option #3 (recommended) Being object-oriented by

    nature, D8 allows us to extend the base ResourceBase class and create our own custom resources. This would be my recommendation. 24 @brian_ward Creating custom rest resources
  25. /**
 * Provides a resource to get articles by UUID.


    *
 * @RestResource(
 * id = "articles",
 * label = @Translation("Articles (v1.0)"),
 * uri_paths = {
 * "canonical" = "/api/v1.0/articles/{uuid}"
 * }
 * )
 */
 class ArticleBundleResource extends ResourceBase { } 25 Plugin/Rest/Resource/ArticleBundleResource.php @brian_ward
  26. public function getArticle($uuid) {
 $entity = \Drupal::entityManager()->getStorage(‘node') ->loadByProperties([
 'uuid' =>

    $uuid,
 'type' => 'article'
 ]);
 
 return reset($entity);
 } 26 Plugin/Rest/Resource/ArticleBundleResource.php @brian_ward
  27. public function get($uuid = NULL) {
 if (Uuid::isValid($uuid)) {
 $entity

    = $this->getArticle($uuid);
 return new ResourceResponse($this->transform($entity)); } else {
 return new ResourceResponse([
 ‘http_code’ => 400, ‘error' => 100,
 'message' => 'The UUID supplied is invalid.'
 ], 400); 
 }
 } 27 Plugin/Rest/Resource/ArticleBundleResource.php @brian_ward
  28. private function transform($entity) {
 return [ 'id' => (int) $entity->nid[0]->value,


    'title' => (string) $entity->title[0]->value, 'published' => (bool) $entity->published[0]->value,
 ]; 
 } 28 Plugin/Rest/Resource/ArticleBundleResource.php @brian_ward
  29. Pros & Cons ✓ Provides most flexibility. ✓ Transformable output.

    ✓ Easier to manage versions. - Requires reasonable programming knowledge. @brian_ward 29 Creating custom rest resources
  30. HATEOAS API Theory HATEOAS is a constraint of the REST

    application architecture. In a nutshell, it is providing information on how to navigate the site's REST resources dynamically by including hypermedia links with the responses. 30 @brian_ward HATEOAS
  31. Content negotiation To put it simply, this is the mechanism

    for determining what content-type the data will be returned in. 31 @brian_ward HATEOAS
  32. Content negotiation 32 @brian_ward HATEOAS ?_format=json Basically, this is the

    mechanism for determining what content-type the data will be returned in. Ideally, we would want to use an “accept” header.
  33. None
  34. Hypermedia controls 34 Provide links to related endpoints so users

    of your api can easily find their way around your data. @brian_ward HATEOAS
  35. private function transform($entity) {
 return [
 'links' => [
 [


    'rel' => 'self',
 'uri' => '/api/v1.0/articles/'.$entity->uuid[0]->value
 ]
 ]
 ]; 
 } 35 Plugin/Rest/Resource/ArticleBundleResource.php @brian_ward
  36. 'links' => [
 [
 'rel' => 'self',
 'uri' => '/api/v1.0/articles/'.$entity->uuid[0]->value


    ],
 [
 'rel' => ‘article.comments’,
 'uri' => '/api/v1.0/articles/'.$entity->uuid[0]->value.'/comments'
 ]
 ] Plugin/Rest/Resource/ArticleBundleResource.php 36 @brian_ward
  37. None
  38. Versioning 38 @brian_ward As Phil Sturgeon says “There are many

    wrong ways to version your API”. Don’t get too caught up about this.
  39. Authentication 39 @brian_ward • Basic auth • Cookie • oAuth

  40. @brian_ward 40 Now that we have created our API, we

    can play around with it on the front-end. Now we’re ready
  41. Introducing Vue.js Vue.js is a MVVM JavaScript library for building

    modern web interfaces. It provides data-reactive components with a simple and flexible API. @brian_ward 41 Introducing Vue.js
  42. Top trending JS framework on Github. @brian_ward Introducing Vue.js 42

    First stable version released earlier this month. Evan You is also a core developer on the MeteorJS project & previously a Google employee. Has awesome documentation.
  43. None
  44. View new Vue({ el: '#app' }) Each Vue instance is

    associated with a DOM element (el). 44 @brian_ward Introducing Vue.js
  45. ViewModel 45 @brian_ward new Vue({ /* options */ }) •

    An object that syncs the Model and the View. • Every Vue instance is a ViewModel. Introducing Vue.js
  46. Model new Vue({ data: {} }) An object that is

    used as data inside a Vue instance will become reactive (Vue instances that are observing our objects will be notified of the changes). @brian_ward 46 Introducing Vue.js
  47. var MyComponent = Vue.extend({}) Components 47 @brian_ward Components are simply

    a convenient way to structure and organise our applications. Optional Introducing Vue.js
  48. Browserify & Vueify require('./app.vue') 48 @brian_ward Browserify lets you require('modules')

    in the browser by bundling up all of your dependencies. Optional Introducing Vue.js
  49. this.$http.get(url, callback) VueResource Using the official Vue-Resource plugin, we can

    request and store our Drupal content as data objects. Recommended 49 @brian_ward Introducing Vue.js
  50. router.on(url, callback) Director A tiny and isomorphic URL router for

    JavaScript Recommended 50 @brian_ward Introducing Vue.js
  51. So where does Drupal come in? 51 @brian_ward Introducing Vue.js

  52. None
  53. Great, let’s see that in action! Firstly we will need

    to create our package.json, HTML & bootstrap JS files. From there we’ll load in our components and interact with our API. @brian_ward 53 Introducing Vue.js
  54. {
 "main": "./src/app.js",
 "scripts": {
 "watch": "watchify -v -t vueify

    -e ./src/app.js -o build/build.js"
 },
 "devDependencies": {
 "vueify": "^1.1.5",
 "watchify": "^3.3.1"
 },
 "dependencies": {
 "director": "^1.2.8",
 "vue": "^0.12.9",
 "vue-resource": "^0.1.11"
 }
 } package.json 54 @brian_ward
  55. <!DOCTYPE html>
 <html>
 <head>
 <meta charset=“utf-8"> 
 </head>
 <body>
 


    <div id="app"></div>
 
 <!-- Load our build script -->
 <script src="build/build.js"></script>
 
 </body>
 </html> 55 index.html @brian_ward
  56. /**
 * Boot up the Vue instance with the VueResource

    plugin.
 */
 var Vue = require(‘vue') 
 Vue.use(require(‘vue-resource’)) var app = new Vue(require('./app.vue')) 56 start.js @brian_ward
  57. /**
 * Wire up the router.
 */
 var Router =

    require('director').Router
 var router = new Router()
 
 router.on(‘/articles/:uuid’, function (uuid) {
 app.view = 'article-view'
 app.params.uuid = uuid
 })
 
 router.init('/') 57 start.js @brian_ward
  58. <template>
 <component is="{{ view }}"
 class="view"
 params="{{ params }}"
 v-transition


    transition-mode="out-in">
 </component>
 </template> 58 app.vue @brian_ward
  59. <script>
 module.exports = {
 el: '#app',
 data: {
 view: '',


    params: {
 uuid: ''
 }
 },
 components: {
 'article-view': require('./views/article-view.vue')
 }
 }
 </script> 59 app.vue @brian_ward
  60. <template>
 <div class="post full">
 <article class="post-content">
 <h1 v-text="article.title"></h1>
 <div v-html="article.body"></div>


    </article>
 </div>
 </template> 60 article-view.vue @brian_ward
  61. 61 <template>
 <div class="post full">
 <article class="post-content">
 <h1>{{ article.title }}</h1>


    <div>{{{ article.body }}}</div>
 </article>
 </div>
 </template> @brian_ward article-view.vue
  62. <script>
 module.exports = {
 props: ['params'],
 data: function () {


    return {
 article: {}
 }
 },
 ready: function() { var url = '/api/v1.0/articles/' + uuid + '?_format=json';
 this.$http.get(url, function (article) {
 this.$set('article', article)
 })
 } }
 </script> 62 @brian_ward article-view.vue
  63. And that’s it. By using Drupal 8 and Vue.js we’re

    able to create a beautiful, maintainable and de-coupled application. https://github.com/briward/examples 63 @brian_ward
  64. None
  65. Useful links 65 @brian_ward • http://vuejs.org • https://en.wikipedia.org/wiki/Model_View_ViewModel • http://browserify.org

    • https://github.com/vuejs/vueify • http://vuejs.org/guide/components.html • http://www.w3.org/TR/components-intro • http://drupal.org/project/restui • ...how-to-enable-cors-requests-against-drupal-8/ • Phil Sturgeon’s book “Build APIs you won’t hate”.