Embed EmberJS app in Drupal 8 block
Here’s a quick overview of the requirements I had.
- Use EmberJS to create a Javascript Component Embedded in a single Drupal 8 block
- Only load the ember javascript code on the pages where the block is displayed
- Don’t use a separate stylesheet for the component’s styling
- Don’t change the url on route changes
- Use jQuery included in Drupal Core
Versions
- Drupal 8.0.1
- jQuery 2.1.4 (current version in Drupal core)
- Ember 2.3.0
- Ember Data 2.3.3
- Ember CLI 2.2.0-beta.6 (used for developing, obviously not used in prod)
Configuring Ember
1. Change library versions
When creating a new ember app via Ember CLI, the jQuery and Ember versions were incorrect. Let’s start of by editing our bower.json this is how my bower.json looked after editing
{
“name”: “drupal-component”,
“dependencies”: {
“ember”: “2.3.0”,
“ember-cli-shims”: “0.1.0”,
“ember-cli-test-loader”: “0.2.2”,
“ember-load-initializers”: “0.1.7”,
“ember-qunit-notifications”: “0.1.0”,
“jquery”: “2.1.4”,
“loader.js”: “^3.5.0”,
“qunit”: “~1.20.0”
},
“resolutions”: {
“ember”: “2.2.0”
}
}
make sure to rerun bower install
2. Configure ember-cli-build.js
We’ll have to make sure that our jQuery is excluded when we are building our application for production, but is still included for easy development.
And, include the config in the builds, because Ember defaults by adding config to a meta tag in the head of your html, which we can’t do.
This is how my ember-cli-build.js looks like
var EmberApp = require(‘ember-cli/lib/broccoli/ember-app’);
module.exports = function(defaults) {
var app = new EmberApp(defaults, {
// don't store config in meta
storeConfigInMeta: false,
// exlude jquery from production builds
vendorFiles: {
‘jquery.js’: {
development: ‘bower_components/jquery/dist/jquery.js’,
production: false
}
}
});
return app.toTree();
};
3. Configure environment.js
Next we’ll configure our environment, there are a few things we need to do.
- Stop router from changing URLs
- Define a root element in production builds
Stopping the router from changing URLs is possible by setting the locationType to ‘none’
And a root element can be defined in ENV.APP.rootElement, there you define a jquery selector string.
This is what my environment.js looks like after the changes.
module.exports = function(environment) {
var ENV = {
modulePrefix: ‘drupal-component’,
environment: environment,
baseURL: ‘/’,
locationType: ‘none’,
EmberENV: {
FEATURES: {
}
},
APP: {
// Here you can pass flags/options to your application instance
// when it is created
}
};
if (environment === ‘development’) {
}
if (environment === ‘test’) {
// Testem prefers this…
ENV.baseURL = ‘/’;
ENV.locationType = ‘none’;
// keep test console output quieter
ENV.APP.LOG_ACTIVE_GENERATION = false;
ENV.APP.LOG_VIEW_LOOKUPS = false;
ENV.APP.rootElement = ‘#ember-testing’;
}
if (environment === ‘production’) {
ENV.APP.rootElement = ‘#block-embercomponent’
}
return ENV;
};
4. Building a production version of the App
Now we want to make a production version of our app.
$ ember build — environment=production
version: 2.2.0-beta.6
Built project successfully. Stored in “dist/”.
Inside the dist directory you’ll find these contents
- assets/
- index.html
- crossdomain.xml
- robots.txt
the contents of assets is where the important files are, inside that folder
you’ll find
- drupal-component-{random hash}.js
- vendor-{random hash}.js
All other content can be important to you, but for the sake of this article, it isn’t for us.
we’ll copy both the drupal-coponent.js and vendor.js to our theme directory inside our drupal installation,
For the sake of easily identifiying everything in my drupal site, we’ll do some renames:
- vendor.js to ember.js
- drupal-component.js to ember-component.js
Drupal Configuration
1. Configure Libraries
Because we want to only load the ember application on the pages where the block is displayed, we’ll have to define our files in a library.
In our theme directory, let’s create or edit the mydrupaltheme.libraries.yml file, and add this content
ember:
version: 2.3.x
js:
js/ember.js: { minified: true }
dependencies:
— core/jquery
ember-component:
version: 1.x
js:
js/ember-component.js: { minified: true }
dependencies:
— mydrupaltheme/ember
Make sure to include the dependencies, remember we excluded jquery from the ember app because we are using the one from drupal core.
2. Create a block.
First we’ll create a Drupal block, and call it Ember Component, this is important, because drupal will generate an id for the block, and it will be #block-embercomponent (based on the name of the block), which we defined in our Ember application,
And we’ll need to create a template file based on this name as well.
3. Create a template file.
inside our template directory we’ll create a new template file for the block we just created.
The name is important, ours is: block--embercomponent.html.twig
The content of the template file is a copy of the regular block.html.twig,
with the libraries attached.
This way our ember app is only loaded on the pages where the block is displayed.
{{ attach_library(‘mydrupaltheme/ember-component’) }}
<div{{ attributes }}>
{{ title_prefix }}
{% if label %}
<h2{{ title_attributes }}>{{ label }}</h2>
{% endif %}
{{ title_suffix }}
{% block content %}
{{ content }}
{% endblock %}
</div>