9 ms·
Alpine.js: A minimal framework for composing JavaScript behavior in your markup
- warpech 7y agoLooks similar to Basecamp's Stimulus[0], with a pinch of original AngularJS 1.x[1]. Care to explain the differences? [0]https://stimulusjs.org/ https://stimulusjs.org/ [1]https://angularjs.org/ https://angularjs.org/
- rolae 7y agoWhile the spirit of using a simple library for javascript sprinkles to enahnce your app is similar, stimulus.js and alpine.js are quite different: Alpine.js has the x-data property, to keep state that you can manipulate, in stimulus all state is directly in the DOM. So for example to make a modal with stimulus, you would add a class to show a hidden overlay. In Alpine you would use a x-show property, that reacts to a change in the data of the component. So the big difference is that alpine has a reactive data context as a first class citizen. In a way it is actually much more similar to AngularJS 1.x than to stimulus, with the idea that it is really intended only to be used to enhance existing html, not to build whole apps with it.
- EasyToRemember 7y agoThat's just silly to memorize Yet Another Framework for markup.
- kitd 7y agoUsername fail ?
- mnoga23 7y agoLooks like client side scriplets - html(structure) mixed up with code(behavior). Can lead to spaghetti code just like it did in the old days (pre JSP) on server side java.
- AlchemistCamp 7y agoThat's remarkably similar to what I heard people saying about React in 2014.
- root_axis 7y agoThe criticism isn't really accurate for react though. React only mixes markup and code in the sense that markup is produced through function calls rather than as the result of processing arbitrary strings.
- lf-non 7y agoPretty much all mainstream frontend libraries have moved away from dom based templating (or augmenting dynamic behavior through attributes) for good reason. It simply becomes unmaintainable for anything more complex than basic interactivity. This approach can't leverage type systems for javascript (like TS, BS, flow etc.) It is easy to end up with mistakes that don't surface as javascript errors and are swallowed completely. You hit weird quirks when browser injects additional nodes (eg. tbody in tables) or restructures invalid markup (eg. div inside p). Ostensibly this approach would help with progressive enhancement, but too often careless usage results in flashes of broken UI which would then fix themselves when javascript kicks in. Then you need hacks to circumvent those with hacks like ng-cloak. Also, in an ideal world this would help with handoff when working with web-designers who are familiar with only html/css but that rarely happens in practice. Every time a web-designer rearranges things in the dom hierarchy the parent-child associations break and that again needs comprehensive testing. Having worked with applications written using knockoutjs as well angular 1 (both of which used similar approaches) which organically grew over multiple years and (to put gently) didn't age gracefully, I wouldn't recommend this approach to anyone. If you can't (or don't want to) go down the road of a full SPA but do want to build interactive applications with non-trivial amounts of javascript, lit-element [1], Vue [2], Strudel [3] and SPF [4] are much better solutions. [1] https://lit-element.polymer-project.org/ https://lit-element.polymer-project.org/ [2] https://vuejs.org/ https://vuejs.org/ [3] https://strudeljs.org/ https://strudeljs.org/ [4] https://github.com/youtube/spfjs https://github.com/youtube/spfjs
- rolae 7y agoAlpine.js really was created for javascript sprinkles, where even vue.js might be overkill. For example, if you have an app, but you need to have dropdowns and modals. Then something like alpine.js can be nice. So it is actually not intended for things more complex than basic interactivity. And what you build with it, should be simple enough you don't need any type system. For people interested, there is a good episode on FullStackRadio on the topic http://www.fullstackradio.com/132 http://www.fullstackradio.com/132
- kreetx 7y ago
- gitgud 7y agoInteresting, I like the HTML-first attitude and the quote "Think of it like Tailwind for JavaScript.". It's also amazing how fast the [1] demo is, I forget how fast webpages can be without Javascript rendering the HTML...
- deleted 7y ago[deleted]
- ehnto 7y agoI don't think it's even the fault of the JS frameworks rendering time, it's all the network latency between asynchronous requests and assets loading in that makes modern websites feel janky.
- arturogoosnargh 7y agoSeems useful for interactivity on sites using static site generators like Jekyll.
- julvo 7y agoThat plus server-side web app frameworks like rails, Django etc.
- continuational 7y agoHow does this compare to Intercooler.js? https://intercoolerjs.org/ https://intercoolerjs.org/
- rolae 7y agoIntercooler is all about getting HTML into your DOM that you get from AJAX requests without actually writing any Javascript. Alpine is more about Interactivity within the current page, without doing a request first. It keeps the state in a data object. Of course you can do similar things as you would do in Intercooler, but it would be explicit in the Javascript part. See this example they give for prefetching dropdown content from the server <div x-data="{ open: false }"> <button @mouseenter.once=" fetch('/dropdown-partial.html') .then(response => response.text()) .then(html => { $refs.dropdown.innerHTML = html }) " @click="open = true" >Show Dropdown</button> <div x-ref="dropdown" x-show="open" @click.away="open = false"> Loading Spinner... </div> </div>
- hombre_fatal 7y agoHaving used Intercooler a few times now, it feels like the worst of all worlds since you now have to write and return HTML at AJAX endpoints and keep that HTML synced with the rest of your HTML (e.g. consider CSS) instead of just returning data from an API endpoint. You end up with a bunch of made-for-Intercooler endpoints instead of thoughtful, general, data API endpoints.
- mands 7y agoWe're using intercooler on our current site and find it easier to keep the API side of the application separate from the HTML-generating MPA side. Internally they both call out to common code, but we like to keep the API-side RESTful and aren't so concerned about REST for the HTML side, both the full page views and intercooler-specific partials.
- vearwhershuh 7y agoYour general data api and your application api should be separated, since they are different concerns with different requirements, as you are discovering. Intercooler is better mentally modeled going from a traditional web application -> more interactivity rather than going from a JSON data API SPA -> an intercooler application.
- deleted 7y ago[deleted]
- strogonoff 7y agoOn the other hand, if you are not opposed to converting to React in the long run[0], but it looks too complex for merely adding some interactivity to a page: it can be simple to incorporate just a few widgets with it, a fact somewhat obscured by extensive documentation. For a minimal start there’s no need to adopt JSX, wrap your head around hooks and functional components, or deal with Webpack configuration. Just add ReactDOM and React scripts, alias React.createElement() to something short like el() for use in render() methods, compose your components and render them at the desired root if user agent has JavaScript enabled[1]. You have the freedom to move the whole page to React later, implement server-side rendering and so on, but you don’t have to. That said, yes, you will be pulling React, which will consume extra bandwidth, and to stay crawler-friendly your React components ideally should replace and improve functionality already provided by the static page in a more basic way. [0] Perhaps you can see your application growing complex enough and you suspect React would be easy to hire for if you need additional help, etc. [1] To preserve compatibility with older browsers but write components as modern classes, you could add a simple frontend build step that runs Babel on JS files with a single preset "@babel/env" specifying your target browsers.
- dragonwriter 7y ago> For a minimal start there’s no need to adopt JSX, wrap your head around hooks and functional components, or deal with Webpack configuration. Unless you've already learned React with class components and lifecycle methods, I suspect it simpler to just not learn them and learn functional components and hooks. It's extra stuff to wrap your head around if you learned the old way first, sure, but it's not fundamentally more complex on its own.
- strogonoff 7y agoI believe making proper sense of FCs and the seemingly arbitrary at first glance rules of hooks requires knowing the underpinnings of how hooks get called. In class-based components “didMount”, “willReceiveProps”, “willUnmount” et al. would be more or less intuitive to a newcomer with just a general idea of how it works. That I believe makes FCs fundamentally more complex to learn from scratch. Personally having some experience I go with FCs if there’s a new complex front-end project that is based on React, but I use class-based components if I need to sprinkle a few on a mostly static website that may have to be maintained by someone else. (Class-based components in a basic case, which would be the case in question, are also quite straightforward to convert to FCs.)
- codedokode 7y agoWhat an awful idea: - first, it is not obvious whether an attribute affects something or not. How are you supposed to know what this or that attribute does? - second, if you made a typo, there is no error messages - third, no there is no namespaces and attributes can conflict with attributes from other libraries What's wrong with good old inline event handlers like onclick? With them you can just click a called function name and see its source.
- whoisjuan 7y ago> What's wrong with good old inline event handlers like onclick? With them you can just click a called function name and see its source. I haven't read the source of Alpine but I'm assuming the inline declarations are abstractions that are moved out of the DOM execution context and therefore can be cached. Real inline event handlers will actually be evaluated and executed in every page load, which will affect performance, especially with inside loops.
- AlchemistCamp 7y agoTo anyone feeling a desire to reflexively dismiss Alpine.js, I'd strongly suggest taking an hour or two rewriting a toy project that uses Stimulus JS into Alpine and give it a fair comparison. If you haven't ever used Stimulus, then I'd be doubly cautious about making a snap judgement. If you're the type who writes every single site as a SPA, then this library isn't for you. Alpine is gaining traction quickly in the Laravel world and isn't going to be disappearing in the near future. On the contrary it's likely to expand and gain adoption in other MVC framework ecosystems. I, for one, am seriously considering for my next Phoenix project.
- mands 7y agoWe're currently using a combination of Intercooler, Stimulus, and React components in our MPA depending on the interactivity and complexity needs of each component in question - so we're certainly not in the SPA camp. However having listened to the Full Stack Radio episode and trying Alpine out, I'm not convinced on writing interdependent JS fragments in HTML attributes. For our team Stimulus feels more robust - store state in the DOM, which then calls full JS/TS classes to do the computation - keeping the separation of concerns intact. We can also make use of Typescript typing, linting, and bundling of our Stimulus controllers, and test the behaviour more easily. Exciting to see more options in the non-SPA world tho!
- Hitton 7y agoI don't see too many situations when using this and saving few KBs is worth it over using full featured Vue.js.
- calebporzio 7y agoHi, creator of Alpine here. Alpine comes out of the server-rendered-app (Laravel/Rails/Django) and static site context. It's important to recognize that. To me, Alpine fills a hole in between vanilla JS (or jQuery) and large v-dom frameworks like Vue/React. I personally think the complexity/overhead of Vue/React/Etc. doesn't justify its value in a lot of cases for me. Often, I'm adding simple interactions to server-rendered pages. Things like dropdowns, modals, dynamic inputs, other reactive doo-dads... By using something like Alpine, I get to keep the data-driven reactivity and declarative template expressions of VueJs, but without all the overhead. (and without a virtual-dom) I thought Stimulus would be the framework for me, but I personally felt I was doing too many manual DOM-manipulations and my code felt more imperative than I like. In my opinion, Alpine is unique in these ways: - You can use it without maintaining a separate JS file or <script> tag (although you can easily break code out into separate files and such if you need to) - It doesn't use a virtual-dom at all and uses MutationObserver to react to DOM manipulations from outside JS (something like Turbolinks, third-party libs, or your own hand-written JS). This makes it very resilient. It won't crumble if you touch the real DOM. - It's lightweight. It's under 5kb g-zipped. - It has a really nice API for listening for and dispatching native browser Event/CustomEvents rather than using its own event system. This makes it a really powerful tool for interacting with third-party libs. It's not a tool for everyone. It's not a Vue or React killer. (although it might be a Stimulus killer lol) If it speaks to you, great. You and I are similar. If not, understandable too. Different tools for different contexts. Thanks everyone for chiming in!
- mstade 7y agoHey! Cool project, thanks for sharing it with the world! If I may offer a suggestion, you should perhaps expand on the rationale in the readme to include some of what you say in this comment. I personally find this to be a very interesting library for rapid prototyping, so if you're looking for use cases that's another one for you.
- aabbcc1241 7y agoThe benefits sounds, would it work with Typescript?
- nine_k 7y agoIf your page logic is small and trivial, anything goes. This thing, svelte, knockout, even jQuery, even bare JavaScript event handlers. As your logic grows, you need a one-way binding to preserve the app's maintainability and your sanity. Hence React (normally with Redux), Mithril, cycle.js, Elm, etc.