Your submission was sent successfully! Close

Thank you for signing up for our newsletter!
In these regular emails you will find the latest updates from Canonical and upcoming events where you can meet our team.Close

Thank you for contacting our team. We will be in touch shortly.Close

  1. Blog
  2. Article

Kit Randel
on 9 August 2018

I recently attended Fullstack 2018, “The Conference on JavaScript, Node & Internet of Things” with my colleagues from the Canonical Web Team in London. Fullstack attempts to cover the full spectrum of the JS ecosystem – frontend, backend, IoT, machine learning and a number of other topics. While I attended a broad range of talks, I’ll just mention those that I think are most pertinent to the work we are doing currently in the web team.

A Thunk, a Saga and an Epic walk into a bar

This talk by Artur Daschevici focused on three different approaches to managing side effects in Redux, in order of relative complexity: thunks, sagas and epics.


Some terminology first – a thunk, sometimes called a nullary function in functional programming, is essentially a pattern for lazy evaluation. The term thunk originates from languages like Haskell and Scheme, although confusingly a thunk is sometimes called a promise in Scheme!

In JS a thunk basically looks something like this:

function outerFn() {
  return function() {

That’s all well and good, but why do we need them? In redux, reducer functions are supposed to remain pure, which means no mutation of state, and no side effects. The arguments for this are described in the redux documentation, but basically impure reducers break time travel and replay, one of the advantages of using Redux in the first place.

Without thunks, that leaves you in a weird place, you can never actually do anything, you can’t perform I/O, you can’t call an API. Thunks allow you to perform some impure action, and then dispatch an action e.g.

// a thunkified action creator
function getBurlyWombats() {
  return (dispatch, getState) => {
    return axios.get(‘/wombats?type=burly’).then(() => {
      // since redux passes dispatch as the first arg to thunks
      // we can then conveniently dispatch the action once this
      // promise resolves and we have *lots* of burly wombats.


Redux-saga is an alternative to the redux-thunk middleware, which attempts to reduce some of the complexity of chaining asynchronous actions which can devolve into callback hell with redux-thunk. Redux-saga employs generators to allow you to write async actions in a more synchronous style. Another advantage of this approach is that the async “thread of execution”, can effectively be paused or cancelled using a normal redux action, which could provide some nice UX opportunities for long running tasks. Redux-saga also makes error handling quite a bit cleaner.

function* getBurlyWombats() {
  try {
    const burlyWombats = yield call(api.getBurlyWombats);
    yield put({type: “GET_BURLY_WOMBATS_SUCCEEDED”, wombats: burlyWombats});
  } catch (e) {
    yield put({type: “GET_BURLY_WOMBATS_FAILED”, message: e.message});

Redux-observable & epics

Redux-observable, developed by Netflix, is built on RxJS, and introduces an entirely new programming model (reactive programming), which the speaker suggested was potentially overkill for anything other than the most complex use-cases. Redux-observable provides many powerful tools for managing asynchronous streams, but the speaker seemed to feel that this translated to many additional ways to shoot yourself in the foot.

Ultimately, the speaker seemed to think that redux-saga offers the best balance of power, without introducing significant complexity. Worth also noting that redux-logic seems to be gaining some traction (also based on RxJS but suggests that it offers a simpler abstraction) but was not mentioned in this talk.


Surprisingly pain-free end-to-end testing with Jest and Puppeteer

Matt Zeunert spoke about using Puppeteer and Jest for integration tests. Puppeteer is a node library, officially maintained by the Chrome team, for managing chrome (headless by default) and has a number of features:

  • Generates screenshots and PDFs of pages.
  • Crawl a SPA and generate pre-rendered content (i.e. “SSR”).
  • Automate form submission, UI testing, keyboard input, etc.
  • Create an up-to-date, automated testing environment. Run your tests directly in the latest version of Chrome using the latest JavaScript and browser features.
  • Capture a timeline trace of your site to help diagnose performance issues.

Using Puppeteer with Jest is relatively straightforward to setup and is well documented.

An example puppeteer tests looks something like:

test('can logout', async () => {
  await page.waitForSelector('[data-testid="userMenuOpen"]')
  await page.waitForSelector('[data-testid="userLoginForm"]')

Matt seemed to think that Puppeteer tests tended to be more reliable than Selenium/Webdriver tests, which as we all know are prone to flakiness.

Perhaps the only disadvantage of using Puppeteer exclusively, is the lack of cross browser support, which service like BrowserStack can help address.


Micro Frontends – a microservice approach to the modern web

Ivan Jovanovic explored the notion of applying the architectural pattern of microservices to frontend development, decomposing frontend code along boundaries (pages, sections), even going as far as to advocate for mixing and composing different frameworks. Ivan suggested that this approach would primarily suit clients maintained by large teams, but that it could also be applied to a project transitioning to a new framework.

External app bootstrapping

The first case covered was that of an external, independently deployed app. The speaker suggested that the simplest means of integration in this case was communication via the global window object, followed by a slightly more sophisticated approach using an event bus library called eev, a ‘micro-library’ (< 500 bytes minified) with no dependencies.

Using eev is as simple as:

  window.e = new Eev();

  // Add a handler
  window.e.on('wrangle-wombats', (num) => {
  alert(`Wrangled ${num} wombats.`);
  // Emit an event
window.e.emit('wrangle-wombats', 10);


The primary tool for achieving this goal is single-spa, which describes itself as a JavaScript Metaframework. It suggests you can:

single-spa isn’t opinionated about how applications communicate – apps can communicate and share state via the window object, an event bus like eev, or a global state store like redux.

Creating a single-spa app looks something like:

  import * as singleSpa from 'single-spa';

const appName = 'app1';
const loadingFunction = () => import('./app1/app1.js');

// routing to determine which app is loaded
const activityFunction = location => location.pathname.startsWith('/app1');

singleSpa.registerApplication(appName, loadingFunction, activityFunction);


Lightning Talk: Introduction to ReasonML

Jack Lewin gave a fascinating lightning talk about ReasonML, a new programming language developed at Facebook by the team that created React. ReasonML is an OCaml variant (strongly typed functional language, but with excellent type inference such that it feels like a dynamic language), and has native JavaScript interop. This means that you can drop raw JS into ReasonML modules, and use libraries from npm. Facebook has recently rewritten over 50% of Messenger in ReasonML, and the language appears to be gaining traction at a number of other companies.

Compared to TypeScript, ReasonML offers immutable types by default (TypeScript needs to be used in conjunction with immutable.js), runtime validation (you get json-schema for free without a library essentially), pattern matching (a powerful technique which obviates the need for complex type checking you would need in TypeScript), and an elegant module system.

An example of Reason’s elegantly minimalistic module system:

  /* This typically compiles to module FileA below */
  let a = 1;
  let b = 2;

  /* */
  /* Maps FileA's implementation to a new API */
  let alpha = FileA.a;
  let beta = FileA.b;

ReasonML & React

If one was pursuing type safety in React, there’s a strong argument for ReasonML as an alternative to TypeScript, as the author of React itself is maintaining the react bindings.

Reason-react has the additional benefit of providing support for redux like stateful components and reducers natively.


Related posts

26 February 2024

Crafting new Linux schedulers with sched-ext, Rust and Ubuntu

Ubuntu Article

In our ongoing exploration of Rust and Ubuntu, we delve into an experimental kernel project that leverages these technologies to create new schedulers for Linux. Playing around with CPU scheduling policies has always been a dream for many kernel hackers and OS enthusiasts. However, such material typically remains within the domain of a fe ...

Igor Ljubuncic
24 January 2024

Canonical’s recipe for High Performance Computing


In essence, High Performance Computing (HPC) is quite simple. Speed and scale. In practice, the concept is quite complex and hard to achieve. It is not dissimilar to what happens when you go from a regular car to a supercar or a hypercar – the challenges and problems you encounter at 100 km/h are vastly ...

Anthony Dillon
25 October 2023

Web team – hack week 2023

Design Article

Today, around 96% of software projects utilize open source in some way. The web team here at Canonical is passionate about Open source. We lead with an open-by-default approach and so almost everything we do and work on can be found publicly on the Canonical Github org. It is not enough to simply open our ...