Your browser doesn't support the features required by impress.js, so you are presented with a simplified version of this presentation.

For the best experience please use the latest Chrome, Safari or Firefox browser.

Decoupled Drupal Days

New York 2018

Progressive decoupling

The why and the how

Silver sponsors

Gold sponsors

Diamond sponsors

Session & contribution time co-sponsors

  • The most stressed person in the room
  • First time speaker
Blazej Owczarczyk

PHP & Javascript Developer

Amazee Labs
On for 9 years 12 months
decopuled projects in

React & Vue.js
contributing to

core, GraphQL, and ...
Progressive decoupling
The why
  • Do whatever needs to be done
Fully decoupled


  • Best possible performance
  • Stellar user experinces
  • Do whatever needs to be done
No compromises
with great power comes great
  • Easy tasks become complex


  • Extremly potent
  • Secure
  • Pluggable
  • States system
  • Ajax system
  • Well defined validation - submission flow
  • Validation out of the box
  • Huge component libray, eg. text, email, number, file, entity reference
  • There are no js tools that can be compared to FAPI.
  • Validation and submission need to be implemented from scratch.
  • All the forms need to be built from scratch, even those that drupal handles well.
  • The more entity references the harder the implementation is.
✖ Forms API
  • Views are so good.
  • We are so used to them that we may underestimate the underlying complexity.
  • We're used to the fact that a table listing with paging, exposed filters, click sorting and bulk operations takes a few dozen clicks.
  • Implement the table template from scratch.
  • Add markup for the exposed filters form.
  • Then fetch the initial data with the number of pages and allowed values for exposed filters.
  • Implement a pager.
  • Implement the url parsing logic to get the current page and values for exposed filters.
  • Check which colums are sortable, turn then into links and pass the sort order to the query.
✖ Views
  • Ok when the frontend and the backend share top parts of the domain.
  • No untrusted apps should share it.
  • If not - OAuth.
  • Simple OAuth works fine.
  • Hard to implement securely on frontend (SSR, refreshing tokens).
  • Drupal spoils us.
  • Once we learn the abstractions we become extremly efficient.
  • Lost when going fully decoupled.
  • Sometimes there are no alternatives, eg. mobile apps.
  • However, for web projects we can use...
❤ Drupal ❤
Progressive decoupling
  • Front end frameworks are really easy and intuitive when building components.
of both worlds
  • Login
  • Content editing
  • Existing functionalities
Drupal when you need it
  • Many possibilities.
  • Few examples
decoupled when it makes sense
  • Front end frameworks are really easy and intuitive when building components.
  • decreases page load time (drastically)
  • improves perceived performance
  • reduce webserver's network traffic
data from external sources
  • decoupling makes it easy to test
  • don't even use oAuth
  • requires CORS
rich, testable UIs
  • easy to integrate
  • swap one page or block without touching the rest of the site
existing projects
The how
  • the easiest way to decouple for drupalers
  • use graphql to fetch data
  • render in twig
no js
easy setup
enable graphql_twig
  • declare data dependencies in the template file
  • isolated and self-contained templates
  • power to the themer


