Preact + Typescript + Parcel + Redux Zero: Rebuilding the QMENTA Front-End focusing on Performance and Minimalism.
Tags: preact, typescript, parcel, redux
Published: 2018-09-17 12:17:01

---
title: Preact + Typescript + Parcel + Redux Zero: Rebuilding the QMENTA Front-End focusing on Performance and Minimalism.
published: true
description: This article provides a comprehensive overview of the different parts that compound the new platform, such as how decorators are extensively used or the choice of technology stack, and how we focus on simplicity and performance.
tags: preact, typescript, parcel, redux
---

*At* [**QMENTA**](https://www.qmenta.com/) *we have been rebuilding the front-end from scratch, seeking simplicity and performance not only in design, but also in the technology stack used for it . This article provides a comprehensive overview of the different parts that compound the new platform, such as how decorators are extensively used or the choice of technology stack.*

---

*This post was originally posted on [Medium](https://medium.com/@albert.alises/preact-typescript-parcel-redux-zero-rebuilding-the-qmenta-front-end-focusing-on-performance-a7c879c5b288)*

The [QMENTA platform](https://platform.qmenta.com) has been going on for quite some time now. The old platform front-end was built using well established technologies like *JQuery, Dojo or D3*. While being feature rich, one of the problems was the scalability and maintainability of such a big codebase and it being quite complex in terms of UX/UI. In medical imaging storing platforms, data and operations are complex enough for the user to manage, so making it more difficult in terms of user experience or visual design is a no-go zone. 🙅🏻

One of the main challenges coming into this year was to rebuild the front-end from scratch to accommodate the new necessities of a growing neuroimaging processing hub, to make it clean and in a way that can be easily maintainable, scalable and up to date with the latest technologies on front-end development.

 ![Register Page](https://thepracticaldev.s3.amazonaws.com/i/uxvbwc6nglbswqlm0tcc.png)
 <figcaption>Figure 1: Register Page for the new front-end</figcaption>
 ![Project List View](https://thepracticaldev.s3.amazonaws.com/i/eea9ae1ys3uuheewy3u8.png)
 <figcaption>Figure 2: Project List view for all our projects on the new front-end</figcaption>

Having speed, performance and minimalism as a flagship, the aim was to build a single page web application using the `FrameworkOfChoice`, which can be **VueJS, AngularJS, React**, or other frameworks such as [*Hyperapp*](https://github.com/jorgebucaran/hyperapp). {% github jorgebucaran/hyperapp %}
Up until there, pretty standard and mainstream definition for a web application project. After pondering the different frameworks and technologies, we chose [*Preact*](https://preactjs.com/) coupled with [*Typescript*](https://www.typescriptlang.org/) as the core libraries of choice for the project.

 ![Typescript and Preact logos](https://thepracticaldev.s3.amazonaws.com/i/3qs6lbnj1c4rvafb885c.jpg)
 <figcaption>Figure 3: Preact and Typescript logos.</figcaption>

---

###But… why Preact + Typescript? 🤔

Preact, according to [its official documentation](https://preactjs.com/), is a *“fast 3kB alternative to React with the same modern API”*. It offers everything we like and love about React such as the [Virtual DOM](https://reactjs.org/docs/faq-internals.html), [Component-Based](https://reactjs.org/docs/react-component.html) development, lifecycle hooks and [jsx syntax](https://reactjs.org/docs/introducing-jsx.html) for generating dynamically, data-driven interfaces.

Preact does all this while keeping the API leaner ([React 16.2.0 + React DOM is 31.8Kb while Preact is only 4Kb, both gzipped](https://gist.github.com/Restuta/cda69e50a853aa64912d)), making it faster, more lightweight, and reducing a lot of the noise added by React. The principal differences with React can be seen [here](https://preactjs.com/guide/differences-to-react). Some of them are:

- `this.props` and `this.state` are passed to `render()` for you. 

- You can just use class for CSS classes. 

- Getting rid of a lot of React / React DOM specific functions like `React.CreateElement` or `ReactDOM.render` , being separate exports thus avoiding the aliasing, making your code cleaner and more readable.


Regarding performance, testing it on a simple [TODO application](http://todomvc.com/), the results are astounding, with Preact being among the fastest of them approached by Vue.js and circa 170ms faster than React. Amazing, isn’t it? 🌠

 ![Performance Test](https://thepracticaldev.s3.amazonaws.com/i/5qa8ppv6r9ptxu4yb773.png)
 <figcaption>Figure 4: TodoMVC Performance comparison between different frameworks. Seen at: [https://developit.github.io/preact-perf/](https://developit.github.io/preact-perf/)
</figcaption>


> You can perform the performance test on your device by going [here](https://developit.github.io/preact-perf/).

Not everything is great of course, one can find that the community is not as big or responsive as the React one (it is not that widely used after all). Some sweet functionalities are still not there, such as support for [fragments](https://reactjs.org/docs/fragments.html) (So you still have to create some good old div wrappers). Furthermore, some libraries are still not supported, but worry not, [preact-compat](https://github.com/developit/preact-compat) creates a layer on top of Preact to make it fully compatible with React. Magic!⚡️

{% github developit/preact-compat %}

 ![Analysis List View](https://thepracticaldev.s3.amazonaws.com/i/i90qhd5lbcu5mfpjkonp.png)
 <figcaption>Figure 5: Analysis List View</figcaption>

We ❤️ **Typescript**. A lot. For an application that is rich in data and manages a lot of different metadata and results from APIs, Typescript offers us static type checking that comes very handy when defining the different data structures that our application handles, as well as the structure of the props and state of the different components, so we know what to expect, have it documented and have all the data to be consistent at all different stages.

> *You can create interfaces with Typescript that characterize the input/output data your application manages. In our case, it helps modeling the data necessary to characterize a subject, or an analysis so everything is consistant and we know what to expect when dealing with those structures.*

```ts
export interface AnalysisInput {
  container_id: number,
  date: { $date: number },
  in_out: string,
  filters?: any[][],
  passed: boolean,
  ssid: string,
  subject_name: string
}

export interface AnalysisSettings {
  acpc_alignment: string,
  age_months: number,
  alignment_tool: string,
  input: AnalysisInput
}
```

With Typescript, you can also create *Custom Components* like the one below. This enforces the classes extending ComponentForm to implement methods for handling the form change and also setting the form model (i.e the object with all the fields required for the form such as the user, password, etc…), this model is then required as the state of the component, also a method `submitForm()` has to be implemented. With that, we have a skeleton or structure that all forms follow with a generic form component that can have any given number of fields.

```ts
import { h, Component } from "preact";

interface FormManagement<M> {
  form: M,
  message: string
}

export abstract class ComponentForm<props, model> extends Component<props, FormManagement<model>> {

  protected setFormModel (model: any) {
    this.setState({ form: new model })
  }

  protected handleFormChange(change) {
    this.setState(({ form, ...state }) => ({
      form: { ...form, ...change },
      ...state
    }));
  }

  abstract submitForm(...args): void;
}
```

An example of a simplified generic Preact Component our application uses that enforce Typescript. We can see the different lifecycle hooks and how the props and state of the component are set as Typescript interfaces.

```jsx
mport { h, Component } from "preact";

export interface CommonSelectorAttrs {
  options: any[];
  class?: string;
  value?: any;
  printBy?: string;
  onChange?: (any) => void;
}

export interface CommonSelectorState {
  visible: boolean;
  innerValue: string;
}

export default class CommonSelector extends Component<CommonSelectorAttrs, CommonSelectorState> {

  state = { 
    visible: false, 
    innerValue: ""
  };
  
  getValue = (entry) => String(this.props.printBy ? entry[this.props.printBy] : entry);

  componentDidMount(): void {
    this.props.value && this.setState(() => ({ innerValue: this.getValue(this.props.value) }));
  }

  selectOption(opt: any): void {
    this.props.onChange.call(null, { target: { value: opt }});
  }
  
  closeTooltip(): void {
    this.setState(() => ({ visible: false }));
    this.checkMatch();
  }
    
  getMatcher(opt: any): boolean {
    return this.getValue(opt) === this.state.innerValue;
  }

  checkMatch(): void {
    const match = this.props.options.find((opt) => this.getMatcher(opt));
    !!match ? this.selectOption(match) : this.setState(() => ({ innerValue: "" }));
  }
  
  explicitSelection(opt: any): void {
    const val = this.getValue(opt);
    this.setState(() => ({ innerValue: val }));
    this.closeTooltip();
  }

  setValue(){
    if(this.state.innerValue === 'undefined'){
      return "";
    }else{
      return this.state.innerValue;
    }
  }

  render() {
    return (
      <div>
        <div>
          <p>
            <input placeholder="Select one option" />
          </p>
        </div>
        <div>
          {this.props.options
            .map((opt) => (
              <div onClick={() => this.explicitSelection(opt)}>
                <span>{this.getValue(opt)}</span>
              </div>
          ))}
        </div>
      </div>
    )
  }
}
```

---


###Decorators, Decorators… 💎
Ah, [Javascript decorators](https://www.sitepoint.com/javascript-decorators-what-they-are/). As a concept, they simply act as wrappers to another function, extending its functionality, like [**higher-order functions**](https://reactjs.org/docs/higher-order-components.html). We extensively use decorators to keep our code cleaner and separate the back-end, state or application management concerns and provide a more structured way to define common functions across components like connecting to the Redux store, connecting to the API or defining some asynchronous behavior to happen before or after the responses are sent (sort of like method proxies), so we do not have to repeat code and provide an elegant, minimal way to define these behaviors. We use them for:

#####- Asynchronous Method Interceptors

For managing asynchronous behavior we use [`kaop-TS`](https://github.com/k1r0s/kaop-ts) , which is a decorator library that provides some method interceptors written in Typescript. With them, we can plug in behavior at a join point on the asynchronous method, like perform some operations before the method starts, or after the method has finished, or plugging in a method that intercepts an error and performs some logic. We can see the `beforeMethod` decorator being used in the snippet below where we define the http decorator.

{% github k1r0s/kaop-ts %}


#####- Connecting with and Managing API calls

For managing the calls to the QMENTA API, we implemented a `@platformRequest(url,method)` decorator that you can wrap in any function of with signature `function(params,error?,result?)` and convert it into an asyncronous call to the API with certain parameters to send in the request and receive the result JSON object from the call or the error thrown by the request. The implementation of the decorator can be seen below as well as an example method calling it.

```ts
const http = options => meta => {
  if(!options.method) options.method = "get";
  const [ params, ...aditional ] = meta.args;
  options[options.method === 'get' ? 'params' : 'data'] = params;
  (request as any)({ ...options })
  .then(res => {
    const data = res.data;
    meta.args = [params, ...aditional, null, res.data];
    meta.commit();
  })
  .catch(err => {
    meta.args = [params, ...aditional, err, null];
    meta.commit();
  })
};

const checkError = meta => {
  const [err, result] = meta.args.slice(-2);
  checkInvalidCredentials(err);
  if(err) return;
  if(typeof result !== "object") {
    meta.args.splice(-2);
    meta.args = [ ...meta.args, new Error("Wrong response format! (not a json obj)"), null ];
  }
}

const stringifyParams = meta => {
  const [ params, ...args ] = meta.args;
  meta.args = [ stringify(params), ...args ];
}

export const platformRequest = (url, method = "get", noop = _ => _) => beforeMethod(
  method === "get" ? noop : stringifyParams,
  http({ method, url }),
  checkError)

/* USAGE EXAMPLE */
interface ChangePasswordRequest {
  old_password: string,
  new_password: string,
  new_password_confirm: string
}

@platformRequest("/change_password", "post")
  RecoverPassword(params : ChangePasswordRequest, err?, result?) {
    if(err) {
      throw err;
      //Cannot change the password
    } else {
      //Password changed succesfully!
    }
 }
```

> *The decorator uses [axios](https://github.com/axios/axios) under the hood to perform the request* 🕵. 

An implementation of it (as a minimal library) wrapping the [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) can be seen on the [`http-fetch-decorator`](https://github.com/aalises/http-fetch-decorator) repo:

{% github aalises/http-fetch-decorator %}

Also, the state management and routing of our application use decorators to extend functionality to the components to, for example, connect it to the store or listen to be rendered at a specific route. On the next section we will talk a little bit more about it.

 ![Subject Detail Viewing](https://thepracticaldev.s3.amazonaws.com/i/fnzcy8oszdysa8lznuki.png)
 <figcaption>Figure 6: Specific Subject files viewing with the edit file metadata modal.
</figcaption>


---

###State Management and Routing 🚀

**State management** is one of the main concerns of any growing React application. When the number of entities and components keep growing, the need for global state management arises. [Redux](https://redux.js.org/) is one of the mainstream solutions that aims to solve that. This post assumes some previous knowledge of how Redux operates; if not, [here you can find a guide on how it works](https://medium.freecodecamp.org/understanding-redux-the-worlds-easiest-guide-to-beginning-redux-c695f45546f6) .

In our application, we did not want to have a big store and we tried to keep it as small as possible, reducing the use of the shared state, enforcing encapsulation and separation of concerns. Given so, we decided to use a lightweight (less than 1Kb) version called [`Redux-Zero`](https://github.com/redux-zero/redux-zero). While having some differences, it also reduces a lot of the unnecessary overhead (for the purpose of our application) that Redux has. It still has a **store** (albeit just one), which provides all the global state that we want to manage; in our case, session and project information, current pages, notifications of the current project id, among others. It also has **no reducers**, which ironically does reduce the complexity of the library quite a lot.

{% github redux-zero/redux-zero %}

 ![Brain Fibers Visualizer](https://thepracticaldev.s3.amazonaws.com/i/bpxtpl673dhwlbaocglj.png)
 <figcaption>Figure 7: Brain Tractography Fiber visualization on the front-end using WebGL
</figcaption>

To get it up and working, just wrap your root component with the `<Provider store={store}/>` component and set the store on it, an object created by the `createStore(state)` method, where the state is the object that contains our shared state. To change that state, you create actions which are just pure functions that update this global state , e.g `setSession = (state,val) => ({sessions: val});`

To call those actions from a component, we have to **connect** that component to the store. Connecting a given component to the store allows the component to gain access to some actions and the global state via props. We created a decorator to simplify the process of connecting a component to the store.

```jsx
import { h, Component } from "preact";
import { Connect } from "redux-zero/preact";

export default function(actions = {}): any {
  return Child => props => (
    <Connect mapToProps={state => ({ ...state })} actions={actions}>
      {mappedProps => <Child {...mappedProps} {...props} />}
    </Connect>
  )
}
```
With this decorator, we can plug it in on top of any component specifying the actions the component will get as props. e.g by putting `@connectStore({removeSession, setCurrentPages});` right on top of the declaration of the component, you have access to these actions inside the component which update the global state on the store, while also having access to the global state itself via props ( `this.props.removeSession();` ). With this method, we provide a cleaner, more elegant and compact way to connect a component to the store.

Another integral part of any modern application is the option to route between the different views of the project depending on the URL or other parameters, being able to pass parameters to the routes, etc. A common solution is to use [the amazing router that comes with React](https://github.com/ReactTraining/react-router) . As much as we like it, it comes with a lot of functionality that we would not really be using, so we made our own [preact-routlet](https://github.com/k1r0s/preact-routlet) , a simple router for Preact/React based in decorators.

{% github k1r0s/preact-routlet %}

The intricacies of it are simple, just wrap your application with the router component `<RouterOutlet />` and you are ready to go. You can also wrap some components with `<PathLookup shouldRender={condition}/>` specifying a condition to render some path, or use the `<RouterOutlet redirect="/route" shouldRedirect={condition} />` to specify a condition which, in case it is met, the router automatically redirects to the specified route (for example, we use it to redirect to the login if the session is invalid or has expired).

To navigate to a route you just have to call `navigate("/route")` and to specify a Component to be rendered at a specific route, you just have to plug the decorator on top of the component e.g `@renderOnRoute("forgot-password")` making it clear and visual in which route the component is rendered.

With that, we have a compact way of representing routing and state management with the signatures on top of the component that makes it very readable. A dummy component that connects to the store and is rendered on a given route can be seen below.

```jsx
import { h, Component } from "preact";
import { renderOnRoute, navigate } from "preact-routlet";
import { setLoginMessage } from "../actions";
import connectStore from "../../../connect";
import { platformRequest } from "../../../services/api-decorators";

//With these decorators, we know the route this component is rendered at and which actions does it have access to, in a compact way
@renderOnRoute("/forgot-password") @connectStore({ setLoginMessage })
export default class ForgotPassword extends Component<any, any> {

  //Call the forgot_password API with a POST
  @platformRequest("/forgot_password", "post")
  performLogin(params, err?, result?) { //Params are the parameters of the request e.g {email: "test@gmail.com , user_id: 1234}
    if(err || result.error) {
      this.setState({ message: "There was an error with the request" })
    } else {
      this.props.setLoginMessage(result.message); //Calling the store to set a login warning message
      navigate("/login"); //Navigate back to the login using the router
    }
  }
  
   render() {
     return (
        <div>
          Just an example component with some decorators...
        </div>
   }
}

```

---


###Bundling with Parcel 📦

[Parcel](https://parceljs.org/), not to be confused with the australian band [Parcels](https://www.youtube.com/watch?v=PTFK96KNfIE), defines itself as a *“blazing fast, zero configuration web application bundler”*. At the start of the project, we used the fairly standard Webpack for bundling our application. It required quite a lot of plugins and configuration. (`webpack.config.ts`). Switching to Parcel, we don’t need configuration for typescript or html files anymore, just adding `npm install --save-dev parcel-bundler parcel-plugin-typescript` does the trick.

The only remaining thing is to specify an entry point and output directory and voilà, it just works. The difference in speed and performance compared to webpack is not very acute in our case (it’s essentially the same in terms of speed), but it’s the zero configuration and minimality of Parcel what makes it our bundler of choice for the project.

{% github parcel-bundler/parcel %}

 ![Parcel Performance](https://thepracticaldev.s3.amazonaws.com/i/8ujt08n3fk4kzwnlffbw.png)
 <figcaption>Figure 8: Screenshot of the build of the whole application. Parcel’s magic💥</figcaption>

The only downside is that, in order to get the [hot reloading](https://parceljs.org/hmr.html) working for the dev server in Preact + Typescript, you have to add the `module.hot.accept()` flag to your root component and specify some types in the render function (the third argument as `foo.lastChild as Element` for Typescript not to complain. The fix can be seen on the following snippet.

```js
import { h, render } from "preact";
import Main from "./components/main"

declare const module: any

const mountNode = document.getElementById('root');

render(<Main />, mountNode, mountNode.lastChild as Element);

// Hot Module Replacement
if (module.hot) {
    module.hot.accept();
}

```

---


###Unit and e2e acceptance testing with Jest + Puppeteer

Testing is an integral part of any project. In our project, we use the fairly standard [Jest](https://jestjs.io/) for [testing our components](https://jestjs.io/docs/en/tutorial-react) coupled with [Puppeteer](https://github.com/GoogleChrome/puppeteer) , wich is a web scraper, or having your own highly trained monkey perform the operations you tell him/her on the browser, like clicking a certain button or dragging the mouse over an element. Using those, we can perform some operations on the front-end via a headless Chrome API and then check for expected results with Jest, like checking an element of confirmation appears or the warning message displayed is correct👌. If you want to learn more on how to use Jest + Puppeteer for testing in React, [there is a nice article talking about it](https://blog.bitsrc.io/testing-your-react-app-with-puppeteer-and-jest-c72b3dfcde59).

{% github GoogleChrome/puppeteer %}

> Just an example of testing the pagination component using Jest.

```js
import { h, render } from 'preact';
import Pagination, {generateMidPageTabValues} from '../../src/components/pagination-component';

const spy = jest.fn()

describe("<Pagination /> e2e tests", () => {

  let scratch = null;
  let component = null;

  beforeEach(done => {
    scratch = document.createElement('div');
    render(<Pagination initialPage={1} ref={ref => component = ref} pageChange={(from, to) => spy(from, to)} totalItems={45}/>, scratch);
    done()
  });

  it("should display proper information about pages", () => {
    expect(scratch.innerHTML).toContain("Showing items 1 to 15 of 45");
  });
  it("shouldn't allow to decrease current page if we're on the first page", () => {
    expect(component.state.prevAllowed).toBe(false);
  });
  it("should properly increase current page", (done) => {
    component.pageForward();
    setTimeout(_ => {
      expect(scratch.innerHTML).toContain("Showing items 16 to 30 of 45");
      expect(spy).toHaveBeenLastCalledWith(15, 30);
      done();
    }, 1000);
  });
  it("Should correctly compute first page indices", () => {
    expect(generateMidPageTabValues(1,5,10)).toEqual([2,3,4,5,6]);
    expect(generateMidPageTabValues(4,5,10)).toEqual([2,3,4,5,6]);
  });
  it("Should correctly compute last page indices", () => {
    expect(generateMidPageTabValues(13,5,15)).toEqual([10,11,12,13,14]);
    expect(generateMidPageTabValues(11,5,15)).toEqual([10,11,12,13,14]);
  });
  it("Should correctly compute middle pages indices", () => {
    expect(generateMidPageTabValues(10,5,15)).toEqual([8,9,10,11,12]);
    expect(generateMidPageTabValues(7,5,15)).toEqual([5,6,7,8,9]);
  });
  it("Should correctly compute indices when few pages", () => {
    expect(generateMidPageTabValues(1,5,5)).toEqual([2,3,4]);
    expect(generateMidPageTabValues(2,5,3)).toEqual([2]);
    expect(generateMidPageTabValues(2,5,2)).toEqual([]);
    expect(generateMidPageTabValues(1,5,1)).toEqual([]);
  });
});
```

The building, testing and deploying process is automated using [Jenkins](https://jenkins.io/) , with the tests running in a docker container in order to perform the tests in an environment with all the graphical libraries puppeteer requires. The **fairly simple** pipeline can be seen in Figure 9:

 ![Jenkins Pipeline](https://thepracticaldev.s3.amazonaws.com/i/jx50xsbtibzd11vgw9b1.png)
 <figcaption>Figure 9: Jenkins pipeline for deploying the front-end
</figcaption>

> *We build the binaries, perform the unit tests and then deploy to a testing dominion which varies based on the git branch we are on. Then we perform the e2e tests on that dominion.*

The docker image used for the container in which Jenkins runs the pipeline is a custom version of the [Puppeteer Docker Image](https://github.com/alekzonder/docker-puppeteer) , based on the ubuntu 16.04 image with node 8. The dockerfile can be seen below:

{% gist https://gist.github.com/aalises/3c4d7a4bef8bb21c668914b4c4348e13 %}

> *We add the “deployuser” to the container because Jenkins mounts its workspace directory (owned by deployuser) and it requires the user inside the container and outside to be the same in order to perform all the operations required for the deployment to be succesful.*

This way, we avoid the whole application to suddenly crash and burn or turn into [one of those amazing 90’s websites](http://www.adamhammond.com/90s/radiohead/).

---


###Summary

In this article we have presented an overview of the technology stack we used for rebuilding the QMENTA front-end and how it focuses on being small, efficient and simple. We have also seen how we use decorators in our project and the different parts that compound it such as API calls, routing, state management etc.

By setting the foundations and patterns of the project, the next steps are continuously improving the new front-end in a scalable and maintainable way and adding meaningful features to match the functionality of the old platform, while keeping it minimal. [You can see how it goes here](https://preview.qmenta.com/#/login). 👋

> *Special kudos 🙌 to {% user k1r0s %} for setting the foundations of the project, carrying the heavyweight through most of it and teaching me the ways of the H̶a̶c̶k̶e̶r̶m̶a̶n̶ Javascript ninja.* 🤖 🏋🏻

Want to experiment with these technologies in your next projects? Yay! Here you have some boilerplates we created in github to get you up and running as soon as possible.🤘🏼

- [Preact + Typescript + Parcel](https://github.com/aalises/preact-typescript-parcel-starter)

{% github aalises/preact-typescript-parcel-starter %}

- [Preact + Poi](https://github.com/k1r0s/preact-poi-starter)

{% github k1r0s/preact-poi-starter %}

- [Preact + Typescript + Webpack](https://github.com/k1r0s/bleeding-preact-starter)

{% github k1r0s/bleeding-preact-starter %}