New Stimulus Design Pattern?

Sam Ruby Sam Ruby on February 24, 2021

As far as I know, this is a new design pattern for Stimulus. At the very least, it isn’t something I was able to readily find with Google searches.

First, let’s gets some standard stuff out of the way. The Ruby2JS.com is built using the Bridgetown static site generator. Opal is used to generate the bulk of the scripts to be executed. HTTP caching ensures that these scripts are only downloaded when they change. Turbo ensures that these scripts are only loaded once per site visit. Stimulus associates HTML elements with controllers.

All standard stuff so far.

Ruby2JS.com has three controllers on the page. The first is a Ruby editor. The second is a read-only JavaScript view. And the third is invisible, but runs the JavaScript which outputs to the console log. Other pages have these same three controllers with different arrangements and/or different data, for example the Stimulus introduction and the React Simple Component. The Ruby2JS Demo has a Ruby editor and a JS ouput, but doesn’t have a results controller and adds an options controller.

The source to the controllers can be found in GitHub. Unsurprisingly given that these controllers support the Ruby2JS site, they are written in Ruby.

But that’s not the unique design pattern part.

Look at a Ruby editor on any of the pages mentioned. There isn’t really any Actions, Targets, Values, or CSS Classes to speak of.

Instead, updates made in the Ruby editor are sent to other controllers. A global overview of the design of these pages: the options controller on the demo page will update the Ruby controller. The Ruby controller will update both the JavaScript and evaluation results controllers. And there is even a case where the evaluation results controller will update the Ruby controller, but we will get to that in a minute.

All of this is accomplished by subclassing a common base class and overridding the source method with calls to a findController method. The findController method unsurprisingly searches the application.controllers array. This base class also takes care of connecting sources with targets indpendent of the order in which the controllers connect.

Once a source is paired with potentially multiple targets, messages pass via standard method calls and/or attribute accessors (getters and setters in JavaScript terms).

As an example, here are the lines of code where Ruby2JS.convert is called and the resulting JavaScript is sent to each target.

The JSController’s implementation of the contents= method will dispatch the content to the jsEditor.

The EvalController’s implementation of the contents= method will load the script into a script element and append it to the document.

An interesting detail: if you bring up the Stimulus Introduction page and click on the JavaScript tab you will see different results in Safari than you would in see in Chrome, Firefox, or Microsoft Edge. Safari doesn’t yet support static public fields, so an assignment statement after the class definition is used instead.

The way this works is that the Ruby souce code is initially converted to JavaScript using the ES2022 option, and the results are sent to the evaluation controller. The evaluation controller captures the syntax error and given that this occurred on the very first update it will update the options in the Ruby Controller, triggering another conversion, the results of which are sent to both the JS and Eval controllers.

While this usage is quite different than the traditional application of Stimulus, the end result is comparable: a site consisting entirely of static HTML augmented with a small number of data- attributes that cause the controllers to activate.

I’m quite curious if others have seen this usage of Stimulus before, if they find it useful, or have any suggestions.