Perhaps a longer answer than you wanted, but here’s my take
JAVASCRIPT STATE
Perhaps the main challenge was not reusing the majority of the previous Javascript. Most Javascript libraries manage state in memory (jQuery, React, Angular, VueJS, etc). Trying to make these libraries work with Turbo often causes unexpected behavior, which often in the end won’t work. I personally attempted to use the older Turbo library (turbolinks) with in-memory JS frameworks and ran into many of the same challenges. With the Stimulus best practice of storing state in data attribute tags, it works very well with Turbo.
Some of our developers still struggled with state using turbo+stimulus at first, until they realized that they were saving state in memory instead of in html attributes. You want to consider doing this in both HTML and Javascript.
- HTML
<div data-controller="search" ... data-search-last-search-value=""></div>
- JS (set/update
data-search-last-search-value
)
Stimulus values:
this.lastSearchValue = event.target.value; //=> updates data-search-last-search-value=""
or custom attributes
this.element.dataset.lastSearchValue = myVar; //=> updates data-last-search-value=""
We’ve had little problems or complaints since reaching this paradigm shift.
ASSUMPTIONS/MYTHS
We also had to overcome a few of our own assumptions or “myths” before moving forward.
MYTH 1: SLOWER DEVELOPMENT WITHOUT LARGE CONVENIENCE LIBRARIES
Even with stimulus targets, we thought we couldn’t live without convenience libraries like jQuery or Lodash. They “speed up development”. The challenge with these libraries is they tend to be large and include a lot of code, and we hoped to have small and fast javascript files.
MYTH 1: CONCLUSION
Turns out you can now to the majority of what these convenience libraries do with the latest browser version. We googled “you don’t need (XYZ Library)” and found lots of resources showing how to accomplish the same thing using vanilla JS, and it does not always take as much code as you think. We no longer feel we need these convenience libraries.
MYTH 2: YOU CAN’T EASILY IMPORT MODULES DYNAMICALLY WITH STIMULUS
Some libraries you do not want to rewrite. For example, we use the zxcvbn: Low-Budget Password Strength Estimation library to help our users create stronger passwords. However, this library is more than 400k compressed and would make our payload much larger. We wanted to dynamically load this library only on pages that use the stimulus controller which uses this library. We assumed we would have to add a custom javascript tag on the page to load it. Our previous JS stack helped us do this without even thinking about it.
MYTH 2: CONCLUSION
We found the following article which shows us how to dynamically import the module.
It worked perfect, exactly the way we hoped.
MYTH 3: HOTWIRE REQUIRES MORE EFFORT TO WRITE CUSTOM COMPONENTS
Before starting, we felt concerned that using Hotwire instead of JS libraries with a larger community and more shared components would results in a slower development time. We did an exercise to rewrite the overall layout and one page using Hotwire with TailwindCSS.
We then measured the “effort” of prior vs hotwire stack using the “lines of code” to see how much more code we needed to write in order to write our own components using Hotwire and TailwindCSS vs the previous library (which included JS and CSS). (Note: I recognize lines of code as a horrible way to calculate effort, but we did not have any other way to measure).
EXPERIMENT: LAYOUT + PAGE 1
To our, surprise the layout + one page (which required multiple custom components) contained almost the same number of lines in custom JS, CSS and HTML as our prior stack. It did not result in more (as we assumed). Even better, a good percentage of this custom code existed in stimulus components which we planned to re-use in future pages.
EXPERIMENT: PAGE 2
We performed the same exercise on a second page and again compared the amount of new code written. Because we reused the components we wrote for page 1, the amount of new code was significantly less.
MYTH 3: CONCLUSION
For our application, Hotwire used approximately the same amount of effort to write pages with custom components as it was to use a prior stack with existing components. After the initial components, the amount of effort decreased dramatically as we re-used components. Note: one of the key strategies to properly writing an re-using components came from this article: