Aurelia And Ace: challenges and best practices - devuxd/SeeCodeRun GitHub Wiki

Introduction

Providing developers with new programming experiences includes sharing and building code online. These experiences come with challenges for the developers of such solutions, from choosing a framework to the best libraries to integrating them as a compiling solution. We have seen platforms for cloud-based development such the IDE Cloud9, or for code sharing like JSFiddle. Yet, the documentation for creating new web-based programming experiences is scarce.

We will explore how we can use a versatile code editor, Ace, and integrate it into a flexible and robust JavaScript client framework, Aurelia, to provide new information to developers about their code . Based on a previous blog for using Ace, I will explain how to use and extend advanced features such tooltips, code highlights, and gutter widgets. Then we will explore Aurelia, specifically its MVVC architecture and how these overlays can be integrated into an app following its guidelines.

As a result, I will show you how to associate Ace events to Aurelia's event system. Then, how to add your information as overlays to the editor within an Aurelia app. Also, I will elaborate on how to avoid common problems when putting Ace and Aurelia together.

Background

Mastering current JavaScript(JS) technologies require significant amounts of time. In the long term, learning frameworks allow developers to build robust solutions. However, the learning curve and programming lore of these solutions propose a considerable challenge to most developers, including me =].

So, to mitigate this cumbersome challenge, let's start with what JS means and how its libraries work.

Document Object Model(DOM)

We should start with the founding abstraction that constitutes a web page, the DOM. A browser uses a DOM as a mean to interact with its components and offer an interface to others, an API. Browsers such as Chrome, Firefox, and others, provide their implementations of the DOM, normally following a JavaScript/ ECMAScript ESx standard.

These different implementations are the source for browser conflicts. That is, what works on Chrome is not guaranteed to work in Firefox unless both browser versions meet the same ES standard. This is the first incompatible assumption that we make when deploying our web apps.

Once we know what "ESx" standard our target browser is compatible with, then we must check that the libraries we want to use are too. Failing to do so, will generate adverse results and take significant amounts of time to figure it out.

The most critical fact that we need to acknowledge to start working with libraries is how and when they access the DOM. When a library or any script attempts to write the DOM, two things will happen: (1) If the DOM was not in write-only mode, then it will start this mode, allowing only the script to modify it; and (2) if the DOM is write-only mode, the script attempt will be discarded. This contract must be acknowledged by us, developers; otherwise, assumptions such as these writing attempts being queued and written afterward, later on, will result in incorrect app behavior. Furthermore, these discarded writing attempts are handled silently to debuggers and unless a sophisticated analysis is involved, they require plenty of time to be found.

We will discuss how to work with Aurelia and Ace. Both artifacts interact with the DOM on their on terms, but learning how their lifecycles are will help us avoiding the aforementioned write-only issue.

Aurelia

This robust client framework offers a component-based development with a proper app manager for compilation, debugging, and deployment, Gulp.

MVVC

We need two artifacts to build our components in Aurelia, an html file fro the view, and a js file for the view model. The controller logic is provided by Aurelia. ####View Controller

export class ViewModel{
  constructor(){
    this.aValue = "Hello, world!";
   }
   attached(){
    // Do DOM manipulation here
   }
}

In the previous snippet, we have defined the class to be bound in the view, it will be resolved as "viewModel". the attached method is critical to avoid components blocking each other.

Aurelia serves as a framework that controls the lifecycle of your components. Once the application root has been set

Model View

Now, let's use the view-model in the view:

<template bindable = "aViewModel" >
<div value.bind="aViewModel.aValue"></div>
</template>

As mentioned before, Aurelia provide control to bind a view-model and the view: value.bind will assign aValue attribute from the ViewModel object to this div, any changes in the view-model will be reflected in the view.

Finally in our index.html (or the defined root of the app) we bind our view to its view-model.

<require from="./a-view.html"></require>
<a-view aViewModel.bind = "viewModel" ></a-view>

With this snippet, we bound the view-model that satisfies the ViewModel requirements and we can run the app. Many view-models can satisfy others. This allows high reuse of the components.

App Lifecycle

By default, Aurelia will resolve the index.js file in the root of the src folder. Normally, the index will load the app configuration(app.js), which will map the root component to start building the app.

Aurelia will resolve all .css files, then all .js files and finally all .html files.

By default, Gulp(the project manager used by Aurelia) is strict with the type of file is included to compile, deploy or bundle the app. A common issue is to name a file x.htm, in the configuration of gulp, only .html files are to be processed, therefore, when running the app x.htm will not be visible. Either change the configuration or use valid file types.

Component Lifecycle

The following sequence will be followed per each Aurelia component: component.css component.js constructor() activate() attached() bind() unbind() detached() component.html

This is a key feature that will let us know why Jquery-UI has problems with the default Aurelia component lifecycle.

Ace

In a previous blog, I showed how this robust code editor could be used and extended. I will focus on using Ace events and mapped them to Aurelia events. Once we understand that they are both event-driven, we will be able to keep their concerns separate and maintain cleaner code.

Aurelia and Ace

Please visit the Ace Utils wiki for details. We will discuss now the inherit problem of using them together.

#The DOM access problem: A silent race condition Every functionality that we provide to a page boils down to modifications to the document we are interacting, from layouts to style to embedded videos. These modifications must happen in a desirable sequence, otherwise, we will obtain undesirable and mostly silent failures in our pages. A race condition is when an object performs more than one operation at the time in an environment where only one can be done at a time, resulting in the operations being performed correctly or not, or even not to performed completely.

When using libraries in JavaScript, one way or another, the use of a functionality will access the DOM, ##Why so silent?! As an amateur in JS, parameters by value-copy and asynchronous call handling are somehow new. Yet, one of the most time-consuming activities is to debug when a part of the code is not being executed where it should, no errors, no exceptions, just a non-running code situation. It happens to be that JS will provide write-only access to the first element asks for it, any other writes happening during this lock will be discarded, silently. to avoid that problem, delay Ace operations using a timeout call.

I noticed this problem by using the network analyzer that is part of Chrome's inspection tools. It provides a timeline with the sequence in which each script has loaded and run.

The mysterious case of Jquery-UI

Our chat uses jquery-UI, but randomly the library seems not to load before we need it. I have tried delaying the attached for some seconds, importing the library globally and locally, specifying the methods to be used when importing. The problem is related to the order in which components are assembled and that document.ready is not sync with Aurelia's loading mechanisms. I discussed previously the order in which an Aurelia component is built, once we are able to customize the lifecycle, we will be able to use them together.

The case

References

Perceived Web Performance – What is Blocking the DOM? Aurelia API Ace's API. Ace's Google group.

⚠️ **GitHub.com Fallback** ⚠️