Introducing ember-prismic-dom
Seamless integration of Prismic with Ember.js
We are happy to announce ember-prismic-dom
, a new open source package that provides developers with easy Prismic rendering in Ember.js.
<Prismic::Dom @nodes={{@prismicData}} />
Prismic is a headless content management system used in numerous features and across multiple platforms at Qonto. It allows us to easily separate content creation from our application development workflow. For instance Prismic is used to manage frequently asked questions or FAQ’s, for mobile and web apps. It allows Product Managers to update FAQs without involving any developers. Thanks to Prismic they can be autonomous. A good example of how Prismic can be used is our web app which is written in Ember.js.
In this article we’ll look at simple usage of ember-prismic-dom
, how it can replace prismic-dom
, how ember-prismic-dom
can be used to write custom elements using Ember.js template based rendering and how to leverage existing addons when writing custom elements.
Basic Usage
The initial pipeline to render the FAQ used Prismics library prismic-dom
.
The example below shows how FAQ data retrieved from prismic.io would be rendered using prismic-dom
.
my-component.js:
import Component from '@glimmer/component';
import PrismicDOM from 'prismic-dom';export default class MyComponent extends Component {
get html() {
return PrismicDOM.RichText.asHtml(this.args.myFaq);
}
}
my-component.hbs:
{{{this.html}}}
We wrote ember-prismic-dom
to replace prismic-dom
in our application. Using ember-prismic-dom
, we can rewrite the previous example.
<Prismic::Dom @nodes={{@myFaq}} />
Motivation
We wanted to easily integrate Ember.js components and addons when rendering Prismic data. We also wanted to make auditing our code simpler.
Simpler code auditing
Ember.js is a template centric JavaScript framework which uses Handlebars.js as its default templating language. Handlebars.js escapes values returned by a ‘double-stash’ {{expression}}
. To render an unescaped HTML string, in this instance the output of prismic-dom
the 'triple-stash' is used {{{this.html}}}
. Internally, prismic-dom
will attempt to escape potentially dangerous input so that {{{this.html}}}
is safe to use.
If we use prismic-dom
we double the mechanisms in our app being used to escape possibly harmful content which could potentially lead to cross-site scripting vulnerabilities, XSS. Instead of relying on a single method, Handlebar.js, to correctly escape content, we are relying on Hanldebars.js and prismic-dom
correctly escaping content which increases the risk of XSS.
Take this example
my-component.js:
export default class MyComponent extends Component {
get html () {
return `<img src="${element.url}">`;
}
}
my-component.hbs:
{{{this.html}}}
The {{{this.html}}}
is unescaped. We are placing trust in element.url
. If that comes from a third party, we are trusting their systems are secure, all content correctly escaped, and anybody with access to updating the image URL is trusted. If element.url='cats.png" onload=alert(document.cookie);"'
when the image is loaded, an alert with the user’s cookie visible will pop up. Instead of alerting the user, the onload could send the cookie to the attacker, giving them access to the user’s account.
We have a high confidence that Ember.js protects us from XSS and want to rely on a single escape mechanism when rendering HTML. By writing ember-prismic-dom
and removing the need for the 'triple-stash', we reduce the amount of code to audit, we only have to trust Ember.js to protect us against XSS.
Easily integrate custom components
The Ember.js template approach doesn’t integrate with prismic-dom
. We cannot use custom components when rendering custom prismic elements with prismic-dom
.
prismic-dom
provides a mechanism to override element rendering for specific tags using a HTML Serializer function. For example custom element rendering of image and list tags:
my-component.js:
import Component from '@glimmer/component';
import PrismicDOM from 'prismic-dom';export default class MyComponent extends Component {
get html () {
return PrismicDOM.RichText.asHtml(this.args.myFaq, this.args.linkResolver, this.htmlSerializer);
} get htmlSerializer (type, element, content, children) {
switch(type) {
case Elements.list: return `<ul>${children.join('')}</ul>`;
case Elements.image: return `<img src="${element.url}">`;
default: return null;
}
}
}
my-component.hbs:
{{{this.html}}}
Replacing this with ember-prismic-dom
is straightforward and allows for Ember.js template based HTML rendering.
<Prismic::Dom @nodes={{@nodes}} @image='image' @list='list'>
image.hbs:
<img src={{@node.element.url}}/>
list.hbs:
<ul>{{yield}}</ul>
More importantly it lets you leverage the existing ember-addon ecosystem. For example you want to use ember-async-image
image.hbs:
<AsyncImage src={{@node.element.url}}/>
Conclusion
In this article, we looked at rendering Prismic data using ember-prismic-dom
and how it can be used to render custom elements and integrate with ember-addons. We also examined how it helps make code easier to audit. ember-prismic-dom
allows us to write idiomatic Ember.js which results in a better developer experience. It makes merge requests to our codebase easier to review and our codebase more readable.
At Qonto we love using Prismic. It enables us to seperate content creation and management from software development. Creating ember-prismic-dom
helps us secure, implement, review and ship features built on top of it. If you’re writing an app in Ember.js and are using Prismic I encourage you to try ember-prismic-dom
.
About Qonto
Qonto is a neobank for SMEs and freelancers founded in 2016 by Steve Anavi and Alexandre Prot. Since the launch in July 2017, Qonto has made business banking easy for more than 150,000 companies. Thanks to Qonto, business owners save time (streamlined account opening before a day-to-day user experience with unlimited history, accounting exports, expense management feature), have more control while giving their teams autonomy (real-time notifications, user right management system) and have improved visibility on cash-flows (smart dashboards, transactions auto-tagging, and cash-flow monitoring). They also enjoy stellar customer support, at a fair and transparent price.
Interested in joining a challenging and game changer company? Consult our job offers!