Show HN: Skruv – No-dependency, no-build, small JavaScript framework
skruv.io
skruv.io
The framework itself looks OK from a quick glance, I'll see if I can give it a try sometime.
I'm searching a small and modern framework since a bit, for hacking together quick small prototypes, personal status-page frontends, and the like. I do not like using bigger frameworks there as after digging around in huge frameworks in the past for work, I want it really just end-to-end understandable.
I actually thought about hacking the few helpers together myself, but I rather like to reuse something to avoid combating different browsers (even that landscape isn't as colourful as it was), and the like. Also, I wanted also to avoid inventing "yet another minimal JS framework".
So, FWICT, Skruv seems to fit my bill actually quite nicely.
Two questions, just out of interest:
Any plans about how to develop and/or maintain this in the future?
Is this anyhow involved in a commercial operation, i.e., where you or other devs can get paid to invest some (maintenance) work into it?
Yes, I plan to continue developing and supporting it although I don't think I'll add too many features since I try to keep it focused.
> Is this anyhow involved in a commercial operation, i.e., where you or other devs can get paid to invest some (maintenance) work into it?
Yes, I use it professionally and can use some paid time to work on it. One of the reasons to post it here was to get some other devs eyes on it and to make it easier to bring on new hires by hopefully building a small community.
I'm curious why you decided to export multiple tag names as opposed to using hyperscript. Something that helped mithril.js gain more traction was that while it is idiomatically meant to be used as plain JS, it's also compatible with JSX tooling for the folks that want that. Also, some things are a bit awkward to express in terms of tag-names-as-functions (most notably, custom components require a hyphen in their names, and SVG tags need to be created with a different DOM API, and some have name collisions with HTML tags, e.g. `title`)
One thing I like about exporting multiple tag names is that it (to me at least) makes it more readable. When I switched over my last team from JSX to JS (that was in hyperapp v1) they did not like writing `h('div')` but were fine with `div()` so I put that together and over time it grew on me. I also kinda like being able to see what elements are used based on the import at the top of the file, but that's secondary.
Skruv still exposes a `h` function that is used for web-components, like `h('my-component')` and you can use it for all HTML elements or for JSX. The rest are just for readability and convinience (and are really just curried versions of `h`).
As for SVG I mostly do that by tracking if a parent was a SVG element and if so I assume all children are SVG namespaced (again, inspiration taken from hyperapp) until I hit a foreginObject element which means to switch out of the SVG namespace. If you have better ideas or feedback on that I'd be happy to listen.
Thank you for taking a look and I'd love to hear any other thoughts you have!
For mithril.js specifically, the hyperscript variation offers an extra feature that AFAIK not many other libs do: the ability to write emmett-like CSS expressions as the tag name (e.g. `m('input.required[type=password]')`). Totally understandable if you think that's too much sugar for your lib, but I've found it handy for usage with CSS frameworks like bootstrap. Mithril.js users also appreciate it and some interesting unexpected patterns came out of that (e.g. `const Foo = '.some.tailwind.thing'; <Foo />`)
BTW, funny story: mithril.js partially took inspiration from an ancient library called dōmo[2] which - as it turns out - uses the tags-as-functions pattern.
[0] https://github.com/hyperhype/hyperscript
Mithril's flexibility is so well designed, we're still finding new and innovative ways to use it, even though the base library rarely changes. Having used React and other libraries for many years, Mithril is still the simplest and most pleasant library out there.
I think skruv comes with even bigger batteries (SVG support, Shadow Dom integration and additional vdom related apis), and I am curious to see how they all play together. The one thing that does seem a bit weird is the html helper functions... like Mithril, I went straight for hyperscript: I think it is very underrated right now but it is actually a good way to write a dom tree -- and you also get JSX support (nearly) for free.
Anyhow, keep up the good work, I think the world needs more micro frameworks like these: powerful but simple enough to be understood and extended easily if needed.
[1]: https://h3.js.org
On hyperscript: I prefer to keep the tag name separated from selectors, to me stuff like element type and classes/id's belong in different places and with css scoping built in I think you won't need as many classes so hopefully it won't be a big issue. In general I want the vDOM/HTML stuff to be a pretty direct abstraction on the HTML/DOM in the browser.
On JSX: There is a generic `h` function builtin that can be used as a target for JSX. I'll put together an example of it in the coming days. I still want the recommended way to use the framework to be without build steps, parsing or dependencies though.
https://skruv.io/Tutorial/step3/ (Inside the renderNode)
Nontheless, I like this direction of a small framework keeping it simple, like Vue was initially.
Now what happens if you want a collection of list items generated by looping over an array?
Assign classes based on some logical conditional?
Conditional rendering?
These are problems everybody has and every template language tries to solve with their own custom syntax.
The point of this method is that rather than create some half-assed template language, you just write Javascript code that acts on and generates a data structure that can then be converted into HTML.
(Note however that while enjoy projects like these and also don't vilify most people who wrote JS-dependent websites, not even in my thoughts, I might think of those who write html with optional js-features as nicer people, more thoughtful/considerate and less childish ;-)
Using a typed languge is such a productivity boon.
The word productive on its own is wholly meaningless without elaboration. What makes a typed language productive? Does the size of the project matter?, why is vanilla js not productive? Is it a lines of code metric? Is it a test suite efficiency metric? Is it a quality metric?
But very briefly I would say that these are the benefits as I see it:
* Access to improved tooling. E.g. refactoring by renaming things is much easier to do without breaking things. Also auto-complete when using third party libraries is a huge benefit.
* Some errors are automatically caught during build-time. E.g. checking the data used in a template lines up with what the component should be passing to that template. Without typescript one should probably verify this via unit tests. With TS these tests are superfluous.
* Improved documentation. It's a lot easier to understand what the shapes are of data is that is being passed around in the application. It also provides the opportunity to define these in central locations (e.g. in the form of interfaces) which can then have additional documentation added to them.
I think the benefits are not so much specific to TS as they are general benefits of using types and a typed ecosystem.
1) tree of function calls like this or hyperscript - this is popular because the language syntax enforces markup well-formedness (e.g. you can't express `<b><i>foo</b></s>`) and it's easy to implement minimalist engines on top of this API style. Hyperscript in particular is also compatible with JSX.
2) template strings - this is popular because you can actually write angled brackets without a build step, but it tends to come at a cost of less syntactical safety (e.g. `<b><i>foo</b></s>` may or may not explode early enough in the dev cycle) and some might argue the semantics of various syntactical permutations are less clear and/or more complex to implement (e.g. what are these supposed to do? `<${a}>`, `<a ${[b, c, d]} />`, `<a ${'b=c'} />`, `a<b, c>d`, etc)
I’m not trying to say that Skruv is state of the art either, maybe it is, I don’t know. But using ClojureScript definitely raises the bar for who has the ability to use Reagent and who is willing to.
why wouldn't you switch the attributes to the second param and set default value {}? seems really redundant this way
section({},
h1({}, 'text'),
article({}, 'text'),
footer({}, 'text')
)
instead of section({}, [
h1({}, 'text'),
article({}, 'text'),
footer({}, 'text')
])
It's a choice, but I think without it you would have a lot more array openings/closings, and they would be more spread out instead of the empty objects, which are kept in the same place."Framework" actually has a meaning beyond "JS library". I'd normally not make this complaint, but the entire home page only tells me what it isn't and some traits it doesn't have, aside from the hint it does weird things to CSS. (I tried to look at the tutorial, but it was a mess on my tablet.) It doesn't tell me why I might actually want to use it. After all, there's no library so concise that it wins the LOC comparison against not including it in a project.
Figured out virtual dom is the one big missing piece to make webdev workable without any dependencies at all.
I can see other people are getting to similar conclusions:)
HTML and CSS are a very good approach to define a GUI. And they will be around for a very long time.
This is the reason why I also don't use React, Flutter and all the other ways to build web/mobile/whatever applications.
I am torn on Vue. It is kind of ok because it lets you work with HTML templates with placeholders. Great. But it alters your data (puts getters/setters on everything) even when you don't need that.
The best solution in my book is to use a javascript template engine like handlebars.
Actually, I should correct myself - yes, the breakdown in terms of technology is HTML, CSS, JS but the underlying abstraction is actually - structure, presentation and functionality.
This is where, imho, Svelte really shines. It helps you to map your mental model of structure, presentation and functionality to it's corresponding implementation of HTML, CSS, JS with a sprinkle of syntactic sugar. This goes way far in keeping the code easy to understand and maintainable in my opinion.
Since those are pretty central to how svelte is used and it's philosophy I don't think svelte is a good fit for me, personally.
We all value different things in different frameworks, and that's great!
At least with Vue I can just include the library into the page, with no mandatory build step.
In the case of Svelte, you're also likely increasing the size of your site, since it transpiles down to simple JS instructions rather than abstracted framework calls.
I think that JavaScript-first is far better for templating the more general case (or the lower level foundation) because JavaScript is where your data lives. It's generally much easier to bring markup into JavaScript than it is data and data manipulation into HTML.
In HTML you need re-invent expressions, scopes, control-flow, references, and imports. You're going to spend more time and code implementing a less expressive, slower, and more proprietary system.
In JavaScript you just need a way to describe fragments of the resulting DOM (whether you prefer JSX, function calls, or tagged template literals), and the rest is just JavaScript.
Now, I do see benefit from the HTML-first approach for a lot of people and some use cases. One reason I also push on web components so hard is that with interop comes flexibility in allowing a mix-and-match of approaches. As a side-project I'm working on an HTML-first declarative component system layered on top of LitElement: https://github.com/justinfagnani/stampino-element
<stampino-element name="simple-greeter" properties="name">
<style type="adopted-css">
:host {
color: blue;
}
</style>
<template>
<h1>Hello {{ name }}!</h1>
</template>
</stampino-element>
<simple-greeter name="World"></simple-greeter>
This can interop with any other web component, so you can write your app components in HTML, but drop to JS for the most complex components and use JS-first third-party components and design systems.I've been slowly seeing more and more of a third approach where there's very little in the way of control flow in the template itself, where data is wired up using different constructs. Solid.js is an interesting example where it uses reactive constructs on top of "plain JS(X)", while encapsulating control flow inside components, which it is then able to optimize aggressively.
You very much can do those optimizations in pure JS. lit-html's repeat() directive implements the list diffing approach used in ivi, Vue. It's invoked just like a higher-order function over an array and a mapper function: https://lit-html.polymer-project.org/guide/writing-templates...
I also don't think custom syntax is necessary or that useful. JavaScript has enough abstraction power in functions and objects that you can build very nice embedded DSLs without a compiler or custom template syntax.
but my main point is that both approaches are still valid, and rather than choose a framework based on its particular DX, we should move away from frameworks and be able to write individual components with whatever DX the developer wants, and have them all work together.
Interesting. I'd say that anything that doesn't let me check that the interface contract for a component is met, i.e. that the component is receiving all the data from the parent that it has declared as required, is close to a no-go for me. I want my tools to be able to statically analyse my code and tell me where I screwed up.
Also any mention of NPM makes me not want to use something. Frankly the tooling around JavaScript is horribly confusing, especially for someone who learned HTML 22 years ago.
Why wouldn't the said someone take a day or two to update themselves on javascript tooling in order to get less confused? There are so many great resources available.
Here is a video of a lovely man who invented Erlang, Joe Armstrong, expressing confusion about how to build a "modern" javascript program: https://www.youtube.com/watch?v=lKXe3HUG2l4 (hilariously he was using grunt - a tool which is now entirely out of favor).
Of course if you've never written a line of code in your life, or if you're angry at the thought of using a dependency manager, you're going to have a hard time. And not only with the web stack.
However, there are an infinite amount of questions one has to answer when starting a new project:
- I see that state management libraries are in a lot of tutorials and talked about online. Which one do I pick? Redux? MobX? Something smaller? Do I skip it entirely? What are the consequences of that?
- Okay, so how do I deliver "pages" in React? Do I pull in React Router as well? I saw an article on using Hooks to replace RR. Do I do that instead?
- How do I handle authentication? Do I use JWT? Which library? I saw some comments on Hacker News that says JWT is terrible. Do... do I pick something else? I kind of need auth so I cant's skip it. What if I need to do OAuth?
- Do I use TypeScript? What is the scope of work for implementing it into my build pipeline? Is it worth it?
- Build tools. Sure, WebPack is the most popular but a lot of tutorials are for outdated versions. A lot of the times I'm googling "how do I do X webpack" and just get different JSON blobs to plug in.
It's just... so much. I just don't care. I don't want to configure Gulp or WebPack or whatever. I don't want to extensively research every dependency I have to pull in to get a working app. There is Facebook's create-react-app and that's a good start. Vue and Angular don't suffer as much from this because they focus more on being complete packages.
Doesn't matter to me though. Phoenix LiveView provides enough interactivity for me.
document.body.innerHTML = `
<div>
Hello world
</div>
`;
the React equivalent is no more complex: const HelloWorld = () => (
<div>
Hello world
</div>
);
ReactDOM.render(<HelloWorld />, document.body);
Add to this a couple of high-level concepts, i.e. that a React component re-renders if its arguments (props) or its internal state change, and you are 70-80% there. Learn the useState and the useEffect hooks, and you are ready to be productive. If you aren't ready for build tools yet and just want to play with the library, take Preact, which has a syntax option that does not require a build step [0]How many hours should this take?
I program for decades. Most of my old stuff using frameworks - say for example, Angular or Jekyll - doesn't work anymore. If I update I end up in a dependency hell that's even worse. It's like XSLT in XML. It will pass. :-)
I agree with you in principle, but I think I disagree in details. Programming using standard web apis certainly feels more future-proof, and all the power to those who have adopted web components. But React doesn't look like it's going away within the next decade. And even if Facebook somehow implodes, and no other company steps up to support the work of the React core team, React's api has been copied by Preact, which has Google's backing; and JSX has spread even wider. Importantly, React in itself is larger than DOM — it is a reconciler that can be used for canvas/webgl (react-three-fiber), for mobile applications (react-native) and windows applications (react-native-windows). So there is a good indication that React will be with us for a while.
But again, I completely agree that many projects that get started with React don't need to have been.
> I program for decades.
Two decades ago, Perl was a good choice :-) And look where it is now.
We are lucky with the rigorous backwards compatibility of HTML, CSS and javascript. But planning for decades may be a bit of an extreme. I wouldn't like to inherit a frontend project that was written two decades ago and hasn't changed since then.
The comment I was replying to was saying:
> there is so much js tooling and documentation and of such wide variety that a year or two would not be enough for even a light review
There's no need to learn the entire ever-evolving JS ecosystem. You pick a sane starting point (a framework tutorial) to get you up and running in a few days, and from there you learn what you _need_.
It's a complicated mess and even seasoned JS developers struggle to answer the above questions. Oftentimes the justification for choosing a framework is that they had read about it in a forum like HN and wanted to try it. Nothing wrong with that for someone who lives and breathes those things but most people want to just get a CRUD UI up, these things are a massive time sink for what they purport to offer.
Especially since you suggest that such developers just need to get a CRUD UI up and running. You don't need a js framework for that.
If you are tainted by old knowledge, then there are things that you wouldn't even imagine is required. Why to I need NPM? JQuery and Prototype didn't need a package manager. You have a ton of tools, different tools for different frameworks even.
The more I look into modern JavaScript the more confused I get.
But that is a question that can be asked of any language. It's a given that any modern language would have a package manager. Ruby has gems, python has pip, rust has cargo, and so on. PHP didn't use to have a package manager, to the chagrin of many professional web developers, until finally there was Composer, and the php community breathed a collective sigh of relief. Package management is good. It helps you define all your project dependencies in a sane way in a configuration file, and put that in source control, rather than download all the dependencies locally and store those in source control.
Javascript had different package managers. It had bower. It had meteor packages. It had something else as well. It had different module formats. It has a rather convoluted history. Luckily, with the popularity of node, we now have only a couple — npm and yarn. Or just one, which is npm, if you consider only the standard tools that come bundled with node.
My current job uses maven and I'd swear a good 20-30% of developers time is spent wrestling with maven dependencies. Especially on a new project.
There's a lot wrong with how npm is used (primarily the never-ending recursive dependencies making proper auditing of the code you use all but impossible), but including tons of script tags on every page and hoping you got the right plugin order without introducing any conflicts was hardly the pinnacle of development.
There are two problems with modern JS, imo. First is all the people insisting you need to use some grotesquely complex setup running on Kubernetes to host a blog that gets a hundred page views per month. The second is that most frontend frameworks want to take over your entire app, and in some cases really want your backend to be running node too. It's usually possible to start small and enhance as you go, but it's not easy.
One way — if you are at all interested that is — is to look for someone who can guide you through the current tooling landscape. For example, I believe Cory House's course on Pluralsight on choosing appropriate tools for a frontend project [0] should be informative in this regard. There are also free tutorials about this subject — for example on egghead.io [1]
The other way is to find the documentation on any of the popular tools: webpack, rollup, snowpack, vite, esbuild, etc. — and just follow along trying to set up a toy project and, by doing so, figuring out what the purpose of the tool is. See the recent Google's site on the comparison of modern tools [2] to find out what each of the tools is supposed to do for you:
[0] https://www.pluralsight.com/courses/javascript-development-e...
[1] this one might be useful: https://egghead.io/courses/how-to-use-npm-scripts-as-your-bu...
Why not? I don't like it when UI logic is needlessly split up and seperated. I like it when things of the same concern are in the same place.
> Frankly the tooling around JavaScript is horribly confusing
I wonder what you think of the tooling and ecosystem for other languages is like? Python, Go, Swift, Rust, C#, Kotlin, C++, etc.
source
because the currently existing HTML/CSS UIs with which I have the "pleasure" to interact do a very good job of convincing of me of the exact opposite
What is better in my opinion is a mix. Use one language or specification to model your architecture and structure and then, strictly on top of that, write (x)html to define your content. (you could also use markdown, just choose a markup language)
Then, for the layout/design, use CSS that is completely separate from your site's structure and content; read: separate file, not embedded in the rest. Well, maybe CSS is insufficient and you also need to use Javascript or some language on top of it because the CSS is still lacking of lot of important things, but that's not a principal problem but a specific problem of CSS as a language.
How is that not well suited to build a logical structure?
Of ccourse the commenter does mention using a templating language but a lot of people will be annoyed with this basic language and just want the full lower of JS to generate the site structure.
<a religion="christian" href="... <div class="main"> oh <div class="sub"> hello </div> </div>
This is valid HMTL but it is not a valid structure in any context that I could imagine, because what is the "oh" supposed to do there?To prevent these (and other) mistakes, the way you can build up the structure should be restricted in a meaningful way and certainly not allow text and random positions and similar things. You could then describe this with a subset of HTML, but there isn't really any reason to choose it, except for "I'm used to it". Better choose your native programming language. And if it is not better than a HTML subset, maybe consider choosing your language.
could you elaborate on that? How would you like to define interfaces in a way different from React or... anything else?
Ne need for build steps. No need for html in the JS script.
It feels like JS from the 2000, simple and light, but with reactivity and speed.
Of course, once you need it, you can just use the awesome ViteJS to get your backend build with SFC files.
This makes vue scale up, but also scale down, which is equally important.
The complexity of React and the OPs framework at least be contained in the frontend. With a server side build step, the complexity of the frontend spoils over to the backend.
You list 13 different sans-serif fonts, and two emoji fonts. The browser is perfectly capable of picking its own Emoji font for emoji characters so this is all completely unnecessary.
Please just use "font-family: sans-serif" if that's what you want, otherwise use web fonts. There's no need for this level of complicated font family micro-management, that doesn't even work.
EDIT: The font list is now down to 'sans-serif', so the issue should be fixed!
Aside from the lack of autocompletion, passing rust closures to js land (DOM) is extremely janky as well. However, that might be caused by my lack of experience with rust.
(If you are curious, this is what I made: https://github.com/SCLeoX/non-grid-path-finder)
https://developer.mozilla.org/en-US/docs/WebAssembly/Concept...
I mean I've probably made one of these for each app I built. It takes a couple of days to write and then you can modify it to fit your very needs...
Kinda sad how little diversity of foundational concepts of the framework there is these days.
ES modules, because we can. vdom, because that's what everybody is doing, and async/await everywhere. Kinda boring.
I like the minimalism of this one though.
Uncaught TypeError: Error resolving module specifier “skruv/html.js”. Relative module specifiers must start with “./”, “../” or “/”. index.js:3:64
I could probably silence it, but since I have examples with that module in the tutorial it felt dishonest to do so.
More feedback from my Firefox (Chrome appears ok): spacing between words is really large. Ticking off font-family (or having it just sans-serif) in developer tools seems to fix it.
EDIT: The font list is now down to 'sans-serif', so the issue should be fixed!
Please make sure you understand the unintended consequences of doing that
Can't rule out group policy settings fudging something though. I'll try another machine.
going to make a hello world app using skruv so I start the timer on my skruv exp
body({
oncreate: (e) => {
console.log(e, 'was just added to the DOM')
}
}, 'Hello world!'),
heh. I find it mildly funny when people recreate JSX from from first principles React.createElement("body", {
oncreate: (e) => {
console.log(e, 'was just added to the DOM')
}
}, 'Hello world!'),
which does not seem that different, right?If you want to you can use JSX with skruv as long as you tell the JSX compiler to use `h` instead, in which case it will produce this:
h("body", {
oncreate: (e) => {
console.log(e, 'was just added to the DOM')
}
}, 'Hello world!'),
which works with skruv.Very arguable. I'll take "wonky XML" over JS function calls any day for readability, and apparently most people would too given that they write JSX rather than use `React.createElement` and that all major frontend view libs (angular, react, vue, svelte, mithril...) offer XML-like templating and people overwhelmingly use it.
At this point I'd be seriously impressed by someone saying "I didn't create a new JS framework, instead I contributed to an existing one".
https://news.ycombinator.com/newsguidelines.html
There are also additional guidelines for Show HN threads:
Be respectful. Anyone sharing work is making a contribution, however modest.
Ask questions out of curiosity. Don't cross-examine.
Instead of "you're doing it wrong", suggest alternatives. When someone is learning, help them learn more.
When something isn't good, you needn't pretend that it is, but don't be gratuitously negative.
And did you verify that at least a few of those pages contained the search terms?
Because in my experience that is not given:
- Google used to brag about crazy number of results but if I tried to go to page 5 it would admit there weren't any. I guess it was a naive bloom filter or something out of my league that caused it - and those that knew didn't care because it looked good for 99,999% of the users.
- Google has happily ignored double quotes for well over a decade now. Lately I've had some success by using the plus operator immediately in front of the doublequotes. Side note: I feel hesitant to write that. An UX-er from Google might notice it and fix that bug to make it consistent (consistently useless, that would be) :-/
These days I use DDG as default though and after being fooled a lot of times and one too many I don't even bother to look behind page 2 on Google since years ago.
I did contribute a bit to hyperapp for a while and used it professionally. They took a different path with v2 though and forking v1 to add the features listed proved to have a similar diff to writing it from scratch.
- writing new frameworks
- contributing to existing frameworks
- commenting on HN deriding those writing new frameworks
I don't know what the keywords are to Google for the 3rd type, but I suspect the result count would be the highest of all.
Please note, that this is not a dig at this particular project. I'm sure it's nice and all but I'm never going to use it because 1) what's the chance this'll be around and maintained in 6 months time? 2) no community support, probably no way to ask questions or see other people's questions, 3) what's the chance that 1 & 2 will change in a couple of months? This line of reasoning can be applied to most of the new frameworks out there I think.