HackerTrans
TopNewTrendsCommentsPastAskShowJobs

TonyPeakman

no profile record

Submissions

Show HN: Dagger.js – A buildless, runtime-only JavaScript micro-framework

daggerjs.org
80 points·by TonyPeakman·10 माह पहले·89 comments

comments

TonyPeakman
·10 माह पहले·discuss
Haha, that’s a great way to put it . Writing one-line code does feel clever in the moment, but you’re right, the “writer’s joy” often turns into the “reader’s pain.” Striking the balance between elegance and readability is the real art of coding.
TonyPeakman
·10 माह पहले·discuss
Thank you — that really means a lot to me. One of the best parts of sharing dagger.js has been hearing from people like you who’ve been down the same path and thought about building the same set of features. It makes me feel like the project is on the right track.

What you described with vanilla JS plus a few helpers is exactly how dagger.js started — I just wanted to save myself (and hopefully others) from having to reinvent the same binding and routing layer every time.

If you ever try it out on your side project, I’d be truly grateful to hear how it feels. Feedback from thoughtful developers like you is what helps me make it better.
TonyPeakman
·10 माह पहले·discuss
Hey, I added two more examples about routers for dagger.js: minimal: https://codepen.io/dagger8224/pen/PwZwgWp?editors=1000 nested: https://codepen.io/dagger8224/pen/bNENZNN?editors=1000

The original react router demo as a comparison: https://codepen.io/pshrmn/pen/YZXZqM?editors=0010
TonyPeakman
·10 माह पहले·discuss
Thanks a lot for the detailed suggestions — this is super helpful.

You’re right that symbols like +//@ aren’t valid in XML/XHTML, and the original idea was just to keep things as short and stackable as possible. But I see the value in a more standard, semantic form like lifecycle.load, control.value, event.click, meta.raw. It’s clearer, easier to search, and plays nicely with stricter environments.

I’m leaning toward offering both: the current short symbols for quick prototyping, and a more verbose but standard form (potentially with dg-
or dot-namespaced attributes) for projects that need stronger compatibility. Your idea of aligning the names with the terminology we already use makes a lot of sense.

And thanks for pointing out the router example — you’re right, the docs only show the “all options” version. I’ll add a minimalist example alongside it so people can see the simple path too.

Appreciate the thoughtful feedback — this gives me a clear direction for making dagger.js easier to use while staying standards-compliant.
TonyPeakman
·10 माह पहले·discuss
Thanks for laying this out — I share your priorities on minimal boilerplate and a buildless-first workflow. dagger.js is designed around that: no bundler by default, just HTML + JS modules, so most code stays reusable outside the framework.