{#graphql  query {
    user:currentUserContext {

  Hi { }, good to see you again.
progressive by nature
declare data dependencies using GraphQL

in any twig template
  • maintainer of the GraphQL module
  • really cool guy
  • he can sing, at least it looks like so
Created by Philipp Melab

Modern JS
  • ECMAScript 2015
  • revolutionary changes
Deconstructing assignment
    const { width, height, depth } = product.dimensions
Property shorthand
  const person = { firstName, lastName }
Spread syntax
  const order = { ...customer, ...address }
  • js finally joined the family of laguages supporting default parameters
Default parameter values
  const getProperty = function (object, property = 'value') {
  return object[property]
  • not only syntax
  • inherits this from the parent scope
Arrow functions
  const getArea = (dims) => dims.width * dims.height
... with lexical this
  this.cartItems.forEach(item => { += item.cost
  class Rectangle extends Shape {
  constructor (id, x, y, width, height) {
      super(id, x, y)
      this.width  = width
      this.height = height
class Circle extends Shape {
  constructor (id, x, y, radius) {
      super(id, x, y)
      this.radius = radius
// Example from
  • Multiline
  • inherits this from the parent scope
Template literals
  const greeting = `Hi ${firstName} ${lastName}`
  • ECMAScript 2016
  • not very revolutionary
  • the exponentiation operator **
  • Array.prototype.includes
  • ECMAScript 2017
  • just one feature, but a powerful one
  • The evolution of async code
ES5 - callbacks
  url: '',
  success: function (person) {
      url: person.homeworld,
      success: function (planet) {
        setHomeworld(person, planet)
ES6 - promises
.then(response => response.json())
.then((person) => {
  .then(response => response.json())
  .then((planet) => {
    setHomeworld(person, planet)
  • No callback hell
  • No nesting
  • Looks like sync code
  • Readable
  • Implemented using generators
ES8 - async/await
  const personResponse = await fetch('')
const person = await personResponse.json()

const planetResponse = await fetch(person.homeworld)
const planet = await planetResponse.json()

setHomeworld(person, planet)
  • Since 8.4
Drupal core now using ES6 for javascript development
  • It was designed for drupal core
✔️ core
  • It was designed for drupal core
✖ contrib
  • It was designed for drupal core
✖ custom
  • use package.json from core
  • postponed because of a bug in babel-cli
  • may work (it did at some point)
[#2957390] Use ES6 for contrib and custom JavaScript development
  • Transpilation is not a silver bullet
  • Adding npm packages is tedious
  • It needs to be easy if we want people to start contributing
npm dependencies?
recipe for
  • requires vue-cli
  • vue is just a folder name
Initialize a vue project
  cd my_module
vue create vue
Define a dynamic library
        function hook_library_info_build()
  • add the bundle from webpack dev server to drupal
  • drupal becomes a webpack dev server
  • page reloads when changes to the files are detected
Connect with the dev server
  yarn serve # starts a dev server on port 8080
  $library['js']['http://localhost:8080/app.js'] = [
  'type' => 'external',
  • it's best not to commit dist
  • build for production in a deployment step
  • include the files from dist in production environment
  • the flow is similar in react
Build for prod
  RUN yarn install --pure-lockfile && yarn build
  file_scan_directory($dist_path, '/^.*\.js$/')
        cd my_module
yarn create react-app react
  • possible thanks to the api first initiative
  • read-only data
  • ok for simple widgets
  $library['dependencies'][] = 'core/drupalSettings';
  • guided product selection
  • redirects to a view with facets pre-set
  • built in react
  • zero-latency navigation
  • this is what the users are expecting
  • alternative to core REST and JSON API
  • Reading and querying content entities out of the box
  • Mutations need to be implemented
  • Quite convenenient in general
  • pre-configured package
Install apollo-boost
  yarn add apollo-boost graphql
  • No configuration needed
  • /graphql is the default endpoint
Import it
    import ApolloClient, { gql } from 'apollo-boost';
const client = new ApolloClient();
  • Fetch everything you need in one simple query
  • Picture is a separate entity
  • Nesting level limited by memory limit
  • Response format defined by the query
Have fun!
  const query = gql`
  query {
    user: currentUserContext {
      ... on UserUser {
        picture: userPicture {
const result = await client.query({ query })
const pictureUrl =
Chrome debugger
  • Sources panel is an IDE
  • Exclude framework files from stack traces
  • Component inspector with props and computed props
  • Vuex panel with the current state tree, list of mutations and import / export
  • Event panel with all the emitted vue events
  • Component inspector
developer tools
  • List of queries executed on the current page
  • Run queries in an embedded GraphiQL
developer tools
  • How can we make it easier?
  • Define a central package.json of npm packages, like composer.json
  • Integrate webpack into the library system in core?
make it

released two hours ago :)
Setup: download the module
        composer require drupal/webpack
add package.json to repository root
        yarn init -yp
add webpack's npm dependencies
        yarn add webpack webpack-serve
declare your library...

  webpack: true
    my_library.js: { }
...add npm dependencies...
        yarn add graphql apollo-boost
...and use them is js your code

import ApolloClient, { gql } from 'apollo-boost';

const client = new ApolloClient();
const query = gql`query { currentUserContext: { name } }`;
const result = await client.query({ query });
const name =;

alert(`Hello ${name}! Good to see you.`);
add babel

composer require drupal/webpack_babel
yarn add babel-core babel-loader
const recipient = 'Internet Explorer';
alert(`Hello ${recipient} :)`);
local development
          drush webpack:serve
...with live reload

building on a server
        yarn webpack:build
How does it work?
dynamic config
based on drupal libraries

module.exports = {
  "entry": {
    "module-library-file": "/path/to/module/js/test.js",
  "output": {
    "filename": "[name].bundle.js",
    "path": "/path/to/project/sites/default/files/webpack",
extendable with plugins
(contrib modules)

class SplitChunks extends ConfigProcessorBase {

  public function processConfig(&$config) {
    $config['optimization']['splitChunks']['chunks'] = 'all';

alterable with a hook

function custom_webpack_config_alter(&$config) {
  if (getenv('LAGOON_ENVIRONMENT_TYPE') == 'development') {
    $config['mode'] = 'development';
coming soon


Question time
  • If you have questions or just want to talk
  • The link to slides is on my twitter

Bonus time?
  • Only if there is a reason for that
  • eg. performance is critical and there is budget
Should this next project be fully decoupled?

Use a spacebar or arrow keys to navigate.
Press 'P' to launch speaker console.