[1] https://css-tricks.com/alpine-js-the-javascript-framework-th...
[2] https://thinkingelixir.com/podcast-episodes/021-tailwind-css...
Oh, finally a hipster stack after my own heart. My initial stack used Web Components instead of Alpine.js, but after one year trying to make it work (using lit-element) I'm battered, bruised and I declare Web Components a failed piece of technology [1].
Alpine is interesting, but not powerful enough for my use case, which is encapsulating common UI behaviours in reusable packages. Stimulus seem to be the missing ingredient in the mix for me. Any other suggestion for lightweight rich JS components that do not require one to buy into Vue, React or other "full-stack" JS libraries?
Also, I wholeheartedly recommend Unpoly as well, fits nicely in the PETAL stack.
1: shadow DOM isn't great on your OWN components, styling isn't fun paired with global CSS/tailwind, dealing with properties/attributes/observables/reactivity in general is an absolute pain in the buttocks, good luck wrapping an <input> in a web component.
[1] http://surface-demo.msaraiva.io
[2] https://thinkingelixir.com/podcast-episodes/024-liveview-upl...
Depending on your needs, you can sort of use Alpine + server-side templating to achieve this. While Alpine itself has no concept of components, you can define a template fragment that consists solely of the “component” for basically the same effect. Because the x-data directive is freshly evaluated each time it appears, you can include a fragment multiple times and get isolated “instances”.
YMMV though, I eventually found that because templating is much more simplistic than a real tree of components as you would get with Vue or React, things started getting hard to follow, especially when my “components” were nested, or involved approximating slots.
Ultimately I converted to Inertia.js, which is a very small glue library that lets me write the whole front end in Vue (or React, or Svelte) while keeping a more traditional Laravel (or Rails) backend.
Also, did you try with pure JS ? no lit ? I just removed StencilJS from my component to go pure-JS and it turns out I really prefer it that way, maybe it would suit you too to do WC without any additional JS lib ?
1. There is not a lot of documentation
2. They don't provide any testing guidelines, the best I've found is hand-wavy test-with-a-browser stuff
3. Everything is essentially global
4. Functions are disconnected from their parameters, i.e. I can't tell which bits of data a function is using without digging through a bunch of code.
5. Putting state in your HTML is tricky if you also want to modify the DOM.
6. Their naming scheme is cumbersome, e.g. data-controller="using-a--sub-directory" and data-target="some--nested--target-has-a.function", that is, the fact that everything is location-in-your-code-file-structure based.
And a lot of other small things.
Ironically, using Stimulus convinced me to switch to Vue because I liked their value proposition of "Javascript sprinkles for your HTML", which Vue lets me do, but more intuitively.
Anything more complicated though, and you are better off with Vue, React, Etc
Just being able to put
<button @click.prevent="save(<%= id %>)">Save</button>
Instead of: <button data-action="click->some--long--path-to#save" data-id="<%= id %>">Save</button>
... save(event) {
event.preventDefault()
In my HTML has been worth the switch for me.If you think you need a JS framework to handle your UI, you've already lost, and you're doomed to reinventing wheels that these technologies have already perfected.
The amount of extra work and complexity that a separate FE introduces requires serious benefits on the other side of the equation.
Apparently Stimulus 2.0 is part of that directional change
Tweets: https://twitter.com/dhh/status/1334916143010680833?s=20
My only complaint/comment is that some of the HTML that I need to generate ends up being littered with so many data attributes, especially when combining multiple Stimulus controllers/behaviors.
Has anybody found a clean way around that in Rails templates?
Once the boundaries of your server-side parts for something are congruent to the client-side parts, you have reached the nirvana state of wondering, "can I extract & package these into a library and share it?".
This is general advice for all development but particularly and specifically true for Rails devs.
Basecamp seems to use liberal newlines / spacing when creating html tags (like one line per attribute) so that might help.
Server-side "component partials" still don't have a great story, but view_component is one emerging option.
https://haml.info/docs/yardoc/file.REFERENCE.html#attribute-...
Not knocking on stimulusjs, but just be wary that it does not grow well with increasing client side complexity. You'll end up writing a lot of javascript boilerplate / DOM manipulation code / custom state management components. From my experience, it's a nice lightweight tool for when you:
1. Just need to add some light interactivity (toggling visibility of components, any basic view filtering) that do not involve a lot of logic 2. Don't need j.s unit tests (stimulus has not been the most testable tool - we lean mostly on integration tests).
One typical example is a component that collects (and displays) education history provided by the user. I'll list out just a few key UI behavior:
* A "read" view which represents a list of containers with titles that show each instance of a users answer (for example, if you provided 5 sets of answers, such as 5 universities you attended, we need to show those 5 in some sort of preview form on the page)
* A button that when clicked opens up a modal which contains multiple "steps" - each step is a small set of form inputs that range from simple ones like date to more complex ones involving search / autocomplete or file uploading.
* A button inside the modal that lets you navigate through the various steps / groups of form inputs.
* A "save" button inside the modal that persists your answers. This closes the modal and shows your set of answers as an instance in the list view (see the first bullet).
* In-line validation errors as the user is filling out each step of the modal
* Messages to notify the user that a modal needs to be opened and completed (Like if the user closed the modal before filling everything out, we want to let them know it's not fully completed).
Where some of the biggest complexity crop up:
* Form input data handling and general state management. As I mentioned, we can have upwards of maybe 20 controls in this component. At minimum, we need to write code to listen to input changes and make sure this new information is kept in sync with both internal component state and other parts of the UI. If you gave us a valid answer, we need to make sure to update the UI to show a checkmark (in the simple case). We also have controls that show or hide based on your answers to other form controls, so we'll need to handle inputs by potentially hiding or showing other inputs.
* Ok, so what if we need to write some UI updating code? Well, updating any part of the UI requires manual DOM manipulation. At minimum, this can be something simple like toggling visibility of an element by adding or removing a class. At worst, this involves appending html template strings (like if we need to show a list of errors on top of the modal) when the user attempts to save bad answers.
* Cross-component communication is difficult. Want to add a subcomponent? And it needs to communicate with the parent? For example, each step in our view is sort of a "sub form" and it needs to talk to the parent "modal" to keep global state - you'll need to roll some basic event handling code between the two.
* Testability. All these DOM changes - how do we test that our component is behaving? At the time we adopted stimulus, there wasn't a standard way of testing our stimulus controller so we've mostly leaned on (expensive) UI integration tests.
Some of this complexity is sort of inherent to forms - forms are complex UI components. There are hosts of libraries in other frameworks for dealing with form inputs alone (in order to cut down on the boilerplate you have to write). For example, formik in react helps cut down on a ton of boilerplate you have to write in order to wire the form control DOM state to react state.
Some of this complexity is also our own doing - we keep A LOT of state in the DOM. If a user blanks out an answer, we need to update the DOM with an additional form control whose value will get passed back to the backend to persist the change in the DB. Moving over to ReactJS won't help us here - this will require changes to our backend vs frontend API's.
However, having to handle the bulk of those DOM changes yourself requires a lot of code, is pretty error prone, and quite hard overall to maintain (as anyone who has rolled apps using vanilla javascript can attest to). StimulusJS doesn't offer many facilities for changing your UI in a declarative way.
Finally, cross-component communication is very common and while there is a number of ways to pass data back and form between stimulus controllers, there isn't really a nice way to do it outside of passing events. This is fine for simple cases, but error prone for our use cases. In reactjs, invoking callbacks that change parent state feels much more straightforward and has been easier to test.
Hope that helps
* easy AJAX loading like turbolinks (<a href="?page=2" up-target=".content">)
* easy AJAX modal (<a href="/users/new" up-modal="form">)
* submit a form whenever any input changes (<input type="search" up-autosubmit up-delay="500">)
* respects the way HTML is intended to be used, so the page still works even when JS is disabled
Gonna check this out in the AM.
EDIT: Couldn't sleep so checked it out now. Looking through the issues, there are a couple that are apparently "fixed in 1.0" but it doesn't look like 1.0 is coming anytime soon. Shame.
And maybe documentation too. Turbolinks has really good docs and conceptually it's pretty easy to get going (1 line of JS and learning a few event handlers). Alpine and StimulusJS have really good docs / guides and tons of practical examples if you Google for a specific problem you're trying to solve.
Unpoly's docs seem like it's mostly an HTML front-end to their API spec with very few examples. It's kind of difficult to figure out how to use most of what it does. There's also very little practical examples of using it if you Google around.
I've heard of it in the past but never got into it because of the above.
Turbolinks falls short in providing a "framework" in how to use third party libraries - how to initialize them and how to tear them down. I finally glued together a mini-framework with hints from stack overflow, but Unpoly and their concept of compilers[1] is much more consistent.
2018 https://news.ycombinator.com/item?id=16052105
It’s encoding conventions that we’ve fallen into using it for the last year. The callbacks in value changes are going to make my life much easier.
Wouldnt stimulus and turbolinks not work so great i would prefer using different libraries.
My original thought was to go for an SPA with a rails API backend. I tried out both React & Vue extensively but got stuck in a while. Since implementing Rails and plain 'vanilla' JS it went better. But with StimulusJS 1+ it went simply great.
Allready upgraded to 2.0 and it feels even more structured with the new features, like values and improved targets.
https://github.com/danjac/localhub
StimulusReflex is a Rails thing that's much more involved than Stimulus.
React (and React-rails) moves rendering / state / logic clientside. You can use tools like react-rails to more easily pass data from your Rails controller to your react components (basically conveniences to create props from instance variables).
Stimulus doesn't handle rendering at all. It's intended to be used for small little "sprinkles" of JavaScript (think things like: showing / hiding content, toggling classes, basic event handlers). If you used to write jQuery snippets to wire up a click event to run ~5-10 lines of JS, then you might look at Stimulus as a more modern implementation (es6, mutationobserver, etc). Stimulus plays nicely with Turbolinks since it needs existing HTML (servered rendered from normal Rails views) to attach to.
You're basically looking at two diverging paths: do you go down a JS-driven SPA application with React (or some kind of hybrid where you have React do parts of the page) or do you opt for Basecamp's "I cant belive its not a SPA" approach with Turbolinks, server-rendered HTML, and Stimulus for small interactivity.
Here's a talk I gave at the London Ruby meetup about Stimulus and in what contexts you might want to use (or not use it): https://assets.lrug.org/videos/2020/september/matt-swanson-s...
If a new HTML element is added to the DOM and has a controller, it just works and is now active. This might not be the case with React or Vue, as you'd have to then bootstrap the component.
This makes Stimulus a really good combo when used with Turbolinks or partial Javascript responses.
Are they implying one shouldn't use it if you don't have any HTML already?
To understand their philosophy, see DHH's blog post announcing Stimulus 1.0, https://m.signalvnoise.com/stimulus-1-0--a-modest-javascript...