Show HN: Introducing Harp – A static web server with built in preprocessing
sintaxi.com
sintaxi.com
I've been using Harp for about 3 months and really like the sweet spot they have found between a bucket of static files and a full-blown web app stack. It's a very new paradigm and you probably need to try it to fully appreciate it.
So far we don't deal with the authoring abstraction layer. Our focus is on solving deployment by automating performance optimization like asset bundling, caching & CDN integration.
The big vision is to provide static hosting for the programmable web. We make HTML forms work and provide an API for sending the input wherever you want. This OAuth2 based API also handles deploying sites, injecting code snippets, and updating individual files.
The real moonshot here is developing a standard similar to JSON Patch for updating HTML via PATCH requests. If Harp, or anyone reading this is interested in this idea, we'd love to collaborate on developing a spec.
Of course, letting users upload arbitrary CSS served from your domain is an XSS-level risk, but let's say you let each user have his own domain and let them upload .less files.
Or you have a say, node.js APP that lets a user enter LESS and spit out the -- escaped -- CSS.
Now they can do:
div.hack {
background-image: data-uri("/etc/passwd");
}
When compiled with lessc 1.4.2, this embeds the contents of that file as base64.Also, with 1.3.x."@import" lets you open any filename and insert it, but it's required to be valid .less. I suppose you could try to @import /dev/random or urandom although I don't know if there's any practical attack surface for decreasing entropy. I don't think I could offhand find a valid file.
However in the theorethical web page evaluating .less, the error output will contain the contents of the file @imported.
Oh, and the evaluation of Javascript... I couldn't make it do much useful, as it seems there's some kind of limited JS environment that code executes in. The worst I could do was:
div {
background: `process.kill(-1, "SIGKIL")`;
}
The "fs" object does not seem to exist there, but I don't know enough about node.js/V8 environment to see whether there's equivalent of jailbreaks.So, uh, don't compile arbitrary LESS files and send users their output, and LESS files someone sends you or checks into a project can kill your processes (at least).
Then you can have rich features like includes without worrying about file-based info leak. (cpu-timing attacks are perhaps another kettle of fish).
I prefer this style of a setup to coupling them together a-la Harp. If the webserver doesn't work out, I can swap it out. Same with the build system. Tying them together makes me antsy. And for good reason I think: since 2004, we have switched from Apache -> Lighttpd -> Nginx, and have switched from custom shell scripts -> Make -> Tup (with some fabricate.py, and with calls out to other build systems like Leiningen)
Yes, the lazy compile (JIT) or "build on request" as you put it plays a huge factor when it comes to performance. Because it doesn't rebuild the world each time there is a change it is able to expend the cpu cycles when it matters most.
Under the hood we have the HTTP and the precompiling system decoupled. The precompiling is done with a library called Terraform which acts as a uniform source agnostic compiler. Harp wraps this with a HTTP layer and and SSG layer. See https://github.com/sintaxi/terraform
"In a typical build system, the dependency arrows go down. Although this is the way they would naturally go due to gravity, it is unfortunately also where the enemy's gate is. ... In tup, the arrows go up. This is obviously true because it rhymes."
"<diagram of tup vs make> See the difference? The arrows go up."
Let the code breath a little -- no whitespace around control structures is a bit jarring:
if(error){
...
}else{
...
}
Instead: if (error) {
...
} else {
...
}
Maybe adopt this Node style guide: http://nodeguide.com/style.htmlA strong statement whose motivation escapes me; it's not as though you can't trivially get the source of the extension in your REPL of choice.
var pets = ["dog", "cat", "rabbit", "turtle", "owl", "alligator"];
for(var i in pets) {
console.log(pets[i]);
}
And what do you get? dog
cat
rabbit
turtle
owl
alligator
function () {
return !this.length;
}
Oops! And here you could argue that the other coder should've known to use hasOwnProperty or forEach or whatever, but, all that aside, extending native object prototypes is an easy way to break code all over the environment.I don't think you can dismiss that argument so easily. Other people modifying natives is the reason that if you're unsure of your environment, you shouldn't rely on `for(el in array/object)` without appropriate `hasOwnProperty` checks.
If you have control over your environment and the developers who will work in/with it (ex. the code for your website vs an npm module you plan to publish), then I see nothing wrong with naked `for (el in array/object)` or with extending natives if it's worth the added cost of developer overhead (they have to know that they're working with extended natives).
IE8 is the last version of IE for WinXP.
On the other hand, Windows XP is barely six months shy of EOL, and IE 8 currently has something like 4% share. Now would seem to be an excellent time to start dropping support for IE 8. Such support is never going to gain you more users, and many other browsers run on Windows XP.
"Don't use Object.defineProperty because a dying browser on a dying platform doesn't support it" strikes me as a rather weak argument. I mean, there are still people out there using IE 6, God help them. Why not shoot as low as we can?
Neither WinXP nor IE8 are dead there, not by a long shot.
As for the enumeration example, you're not making a point about extending the environment in general, but only about extending it wrong -- that is, by simply assigning functions to prototype slots, rather than using Object.defineProperty to do it right.
There are arguments to be made for writing style guides and programmer's cheatsheets with a half-competent audience in mind. All of those arguments are bad ones. The linked guide is generally reasonable, but I'd be a lot happier with it if it said "extending prototypes is usually a bad idea, but if you have to do it, here's how to stay off the landmines", rather than a superficially snicker-worthy insult to the reader such as "don't do this or you'll go to hell".
The simple fact is a static web site on its own is not good enough but its 95% there. Using a full-stack framework is overkill, and needing an Static Site Generator just seems counter productive when considering simplicity is one of the biggest upsides to shipping static assets.
There is no good reason for static web servers to do a little extra for you like smarter redirects, clean urls, layouts/partials. This makes sense to me considering the direction we are headed.
It really comes down to the mental modal of how people look at the tool and how they expect it to behave. Avoiding the term SSG has helped with that.
Right now I'm using grunt to precompile my app to plan old HTML / JS /CSS but there are modules for node that can also compile and cache for me, Either way, I don't have to mess with something that works (NGINX)
Regenerating all the assets every time there is a change just feels sloppy to me. Also, I think it is asking a lot from novice developers to setup these configuration files and the knowledge one needs to have to do it effectively is a needless burden on someone who specializes on front-end development.
No disrespect to NGINX. Its too busy powering the internet to be concerned with these problems :)
Less/Sass seems easy, but I'd like to see more regarding JS build/min/concatenation scripts in Harp. Or is this not its goal?
For now, I use Wintersmith. It supports Jade and Markdown out of the box, and you can extend it by writing plugins.
I wrote one to help me "load" dependencies, without having to use <script> tags. I use Devon Govett's importer[1] for that.
The most horrible thing about trying to build out Node.js applications these days is wishing for the Rails asset pipeline.
http://harpjs.com/docs/environment/lib looks like it should make it very possible to tie this up next to rendr and get the best of all worlds.
We use Harp to power our development platform that has Dropbox integration. It is currently in public Beta and I'll definitely be talking about it in the future.
There is no mention of it in my article because we didn't want our business to get in the way of the open source initiative. We believe in Tim O'Reilly's guidance "Create More Value Than You Capture".
I think the big challenge will be with the languages themselves. LESS, Stylus, CoffeeScript, and Jade are all implemented in JavaScript. Finding C implementations would be tough. Though SASS has a C implementation.
Actually, this is where I tried to go with Punch(http://laktek.github.com/punch) too. Vast majority of the content in web can essentially be static, it's just the minor inconveniences of plugging data sources, updating and managing them is what should be addressed.
I find it hard to understand why one would use this over DocPad... Can someone fill me in, I'm curious to know what the interest is about in case I'm missing something!
We are publishing a spec for how Harp compatible servers should behave and we expect to see other implementations in the future.
They're 7 times slower than a static site server that I wrote in Go.
Forget comparing with Nginx.
Does Harp handle Haml?
Looks like an interesting project, though!
Just ran a spellcheck on it, man!
"We already have extreamly reliable"