I'm glad alternatives like Alpine exist for small sites that don't need many additional behaviours. But having used Alpine for a medium-sized art gallery website last year, I can't really recommend it for anything larger than a very simple site. The fact that all your code is scattered as strings everywhere without error checking or types makes it really hard to debug and work with long-term.
For lightweight front-end tooling, nothing has unseated the ease of Preact for me.
I've been using AlpineJS on various projects for about one year. The creator (Caleb) is actually a Laravel developer and maintains the Livewire meta framework.
I find the sweet spot for utility frameworks like AlpineJS is when used in conjunction with server-side components [1]. For example, when designing server-side Blade components, the more you can keep within the component itself (e.g. html, styles, interactivity), the easier it is to reason about and maintain the component going forward. If your x-data function becomes unwieldy, consider moving the code to a separate Javascript function that returns an object and calling that function from x-data.
Ultimately, using tools like Alpine or Tailwind is a tradeoff. My apps tends to be relatively small and only managed by myself or a small team. If you're building large, front-end heavy apps; React, Vue, Svelte, etc. are definitely a better fit.
The use with Livewire is part of what makes it such an awesome tool to pair with Elixir LiveView. I mainly just need enough js to do client-side things (like closing/opening menus) and it's perfect for that.
I don’t know much about your project but these tools are really meant to be used in conjunction with “html over the wire” frameworks. IE, your JS has zero business or app logic and is just taking care of small UI concerns like transitions and showing modals. They scale just fine in these situations.
exactly this, and honestly, I feel like we need to get back to this model as an industry.
There are times when full-blown SPA is superior, but not nearly as often as people currently think. And the toolchains get vastly simpler when you're not doing SPA too.
Exactly. I used alpine in combination with django for a project and it quickly became a nightmare to maintain when alpine started to take care of app logic / SPA-type reactivity.
Alpine is just not designed with that sort of application in mind, nor should it be.
Funnily enough, I've avoided react/angular/vue as much as possible specifically because I've _always_ felt it was fundamentally the wrong approach. When I first discovered svelte my reaction was "thank god someone else sees it too".
Over the years I've moved further and further from the web as a result of that belief. I still do web work when needed and as a result I'm familiar with vue and angular but I actively try to avoid knowing any more about them than I absolutely need to for accomplishing the goal.
Coming from iOS, with their Massive ViewControllers, and the occasional (usually half-baked) MVVM, it didn’t seem that bad at first.
On the contrary; components!
Finally reusable pieces of UI! Try doing that when everyone on a team is hell-bent on their One Storyboard to Rule Them Al. Even if you did, @IBDesignable (used to preview components in Storyboards) would just crash anyway.
Instantaneous reloading! Even when it takes a bit of time, it takes less than 3 minutes. Pretty much instantaneous when coming from Xcode.
So, yes, React too was a pleasant surprise at first. The kind you get when you take of shoes that are just a tad too small.
So far, everything I’ve had to type in it was code specific to what I was doing. And that feels nice.
The extra boilerplate that doesn’t bring any value to me, as a dev, when needing to update values at runtime. I find two-way binding to just be simpler.
Same thing for the components and their props.
But I also get why some wouldn’t appreciate having things getting "automagically" done for them.
Not sure what part is confusing, Svelte and Vue have their own template languages inside HTML, I don't want to write another `v-for` or a `#if :else` instead of JS/TS.
I had the same feeling with Vue2-3 a while ago, I'd say Svelte is relatively similar in feelgood as both eliminate a lot of annoyances to create "leaner" components compared to React.
I've been using daisyui + svelte and I'm pretty happy with it so far. It may not be as rich as some of the react UI libraries but the basics are all there.
And for Alpine it's sort of fine. People have taken Alpine a lot further than the original intent, which is to add sprinkles of JS to what is otherwise a server rendered page.
For anything even slightly more complicated we have things like Mithril or Preact, and yeah they avoid this sort of thing for a reason.
I’m glad when tools like Alpine remain in their niche. Too many of them grow with their userbase, adding every requested feature, until they become as unwieldy as the framework they originally tried replacing. If you outgrow Alpine, migrate to another framework instead.
Then why not go with nextjs outright so you can apply the exact amount of interactivity for every little detail on your website without changing your entire setup halfway through.
Next.js is a fantastic solution if you're building a SPA.
Imagine I'm a very early stage startup so I start out with a simple app built on Laravel. All my engineers are relatively non-senior PHP folks, not great at JavaScript. So it's rendered server-side in PHP - easier to achieve enough performance, security, maintainability by leveraging the framework. Then I want to put some tiny bit of client-side interactivity. Going full SPA with Next.js would involve a lot of extra cost and complexity. jQuery and Alpine fit well into that niche, and Alpine particularly helps with reacting to state in a way that jQuery is hard.
I don't really understand why people want so bad to mix in code into HTML.
The whole fight since 2000 was to avoid doing that through minimalistic templating and naming elements semantically so you can attach the logic from outside.
That approach (i.e. the jquery style of attach logic to the DOM) just doesn't scale when you're writing a single page app where _everything_ needs to have JS logic attached to it. It turns into a complete mess of imperative UI twiddling and it's extremely easy to forget to update some little element in response to a change.
The bigger question IMHO is if you actually need a SPA. If you don't then yeah the old jquery style (now alpine.js or similar frameworks are spiritual successors) is perfectly fine.
Scaling comes from splitting your app into components and correctly mamaging staye not from the way you attach things to your view layer.
jQuery didn't scale because there was no recommend way to split it into components and managing state.
Those day Backbone.js was amazing innovation.
If jQuery came into existance today when we know what we know about components and their role in building large applications it would be perfectly suitable for many applications.
I agree with this, we managed to sometimes create SPAs faster even though we had to duplicate template/initial page logic on the server side for each page in case of direct link/page refresh. Nowadays sometimes figuring out which prop you misused from a 3rd party component based on a 100 lines TS error takes more time than the actual coding.
I wanted to use something light so I tried Preact without build tools. It was awful, nothing worked (like router and store), so I switched to Vue.js - where everything just worked out of the box. Not sure if I was just unlucky in my selection of js files, or what, but I can't recommend Preact from this experience.
This was a concern for me but when the Remote Ruby devs had the AlpineJS guy on last year, he mentioned that you can pull them apart into data components, which provides a separation that I found quite tidy. Did you check this out and find it unsatisfactory?
I did! I actually forgot about that feature when making the parent comment. It was a useful addition to a degree.
I used it for more complicated components like a mobile nav with animations, and for some re-usable pieces like a subscribe form. The downside with Alpine.data is that it splits the HTML from the JS, so developing and refactoring was a bit of a pain, and caused errors because of old variables I accidentally left in the HTML (whereas Preact/TSX would give me an in-editor error).
It also didn't really mitigate the need to wire up all the pieces your data component exposes into an HTML correctly. Though, this was working inside a simple PHP-based templating engine — maybe one that supports better snippets with parameters would make that part of the experience better.
I’ve made an Alpine plugin that can do a lot of the common things Unpoly does: https://imacrayon.github.io/alpine-ajax/ I’m actively working on it and looking for feedback.
I want to try building something with either and see if it works for me. But last time I couldn't decide between it and alpine and ended up using neither :/
agree with your comment.
i'm using alpine with django and it's is really nice.
some very small sites are using it in production like Vimeo (link:https://vimeo.com/customers/enterprise)
>> The fact that all your code is scattered as strings everywhere without error checking or types makes it really hard to debug and work with long-term.
I'm afraid this doesn't match my experience.
All your code can be in a single file (or as many as you want) with window.app = function(){return{show:false}}
I use this in one project but its bundle size is very large for what it does. I think Preact is usually a nicer option (and no, it doesn't require build tools and NPM if your IDE of choice is notepad) with a React compatible API.
It's 3KB. Even less if you opt to not have any React compatibility at all.
Or for people with bad connections. If you expect high latency it can be worth it to embed js code to avoid the additoinal roundtrip. 10kb makes a big difference for that.
As someone who has shipped thriftily-sized sites targeting developing countries, what you're describing is a needlessly extreme optimization. Inlining 3kb of data vs. 13kb would be a nearly unnoticeable difference for even the worst connections – like in Guinea, whose median download speed is around 3mbps.
Inflating the document size does impact paint time, but it scarcely matters here.
I'm currently on a roaming cell phone connection where T-mobile has graciously given me 256 Kbps down. That actually would be a noticeable size difference. I don't have a deeper point, just thought it was funny that I would love a 3 Mbps connection right now.
Which sites do that for any meaningful reason? I see this argument often, but have a hard time either coming up with an idea of a business for which it would be non-marginally profitable or finding a real app/site which does that to cover the last mile of its world-wide scale.
Until that I believe this argument is equivalent to “what about Mars”. By supporting dead slow connections on Earth you simply support them to remain so.
Literally none...this is just the argument of contrarians or people who've only ever worked on personal projects who take offense to real applications used by actual audiences.
The largest, most painful and apparent issue with JS related build tools is that they change and break. Frequently.
And no, `package.lock` is not enough of a solution, because you will have to update dependencies at some point. Congrats, you now have multiple moving, breaking parts in your dependency tree that throw the weirdest and unrelated errors. So you're hunting down github issues, workarounds and patches, while still not really knowing what the problem was. The bonus here is that you need to remove these workarounds at some later point because your build tools and libraries have fixed the issues, so your code breaks again with very fun error messages or just straight up opaque and weird behaviors.
At some point we have to ask why we're doing this to ourselves. It's not fun at all.
Agreed. Try inheriting a project that hasn’t been updated for a few years. Between the absolute dependency hell, and major breaking changes, there is huge temptation to just rewrite the whole thing.
Even a basic application requires layers upon layers of dependencies. Many of them are not as mature as people like to think either.
Rollup has always been a straightforward path. Vite (built on rollup) is super clean. Before that even, webpack was relatively stable between versions.
If you just used Gulp / Grunt / Browserify I am a little more sympathetic, especially with Grunt / Gulp, but I always felt their limitations were obvious.
Browserify somehow managed to snatch defeat from the jaws of victory IMO
I think almost of these are on the list of past and present enemies. I haven't used Vite but I have better things to do than change the build tool in dozens of projects a year without any guarantees that it will not break like the rest of them.
if you adopted vite from 1.0, you wouldn't have a need to change build tools in dozens of projects a year. Its really stable. Same with rollup. Webpack (was?) a little less stable, but it didn't churn at that rate either.
I'm just not sure where the churn is from. If you're talking about meta frameworks, like create-react-app, that churn alot and change things underneath, I get it, though with tools like that, one should always seek to stay on the happy path only, as its otherwise a recipe for disaster.
Everything you said is true, but it's not limited to JS once you add 'package.lock' isn't a solution.
I've had compatibility issues with rebar, rubygems, pip, go modules and many more.
Once you're pulling in third party dependencies and the tools that manage them - in any development environment - you open yourself up to these issues. At some point, you have to update dependencies and/or tools (for security reasons if nothing else). And at some point, either the dependencies or the tools will break in a way that has you hunting down issues and workarounds that are outside the scope of what you're actually trying to accomplish.
Is JS significantly worse in this regard? It does seem like the propensity for many small packages increases the surface area of things that can go wrong, but that doesn't seem to be a flaw in the tooling.
The problem is that if your underlying stuff, like npm, webpack, babel or w/e changes or breaks, then _everything else_ breaks too. _All_ your dependencies can have potential issues. Meaning you have to update them and boom you code breaks too now, because someone decided to change the API.
And yes that means that bigger surface area leads to more problems.
This is less severe if you are only working on few projects at a time that you gradually update. It still sucks and is completely unnecessary, but only in tiny bits over a spread out time period.
However if touch code from just a year ago, then you might get some of these fun, breaking changes and bugs. Even more fun if you're not familiar with the build tool, or the packaging tool, because there are a dozen of those around as well and someone decided to use X at the time because why not. And you need a specific version of those too.
The Go modules thing is similarly painful, but it's not the best example of what I describe, because there is a very clear cut change from the previous way of doing things. It sucks but there is a clear path forward. With a JS project you get the feeling that you are walking on a minefield.
JS is significantly worse. npm, yarn, webpack, babel, rollup, vite etc etc. Too many dependencies. Too many breaking changes. if build fails, error messages are horrendously cryptic.
Change, sure. We've had browserify, parcel, rollup, webpack. Then the next wave hit with snowpack, esbuild, vite, lasso, turbopack etc.
There's a few that have hung around like rollup and webpack, but there's definitely a constant feel of chasing the dragon when it comes to js bundlers/builds, if not JS tooling as a whole.
I have encountered a mix of several weird bugs and breaking changes with gulp, webpack, rollup and what ever Nextjs uses. Also build related bugs with several popular libraries and the resulting versioning and dependency issues. NPM has disappointed me in similar ways at least a couple of times too. Babel is its own hell.
Basically touching a JS project that hasn't been updated monthly is incredibly anxiety inducing.
And now there are several new build tools since a relatively short while, which makes the issue even worse. They might be improvements in some dimensions but they all invent their own little world again, promising this or that. But it all sounds so familiar and I already lost trust.
I'm proud to say I recently published a library on npm and decided to specifically deliberately not publish anything other than ESM. Now bundle sizes are significantly smaller.
That’s the right thing to do. The issue that I mentioned included switching suddenly in highly depended-on packages without waiting for major end-user tools to catch up, splitting NPM across ESM for few months. It was a deliberate and non-systematic action. That’s why it’s worth ignoring it here.
Absolutely nothing and I advocate and push for them wherever possible.
But I mentioned them for the usually very vocal crowd on HN (and others) that dominate any JS orientated conversation by pissing and crying that build tools exist.
Apparently, to this crowd, the act of compiling code is perfectly OK everywhere else but a travesty to need or want to do any of that for software that runs in a browser. Weird.
Build and dependency management is the worst part of the javascript ecosystem. Other languages do this much better. We're not against build tools for javascript. We're against bad ones.
I'm only against adding a build tool when it's a small project that shouldn't require that complexity. I've seen projects where maintaining the build setup was more work than maintaining the code.
Yes, I've seen that too and it's a testament to how bad the ecosystem is.
However, the kinds of problems that existed in 2015 thanks to detracting tools like WebPack and Babel don't really exist now with the fact that browsers support ES modules and Node is dragging its heels but now mostly supports ES modules.
With things like typescript and vite I now never have the problems that used to be common. In fact when I see people creating brand new projects in 2023 using WebPack I cry a little in side.
At some point having a bad tooling experience can't be solely blamed on the tools. It's a choice.
This is pretty neat. I think being lightweight, and having a very small API is important.
But honestly, at this point function-style JSX/TSX is hard to beat in terms of API. There's basically no DSL to learn (`x-for`, `x-if` and so on), you just use plain old JS with all of its existing capabilities. And it's just a JS function, in come props, out comes HTML. You technically don't even need JSX to do this, it's just syntactic sugar over plain JS function calls.
Sure, React is bloated, its full API has huge surface area (that you almost never need), and there are some icky parts (state, side effects, basically the whole hook system is ehh and doesn't fit the functional paradigm).
There's definitely room for improvement there, but I think it will probably not come from React, but some other JSX-based framework (Preact and SolidJS suffer from some of the same issues).
In any case JSX is going to be super hard to beat IMO.
JSX gives you the appearance of HTML with a boat-load of unexpected rules/exceptions to learn further hidden behind a compile step. Because of the rules, it's harder to onboard and riddled with complexity. To top it off, being XML-like it's hard to read and write. I miss the days when the docs had a toggle to show it as simple, trinary functions. If JavaScript had better function application syntax (like spaces), it'd be easier to reason about and read/write.
Which rules/exceptions are there that are an inherent part of JSX (and not React)?
The only ones I can think of are className instead of class (unfortunately a reserved word in JS), and the addition of convenient event handler attributes (like onClick), which aren’t real attributes in HTML (where handlers are attached to elements manually via JS). Other than that, it’s just like HTML, no?
(Now that I think about it, I’m not even sure that those are parts of JSX and not the React API)
Regarding being XML-like, it’s a matter of personal preference I suppose, but I prefer it that way since it’s basically HTML with tags that you can make yourself.
Don't forget about htmlFor. And to to camelCase your attributes. And style attributes need a double curly brace (never mind the obtuse error message if you only put one!). Fix all those <br> elements, they're no longer acceptable. width=100, nope. What's that funny looking <></> for? Good luck Googling it. WTF did they put {foo && bar} everywhere?
Everyone likes to complain about the DSL that Vue or Angular use, but by the time you learn all the exceptions and oddities of JSX you could have easily learned how to use Vue's templating system.
And the fact that it's common for someone to have no idea whether a feature is part of the JSX syntax, or the framework they're using, or the HTML spec itself is problematic. It's very clear where the v- directives come from.
Yes, but it's not pragmatic or intuitive to use the && operator as a stand in for an inline if statement in non-JSX-land. Doing this is something of an ugly anti-pattern, `let foo = bar > 12 && "there are dozens of us!"`. The fact that it works as an inline if for JSX is almost an accident that has now been abused into convention.
className and onClick are not part of the JSX spec though.
The biggest differences between JSX and HTML5:
1. In JSX, all elements need to be explicitly closed whereas in HTML5 elements like img and br should not be closed.
2. In JSX, attribute values are quoted strings, JS expressions in curly braces, or nested JSX expressions. In HTML5, you can leave e.g. numbers unquoted.
3. In JSX, you can use the 242 character entity references from HTML4 but not the 2231 from HTML5.
A topic not mentioned in the JSX spec is how whitespace between tags is handled, but HTML5 errs on the side of including too much whitespace in the output whereas a React app sometimes includes too little.
What we so though is there exists obvious differences. This means you need to understand HTML but also intimately understand JSX and how it differs. It does not match expectations, and looking like HTML doesn't make it more approachable. The original function syntax (more often I seen referenced as hyperscript now) was a simple DSL of functions that took 3 arguments: string name of the element, object of attributes, array of children (technically varg with keys needed for arrays). These functions are understandable by anyone with a cursory understanding of JavaScript.
`className` bit is React specific. Preact, Solid JS and others allow you to use `class` (and sometimes both) no issue. Some just opted to follow React's lead there
I think what he meant was that the style of JSX does lend itself well to parallelism (e.g different subtrees can execute in parallel), though to the best of my knowledge no such implementation exists (maybe something can be done with WASM or WebWorkers)
Yeah - 100%. I have pulled this off successfully with some crazy household names in tech. I really value some of those random emails - I go back and read them from time to time.
People are often really chill and kind about answering questions and love to help people who take a genuine interest in their work!
That's precisely my issue with React though - JSX is a DSL that looks almost like normal HTML, but differs in small uncanny-valley ways. Sure, it's fine once you're used to it. But it's very much not standard HTML.
Just one example: the class attribute in HTML vs className in JSX.
It’s not that it’s complicated, you just use one or the other. But it’s very indicative of what’s going on under the hood: despite looking exactly like HTML, JSX isn’t creating HTML. It’s creating elements via JavaScript APIs.
The only "debatable" thing that React does is to use the names from the JS API in JSX (where some people would expect names from the HTML API because JSX looks like HTML)
That’s basically what I said, though? The point is that JSX is made to look like HTML so you think you’re writing HTML but you’re not, you’re using a JS API.
Also I had to laugh at the sibling replies:
> Narrative violation: className and friends are NOT a React thing!
> FWIW, the className prop is a React thing not a JSX thing
FWIW, the className prop is a React thing not a JSX thing. Other libraries which use JSX will happily accept a plain class prop. The React limitation is abstraction leakage: props are not attributes, they map to DOM properties.
But to the point that JSX is a DSL, that limitation is specifically because React itself is very tightly coupled to DOM semantics… but JSX explicitly has no built in semantics[1].
1: First sentence of https://facebook.github.io/jsx/ - “JSX is an XML-like syntax extension to ECMAScript without any defined semantics.”
That is just wrong on many levels. JSX brings an XML-like notation to JS. It has nothing to do with HTML. react-dom couples your React DOM to the real DOM - thus allowing you to use special JSX elements that create DOM elements. But then you / React interacts with them using the DOM API - not HTML source code.
Things like `htmlFor` or `className` should not be confusing - these are the official DOM properties. `style` in its DOM API also has an object-oriented API and not a string. If you are confused by these things (className vs class, ...) then potentially you started learning JSX from a completely misleading / wrong point.
I know most articles on React / JSX get that wrong, but this non-sense has to stop. After all, you do not write React in the browser because you want to generate HTML - you do write it to manipulate the DOM. On the server, you may want to generate HTML and then this can be misleading (true), but this has not been the main objective.
Telling someone they learned something wrong maybe isn't the best approach when trying to explain why something should not be confusing. Especially when it's a widely held view, maybe the learners are not the problem.
Most people learn JSX when they learn React. It was created by Facebook for React, after all. What does the React docs teach about className?
Here in the intro it doesn't even explain that you need to use className instead of class. It uses it with no explanation. Then it throws in a line about camelCasing and assumes that you understand why it changed.
Finally! In a page that seemingly has nothing to do with JSX we get told to change how we write HTML, but we're not even told why. (The htmlFor section tells us.) No wonder people are confused.
Yes, className is a property of the Element interface but it is not the attribute used when writing HTML. You're still changing how you write HTML. It is no longer standard. That is the point people are making here - JSX introduces enough edge cases that you must learn that it adds equally as much mental overhead as the template DSL for Alpine or Vue. Even if people understand the reasoning and it is not confusing, it's still a shift.
> Here in the intro it doesn't even explain that you need to use className instead of class.
Again, because `className` is not React specific, it's JS DOM API specific. Sounds like the real problem is that people start learning React without fully learning the JS DOM API itself, then they get confused when things like `className` or `htmlFor` show up.
> Yes, className is a property of the Element interface but it is not the attribute used when writing HTML. You're still changing how you write HTML.
You're not writing HTML. That's the entire gist of the parent comment. It looks like HTML only insofar as HTML is a type of XML. But what you're really doing underneath is something like:
JSX is simply syntactic sugar on top of DOM operations like that (albeit within the context of a renderer like React; Svelte eschews a renderer entirely and truly is creating DOM operations like above). In React, JSX would be direct syntactic sugar for:
It is standard, it is in the Element API, I don't know how it can get more standard than that. Again, it sounds like the problem is that people really should learn JS and DOM separately before ever touching React. Sadly, too many beginners in web dev and programming in general gravitate towards a React/Node stack, which are good production tools, but they really ought to know how we got there.
Now why I don't use DSLs is because they don't use the standard of the JS DOM API, they use their entirely new creation, like v-for or #if :else. That is why I consider Vue or Svelte templates to be DSLs while not JSX, because the latter is fully compliant with the Element spec, and it uses plain JS/TS, unless you define a DSL to be so broad as to be literally any transformation of code, which, well, I can't practically agree with.
> JSX is a DSL that looks almost like normal HTML, but differs in small uncanny-valley ways.
My point was not that its a common misconception that JSX has something to do with HTML - therefore comparing it to HTML and then being surprised that it isn't, shouldn't come as a surprise.
Also it does not differ in small uncanny-valley ways. Just one example on the syntax level: HTML has real self-closing elements (e.g., `<img>`) while JSX requires you to explicitly self-close (e.g., `<img />`). In HTML you also cannot explicitly self-close any element (e.g., `<div />` will just be parsed like `<div>`), while in JSX you can. I don't even want to start about whitespace etc. - those things are actually found / listed in any decent JSX tutorial.
I strongly agree but looking at the Alpine examples it feels like the worst of both worlds to me. At least JSX allows code checking etc, putting code inside HTML attributes has a real ick factor for me.
No, you're not. There is no JSX of any sort in the example the parent commentor provided, nor in the approach that they present, even outside of that specific example.
The first parameter is the component, which is string containing the HTML tag name for built-in components which are basically just HTML elements, such as div, span, img, h1, etc, but the actual component (a function or a class) for any other type of component. The second parameter is the props. The third parameter is the children, which happens to be a string in this case because the content of the h1 in the example is pure text, but if you'd want anything more complicated as children, you couldn't put in a string and pass that, you'd provide it more React.createElement -provided values.
React at it's core is a function (or set of functions) that interpret strings like "h1" into DOM elements in a browser.
JSX is a shorthand for writing those function calls. <h1> becomes React.createElement("h1"). Sure you are still largely using HTML element names, but that's only because people don't really use JSX for anything else. The whole point is that it's easier to write JSX than the underlying function calls.
Why is it such a strong factor for you? I see this point being made every time someone mentions a framework that doesn't use JSX.
But frameworks are so complex nowadays! Learning something the size of React, whatever templating language it uses is the least of my worries. Especially because calling it a DSL is a bit of an overstatement, it's always just HTML with a few custom tags/attributes that let you inject values, use loops and conditionals.
For me it’s cause there exists already perfectly capable and better ways to do these operations.
I don’t need or want to work in an environment that reinvents how to map over a list.
Frameworks and libraries have their own APIs like reacts hooks or solids signals. Yes these can be involved but they are different from the generalized solutions that the framework reinvents with the custom properties in alpine or the looping I mention
An API exposing the capabilities of a framework is different than reinventing data attributes, looping etc
Seriously. That `x-show="open"` example is so ambiguous. Is it setting a `hidden` attribute? Setting CSS `display`? Or `visibility? Or is it actually removing it from the DOM? If so, is it deleting the node or just holding on to it?
hard agree. also especially brutal if you have to enclose it in strings like this, meaning you need to write an extension/language server to get this to have any semblance of a good developer experience
I'm using Alpine.js in a Django project and it does what it says on the tin. It blends well with the MVT style of Django along with HTMX and makes the client side interactions really easy. This is now my favorite JS framework for doing light client side JS magic.
Nothing, if it works for you great! I’ve found Alpine code to be more declarative and easier to reason about. Also, jQuery often requires you to write more code to do the exact same thing in Alpine.
One thing jQuery does better is AJAX, Alpine doesn’t have builtin AJAX tools. I’ve made a plug-in to bridge that gap though: https://imacrayon.github.io/alpine-ajax/
Not only are the names used in the documentation different from what the main page says, but not a single one of the numbers match. Not sure what to make of that.
Its slightly misleading, but not really an outright lie. The extra items don't look at first glace like they are adding a ton of complexity or anything. Some of the unmarketed ones do look like they are more advanced features that are not needed most of the time.
Alpine.js is seeing an increase in utility as it pairs nicely with htmx[0], Phoenix LiveView[1] and the likes for lightweight interaction that doesn't require the server.
Actually, HTMX has a fundamental flaw if it comes to history restoration: In some scenarios it takes snapshots of the DOM for history navigation, just before navigating away from a page. If the DOM was previously modified by other JS libraries like Alpine, jQuery or any other tool, these changes end up in the history snapshot, leading to unexpected results [1]. I've had a much smoother experience with Alpine + swup [2]. Disclaimer: I became a maintainer of swup this year.
Say you have a collapsible menu (Burger etc.) which you just implement with a simple CSS based toggle. You open the menu and then navigate to a different page (via htmx). All good. But now your back button will break because it will send you to the previous page but with the menu open.
In this particular case it's _kind of fine_ depending on your navigation concept and design. It might even be a feature! But this behavior just proliferates little workarounds and caveats and can lead to surprising UI bugs, especially if you need some state management in-memory etc.
So htmx is great the less JS you use on top of it, except you are very aware of how it operates and how you interact properly with it's events. It's a very well designed and small library overall - with caveats.
I don't know as much about the underlying issue as the sibling, but I've also found that LiveView and AlpineJS interact in complex and unexpected ways in the case of components. The only sane way I found to integrate them was to make an Alpine-based component which is solely responsible for rendering itself, and then communicate updates back and forth with the LiveView process via custom events. That works but it's fairly heavyweight.
I would like to be able to use Alpine in precisely the cases where the JS commands aren't enough. This case was one of those accursed custom form controls that designers love to come up with (a dropdown with checkboxes and a search filter).
Ha, right. I was in that same position. Unless you're working with a fixed, non-search, massive dataset, I found the performance is just fine doing it in pure Liveview over the socket, but I don't know your situation.
Yeah, indeed, doing it in pure LiveView is a realistic option, but it does degrade the user experience for e.g. someone on a crappy 3G mobile connection.
For lightweight JS interaction, I prefer the Stimulus controller approach that doesn't mess too much with your HTML, and doesn't try to sell you "components"...
Petite Vue appears to be dead. ISTM that Evan You saw Alpine, made a quick proof of concept version using Vue, then handed the project off, and it died. Nothing wrong with that! But I don't think it makes sense to use it over Alpine for anything serious.
“petite-vue is indeed intended to fill the gap for progressive enhancement cases where Vue 3 would be too heavy-handed.
It is not abandoned, but rather it is considered "done" because the scope is well defined. I don't think it needs more features (as that would defeat the purpose of being lean and minimal). If you find yourself needing more than what petite-vue provides, you can either go up to Vue proper, or try https://alpinejs.dev/.
That said, I should update the README to indicate this more clearly.”
Alpine is great. I've been using it in production since 2020, and I've never had any complaints. I like that it embraces JS instead of pretending that JS doesn't exist, like other microframeworks do. (I'm thinking of Stimulus and HTMX specifically.) Alpine's job is simple: it adds encapsulation and reactivity around JS. Other than that, it's more or less vanilla JS, and you can use it the same way you'd do things if you were doing document.querySelector yourself.
Yeah, this is the dealbreaker for me with alpine.js and htmx.
And I wouldn't even say "tight CSP" as much as "standard CSP." To make alpine.js play nice with CSP, you have to allow unsafe-eval, which severely weakens your protection against XSS.
alpine.js claims to have a compatibility build with CSP, but it's not officially available, doesn't fully work, and the parts that are broken in the CSP build aren't documented.[0]
htmx works under CSP, but it opens a new vector for attackers to inject JS into your page, which effectively neuters CSP.[1]
> htmx allows you to define logic directly in your DOM. [...] One concern with this approach, however, is security. This is especially the case if you are injecting user-created content into your site without any sort of HTML escaping discipline.
You should, of course, escape all 3rd party untrusted content that is injected into your site to prevent, among other issues, XSS attacks. Attributes starting with hx- and data-hx, as well as inline <script> tags should be filtered.
That's been SOP for web development for aeons. I'd say the rewards vastly outweigh the costs. Not a deal breaker for me.
>That's been SOP for web development for aeons. I'd say the rewards vastly outweigh the costs. Not a deal breaker for me.
You should always sanitize inputs and encode outputs, but it's difficult to get that right 100% of the time. With CSP, you have a pretty robust safety net against XSS for when you encode user-controlled data incorrectly. With htmx, you're forfeiting the safety net.
I understand that not everyone wants to use CSP because a lot of libraries break it, but to me, giving up CSP is a pretty big sacrifice.
I agree that htmx warrants an extra level of awareness as to the loss of that safety net. Especially if your encoding/escaping is done manually and is very localized (i.e. you explicitly call escaping functions from your templates or other output functions), In such cases, CSP is crucial.
That been said, that's not how XSS has typically been handled. Usually, those encoding/escaping steps are already made part of the tight Request/Response stack in the backend (e.g. as middlewares, as part of a data mapper library, or as a filter activated on the template engine or Response library). Also, this is usually a default behavior that often requires to be explicitly disabled. And as long as you don't have some "rogue" I/O processes completely outside of that pipeline, you're set.
Because of this typical setup, I tend to consider CSP a mere redundancy for XSS. If you lose that extra protection due to htmx, what you gain seems far more valuable to me.
IMO, Libraries like these should state their CSP compatability upfront, Any JavaScript minimalist who are likely the target developers for these libs likely has full CSP implementation on their back-end.
Telling our library isn't compatable with CSP in a footnote seems disingenuous.
I've desperately searched for one, but I can't find anything. Stimulus[0] I believe is compatible with CSP, but I've found that it's more work than just writing vanilla JS.
I've heard good things about mithril, but I've never tried it.
When I see tools like this, I remember once again what a great revolution angularjs was. If people are happy with tools like this, of course that's important, but I don't think I'll understand the logic of writing javascript code in an attribute.
Check out Joystick [1]. It's designed to be a logical next step from learning the fundamentals of HTML, CSS, and JavaScript. No surprises in terms of syntax or tooling (if it's in the specs/docs for those languages, it will work in Joystick). It's also full-stack, meaning you can start out building simple web pages with components and upgrade to a full-blown app as you learn more.
If you have any questions, feel free to get in touch: ryan.glover@cheatcode.co.
I agree that you should start with vanilla JS, but Alpine is a good follow up because it just adds conventions around what you'd be doing in vanilla JS anyway.
I"m not a programmer so I was learning js from basically nothing. As others have said, I have found it best to avoid frameworks if possible. One of the biggest reasons for me is a lot of the examples and things on places like stackoverflow is out of date so I would find myself learning a framework to do one little thing and then a few days later find out there was a new pure js way to do thing or that the way I figured it out was depreciated or something. SO try to stay pure at the start.
Every framework will teach you a different way of looking at things… can’t go wrong picking one and going really deep, then exploring some others. I wouldn’t recommend one specifically, but definitely start with one and stick with it for a bit
> but definitely start with one and stick with it for a bit
Devs are paid quite a bit of money to play russian roulette with their tool choices.
Frameworks are an abstraction and not really key to understanding anything. And devs need to understand, at least conceptually what the framework is doing (or attempting to do) without too much magical BS. Ideally that starts with working with the dom and seeing first-hand the pains and joys of adding and removing elements, functions, sync and async behaviours, data handling, objects etc.
Then only will frameworks click and make sense, and so choose the right tool for the right job.
> devs need to understand, at least conceptually what the framework is doing (or attempting to do) without too much magical BS
This strongly aligns with how I like to learn, and is one of the reasons (besides lack of need) why I haven't touched JS thus far; everything seems to focus on the revolving door of frameworks, but it isn't clear as an outsider if any of them are "purer" than the others. The reason for asking about this one in particular is that at a glance, it appears minimal and clean - but I suppose that doesn't necessarily correspond to it being an idiomatic example of simple JS done well.
I think there is definitely value in both approaches and depending on your preference one may be more fun than the other. My point is not to get caught up in the framework of the day.
Am I the only one who doesn't add random attributes to the existing HTML elements? I use the dataset `data-` attributes for that.
You can go nuts with custom elements though.
Maintainability and browser compatibility (less of an issue these days). If you use a non-standard attribute and hand your code off to someone else, they likely won't catch it and can introduce bugs.
Nothing makes it more of a problem. Same as any other code. Just the idea of introducing non-standard things (especially if used inconsistently) increases the likelihood that things will break and be harder to fix.
For example, if someone binds an event listener to an element in two different places with something like clicker="button" in one place and then uses data-clickable="true" in another place, it can introduce confusion. Not only does the original developer have to remember all of their custom attributes but so does anybody else who comes on to the project.
There is also the PETAL stack: Phoenix, Elixir, Tailwind, Alpine, and Liveview. The ordering doesn't make sense, but it is a nice acronym. I haven't actually gotten around to developing with it, but I am excited to do so.
I tried Alpine.js a very long time ago. Managed to build some small web apps with Haml[0], but never everything big. It's generally very easy to use but when it comes to scaling it doesn't scale very well. Building a todo app with it requies many lines of JS objects, combined with that every object is defined in a string makes the code look a bit ugly. Useful for prototyping and small web apps if you dont want to use complex stuff.
Looks interesting, I might take a deeper look into using this.
One thing to note, on my mobile browser (Firefox Nightly) the site is a bit broken. The page has the wrong width so periods etc are off screen and for the code example blocks I can't scroll them to see the whole line.
BTW, I feel some affinity for this just because I've been listening to Caleb Porzio's awesome "no plans to merge" podcast for so long. Good blend of entertaining and educational.
People comparing Alpine to React, Vue, Svelte, etc. are missing the point. Not everything has to be a SPA.
There are so many Reacts devs out there that now blogs and landing pages are fully rendered client-side. With a backend only used for its API. Instead of simply sending HTML.
Alpine is great for the simple dropdowns, navigation drawers, etc. The things we used jQuery for before we started to do everything in JS.
I still love writing SPAs but I'll stick to boring HTML with JS sparkled whenever I can.
Shameless plug: Astro supports Alpine.js and is a great dev environment for trying out Alpine for the first time. It runs in the browser as well, via Stackblitz!
To make sure I'm understanding you correctly: you are saying that sites which use alpine will use progressive enhancement, where most of the static content is vanilla html, and then little alpine snippets are used to improve the page (nav bars, widgets, etc). Versus full SPA where all of the content is clientside rendered.
At first, I (incorrectly) thought you were saying that the alpine templates are stored "in the dom", so then google would parse them. For example:
But, once I figured out you were talking about progressive enhancement, I came back to reality that google will only see "Copyright (C) " and won't see "2023".
Note: I think it can be used for CRUD based GUIs, if paired with "Html over the wire" (rails hotwire, phoenix liveview, laravel livewire), but that's a different point.
For Google in particular they can see the 2023 just fine[0], but I think it's needless complexity when you could just do it server side. Maybe it's nice for a rarely updated static site though.
Yeah, I was hoping the HN title would give some context on why it was being posted now (2023). My guess: "TIL about a really cool js framework which has been around for years"? Which in my opinion is totally fair, but others might disagree. :)
What's so bad about charging for a service or for tools? Just because some of the MegaCorps offer Javascript frameworks + tools for free, why shouldn't a small competitor be charging a bit of money for work that is built on top of the free framework to keep it financially sustainable?
It's an optional purchase for people who might want to rather save time, e.g. when you're a small dev team trying to build something, you need to calculate the opportunity costs.
Furthermore, sometimes I will even refuse to use a service if they don't charge money. The interests of a service will often be aligned to those who give the money. So if the money is not coming from me, the supposed customer, it has to come from someone else.
Creator of Alpine here! Those components are the reason I can work on open source full-time. If I didn't charge for anything, I wouldn't be able to pour as much effort into these tools.
Keep up the good work, all the developers I know who are clear thinking know that open source engineers need to make a living too. Thanks for your work.
Why are some dev so cheap?
Everywhere else you want great tools, you are willing to pay the price.
Especially if they help you earn something in return.
but, there are many paid component libraries out there, for various different frameworks, right? other than this being first-party, what’s the difference?
Yet another JS framework. How fast is it really? The learning curve may not be worth it if it's slower than https://www.solidjs.com/ and according to https://krausest.github.io/js-framework-benchmark/current.ht... few things are faster than a very little-known framework called Mikado (https://github.com/nextapps-de/mikado). That being said, I would never sacrifice performance of my software for how trendy or popular something is, e.g. React is #1 in popularity yet it's overcomplicated, massive, slow as hell.
For lightweight front-end tooling, nothing has unseated the ease of Preact for me.