On syntax: you’re right that +/* aren’t XML/XHTML-friendly. The short, stackable directives were chosen for ergonomics, but I’m considering offering a dg-* variant to improve standards compliance where XML/XHTML interoperability matters.

Appreciate the push here — keeping the buildless path the default while tightening standards compliance is exactly where I want to take dagger.js next.
TonyPeakman
·10 माह पहले·discuss
Thanks to both of you for the thoughtful discussion — I really appreciate seeing different perspectives here.

On the “lock-in” concern: that’s a fair point. dagger.js is still young, and it’s reasonable to be cautious with any new project. One of the core goals, though, is low lock-in: your code is still just HTML + JS + Web Components. Even if dagger.js disappeared tomorrow, your markup would continue to work with minimal adjustments.

On code readability: you’re right that the current source is compact and not heavily commented. That was a stylistic choice early on to keep things lightweight, but I understand it can make debugging less inviting. Based on this feedback, I’m planning to provide a more readable version so others can more easily step in.

So the trade-off you mentioned is valid: fewer features, but less surface area and minimal lock-in. The feedback here helps me refine where the ergonomics stop and where maintainability needs more attention.

Thanks again for taking the time to review both the idea and the code — it makes the project better, and I’ll keep iterating with these points in mind.
TonyPeakman
·10 माह पहले·discuss
That’s a really good point — thanks for laying out the example so clearly.

You’re right: Aurelia can avoid a build step and still preserve flexibility, and the kind of helper you sketched (load_modules("thispage")) would definitely make the default case much less verbose while still allowing people to override pieces explicitly when they need to.

With dagger.js the initial choice was to keep everything explicit to reinforce the “HTML/JS/CSS are just independent modules” idea, but I agree that adding a convention-based shortcut on top could make the developer experience smoother without removing transparency.

In future iterations, I plan to add more flexible usage patterns to better meet diverse development needs.
TonyPeakman
·10 माह पहले·discuss
That’s a great example — I agree, with JS Modules and import maps you can already do a lot of dynamic composition in the browser, even with heavier frameworks like Vue. dagger.js isn’t trying to claim something impossible with ESM; the goal is more to make the “drop-in” workflow the default, without needing to wire up import maps or component bootstrapping code yourself. It’s about reducing the ceremony, not redefining what modules can do.

On the styling point: totally hear you. Shadow DOM can be a blessing or a curse depending on whether you want strict encapsulation or global theming. dagger.js doesn’t enforce Shadow DOM, so you can share global Tailwind styles when you need them, while still having the option to encapsulate components.

If you do want to explore Web Components without the pain of rolling everything yourself, I’d recommend taking a look at Shoelace — it’s a really nice library of styled Web Components that play well with dagger.js. You get encapsulated, accessible components, but with good customization hooks for theming. Could be a good middle ground between Lit’s strict encapsulation and Vue’s more global styling.
TonyPeakman
·10 माह पहले·discuss
For anyone curious, I’ve put together a collection of comparison demos here: https://codepen.io/dagger8224/pens . They show the same functionality implemented with dagger.js alongside other frameworks (credit to the original authors of those examples ).

If there’s a particular feature, page, or component you’d like to see built with dagger.js, feel free to leave a comment — I’d be happy to explore and discuss it together. Thanks!
TonyPeakman
·10 माह पहले·discuss
Really glad to hear that — thanks for the kind words! dagger.js is meant for exactly that use case: if you normally avoid heavy JS but occasionally need a bit of interactivity, you can drop in a <script> and use just what you need without a build step or big framework overhead.

If you give it a try, I’d love to hear how it works out for you. Feedback from people who prefer “as little JS as possible” is especially valuable.
TonyPeakman
·10 माह पहले·discuss
Aurelia is a great framework — I really like the way it ties template, JS, and CSS together into one unit. That convention makes it very natural to organize components and reduces boilerplate.

You’re right that dagger.js takes a different approach: it treats HTML, JS, and CSS as independent modules that you explicitly wire together. The reason is to keep everything buildless and decoupled — you can serve each piece directly from a CDN, mix and match across projects, and avoid any assumptions about file structure or bundling.

The trade-off is exactly as you noticed: dagger.js doesn’t auto-bind a .js class to a .html and .css file. It gives up that convenience in exchange for transparency and flexibility in how modules are loaded.

That said, I think your idea of a convention layer on top of dagger.js (similar to Aurelia’s “unit” model) is interesting — it could make sense as an optional helper for people who want stronger coupling between files.
TonyPeakman
·10 माह पहले·discuss
Thanks for the thoughtful feedback — you raise valid concerns.

The reason dagger.js allows JS expressions in attributes is mostly about lowering the barrier to entry. By keeping everything in plain HTML, you can copy-paste a snippet, view-source it, and immediately see both the structure and the behavior in one place. For small widgets, docs, or internal tools, that convenience often outweighs the drawbacks.

You’re right that it’s technically not “valid HTML,” and that data-attributes would be more standards-compliant. I chose the lighter +click="count++" style because it makes the examples concise and easy to reason about — essentially HTML as a living playground. The trade-off is that it bends the rules a bit.

That said, I agree separation of concerns is important. dagger.js is not trying to replace large frameworks or enforce this pattern everywhere. It’s intended as a minimal option where simplicity and quick iteration matter more than strict layering. If it proves useful but the attribute style becomes a blocker, I’m very open to exploring a data-* form or even alternate syntax.

Also, thank you for sharing your own framework — it looks great. Actually I’m considering adding a pre-compiled, separation-of-concerns version of dagger.js in the future to support a wider range of development needs.

And thanks as well for the docs suggestion about emojis. Feedback like this really helps shape the project in a healthier direction.
TonyPeakman
·10 माह पहले·discuss
As a frontend framework, Svelte apps absolutely run in the browser.However, Svelte relies on a compile step: your authoring code is compiled ahead of time into efficient JS that runs on the client. dagger.js is contrasting itself as purely runtime, build-free — you drop in a script, no compilation needed.

So it’s less about runtime location (Svelte is client-side too) and more about how you get there.

Svelte → compile first, then run in browser

dagger.js → no compile, just run in browser
TonyPeakman
·10 माह पहले·discuss
Glad to hear that! Buildless is the whole idea — drop in a <script>, wire up a few +click / +load attributes, and you’re up and running. The goal is to keep things simple and view-source-able without needing a bundler or toolchain.
TonyPeakman
·10 माह पहले·discuss
Well put — that lines up with how I see the ecosystem too. For small sites, vanilla JS is fine; once you move toward “app,” you either reach for a framework or start reinventing bits of one yourself.

dagger.js is basically me leaning into that middle ground: accept the verbosity/sharp edges of the DOM, but try to smooth just enough of them with directives (+click, +load, interpolation) so you don’t accidentally start building your own mini framework. It stays runtime-only, works directly with Web Components for composition, and tries not to hide what’s really happening under the hood.

So it’s not aiming to replace React/Angular, more to give people a lightweight option before they hit the point where those make sense.
TonyPeakman
·10 माह पहले·discuss
That’s totally valid — if you’re comfortable living close to the DOM, zero-runtime + zero-build is the purest path.

dagger.js is meant for folks who want to stay mostly in plain HTML/JS but still smooth out a few of those DOM “sharp edges” — e.g. inline state with +load, simple event handlers with +click, template interpolation. The idea is to reduce boilerplate without hiding what’s really happening underneath.

So it’s less about abstracting away the DOM entirely, and more about lowering the friction for small tools/demos where you don’t want to write a ton of document.createElement calls.
TonyPeakman
·10 माह पहले·discuss
Haha, true — the front page doesn’t always need another JS framework

dagger.js is tiny and pretty niche compared to the “big ones,” but I figured it was worth sharing since it’s trying to go backward a bit: no build, plain HTML, Web Components. More of a “view-source-able” experiment than a contender for the next React/Vue.
TonyPeakman
·10 माह पहले·discuss
Totally agree — the ESM build of Vue gives you a great “no-bundler” experience with a full framework behind it.

dagger.js sits in the same no-build space, but deliberately strips it down even further: no VDOM, no reactive system, no SFCs. Just HTML with attributes like +click / +load, and it plays nicely with native Web Components. The trade-off is fewer features, but also less surface area and almost nothing to configure.

So if Vue ESM is “full-featured without the tooling overhead,” dagger.js is more like “minimal glue you can drop in via <script> when you want to stay as close to plain HTML/JS as possible.”
TonyPeakman
·10 माह पहले·discuss
That’s a good point — the ESM build of Vue is solid, actively maintained, and does give you a no-build setup with the full feature set.

dagger.js aims a bit differently: it’s even smaller in scope (no virtual DOM, no reactivity system, no SFCs), and is designed to pair directly with Web Components and plain HTML snippets. The trade-off is fewer features, but also less surface area and almost zero “lock-in” — you can literally view-source and drop it into a page.

So I see them as different tiers on the same spectrum: Vue (ESM) if you want a mature, batteries-included framework without a bundler; Dagger.js if you just want minimal runtime directives and WC interop with almost no moving parts.

Appreciate you sharing the blog link — I’ll check it out. Always happy to see more people pushing the “modern JS without a toolchain” approach.
TonyPeakman
·10 माह पहले·discuss
Yeah, that’s a fair comparison — Dagger.js lives in a similar space to petite-vue / Alpine: no build step, HTML-first, sprinkle behaviors where you need them.

The main differences are:

pure declarative mode → there is zero API and third-party code & tool dependency.

Web Components first → you can wrap functionality as native Custom Elements and Dagger will happily coexist.

Directive model → simple +click, +load, etc., instead of reactivity syntax or x- attributes.

Distributed modules → small script modules you can drop in from a CDN when you need them.

So it’s playing the same role (buildless, quick internal tools / embeds), but with a slightly different philosophy: keep everything view-source-able and make WC interop a first-class story.