Presenting the Most Over-Engineered Blog Ever
jlongster.com
jlongster.com
Casey attempts to explain what he did in a podcast[1]. Apparently, he was frustrated enough with CSS's margins that he built a layout engine in C that calculates offsets for every piece of text in the page, then generates hundreds of lines of Javascript that apply fixed positioning to arrange the text.
[1] transcript: http://mollyrocket.com/jacs/jacs_0004_0010.html
You should have seen it about a year ago, it was even crazier. The same layout engine in C, but it also just did a massive innerHTML set at the root of the page with a huge string of HTML. It was awesome.
Good point, though. He beats me by far.
(PS. you probably know this, but I forgive him because he's an awesome low-level games programmer so it's in his blood to do stuff like that)
"This paper proposes a new microblogging architecture based on peer-to-peer networks overlays. The proposed platform is comprised of three mostly independent overlay networks. The first provides distributed user registration and authentication and is based on the Bitcoin protocol. The second one is a Distributed Hash Table (DHT) overlay network providing key/value storage for user resources and tracker location for the third network. The last network is a collection of possibly disjoint “swarms” of followers, based on the Bittorrent protocol,..."
(and I am sure someone will come up with an example of a blogging platform that starts at the level of specialized mesh networking hardware or something like that...)
For me it's rather an expression of ignoring that websites are always slightly differently displayed than a good solution.
Nice work!
Glad to help and again, nice work. :)
You're correct about it being sort of awkward at first when you are figuring out how to structure an isomorphic applications. It gets even weirder when you only use JavaScript as a compilation target.
I created an example isomorphic Clojure and ClojureScript application (https://github.com/domkm/omelette) and wrote about how it works (http://domkm.com/posts/2014-06-15-isomorphic-clojure-1/). It was an interesting experience. I wouldn't recommend it for production quite yet but I'm looking forward (and working toward) the day when we can easily deploy isomorphic applications that are not written in JavaScript.
The more examples we can get of this the better.
EDIT: Ok, I see Javascript is your thing ;), do you think doing it in JS has strong advantages over Clojure(Script)?
If you are not entrenched in the JS world, I would look into Clojure(Script). They've got a lot of really cool stuff going on.
I have significant mental investment in JS, and I work on the JS debugger for Firefox, so I feel like I need to be a heavy user of JS. Also I know so much about all the little corners of server/client JS, package management, how to deploy, etc. I don't think the return would be great enough to re-learn all of Clojure's tools.
If I were to start on certain types of apps (high-performant data modeling, or anything that requires special care about complex flows), I may look into Clojure. But honestly I'm interested in starting to write games so I'm probably going to spend mental energy learning Rust.
Clojure has been fun, so to me is really of being good enough at JS to be proficient at Clojurescript.
- Have the data your view depends on expressed as a named parameter in routes.jsx: https://github.com/appsforartists/ambidex-example--bike-inde...
- Use those named parameters to resolve which stores need to be populated before rendering: https://github.com/appsforartists/ambidex-example--bike-inde...
- Don't render the page on the server until those routes are populated: https://github.com/appsforartists/Ambidex/blob/master/src/ca...
In that example, the editBike view depends on bikeID. actionsForRouterState makes sure that the viewBike action is called to populate the CurrentBike store before any route that includes bikeID is rendered.
I've been trying to do the same sort of thing - currently I'm parsing the routes separately in koa and setting data directly on the stores before the React components load, so they're pre-populated with data. Seems a shame to do all the routing twice though.
- ReactRouter figures out which routes are being rendered. It yields routerState, which includes a dictionary of all the active parameter names and their values.
- The actionsForRouterState dictionary declares which actions and stores are correlated with a particular route or parameter name.
- callActionsForRouterState filters actionsForRouterState to include only the actions that are relevant for the routes and parameter names dictated in routerState.
- It calls these actions, returning a promise that resolves when all their stores are filled.
- After that promise resolves, it's safe to call React.render. Any calls from the active components to Store.listen will be resolved with the prepared data during mounting (e.g. immediately before the render pass).
Is that helpful?
https://github.com/ponyfoo/ponyfoo has over 2k commits
bevacqua, I don't know what you are trying to achieve by that, but if this is an actual serious project, know that this commit log is unreadable and would repel any potential contributor to the project you might find. And I don't mean to offend because, going by your profile, you're obviously a very active open source contributor - but I also found the exact same log quality issues in all your other projects.
If you truly care about them, you should care about that too.
Then again, you don't really need <noscript> in that case. It's rendering server-side, so the page already displays correctly, you just need to make sure all your links work.
I might give React a closer look, having read this.
Here's my lab https://github.com/gcanti/tom
You can define middlewares, as you would do server-side with expressjs:
router.route({
method: 'GET',
path: '/users/:userId',
handler: function (ctx) {
// load user async
getUser(ctx.params.userId, function (err, user) {
ctx.user = user;
ctx.next(); // exec next middleware
});
}
});
There is a `demo` folder with a detailed example. The main entry point for the client is here https://github.com/gcanti/tom/blob/master/demo/client.js#L21I guess an exception would be richer "experiential" type of apps and toys, where some DOM might be replaced with Canvas/WebGL, and transitions/animations/etc take precedence over SEO and initial load time. I haven't seen much innovation in terms of MVCs or frameworks that target these types of sites.
http://conf.reactjs.com/schedule.html#beyond-the-dom-how-net...
Jafar is already a great presenter, and seeing someone using React without a DOM should be inspiring.
Correct me if I'm wrong, but wouldn't this basically become client/server socket programming from the 80's and 90's, using UI widgets for display?
Needless to say, I am a React fan.
That said, here are some things you will run into as you build more complex applications with this architecture. Some are related to shared browser/server JavaScript and some are React in general:
* You will find that some JavaScript libraries you want to use should not be loaded into the server context.
* On occasion, you will need to add server-vs-browser conditionals. And creating components to deal with browser-focused JS libraries (think Google Maps) will require some liberal and sometimes awkward use of React component lifecycle methods.
* Until there's a nice, agreed-upon open-source layering library for React out there, or you make your own, things like click-based (not hover-based, which can work with just CSS) dropdowns and non-modal dialogs are weirder to get to dismiss (when clicking outside of them) than they should be. Just because of the way React events happen and are bound.
* Also because of the way events are bound, it's awkward to write nice reusable form components. Without some trickery, you can only bind events from the component you're writing to its descendents. You can't bind events from one descendent to another. You end up writing a new component for each form every time, which isn't necessarily terrible until you want to make a fancy form builder like Rails provides in ERB. I've tried every which way around this, and I've had some success, but the solution always feels wrong and ugly no matter how I do it.
* This is really more of a good thing, but it's so enabling that you'll never really be done adding convenience features. There are just so many "Wouldn't it be nice if ____ just worked?" scenarios that get you thinking about the next reusable tool you want. I spend a LOT of time trying to create the "perfect" browser-side data store abstraction and the "perfect" lazy loader/renderer component for not-yet-fetched models.
The tradeoffs thus far have been worth it, but we haven't yet found or built the holy grail. So many things are so much easier than the old ways, but sometimes they're harder.
var ProfileUpdateForm = React.createClass({
render: function() {
return <ModelUpdateForm model={@props.user}>
// I don't actually have a reference to `form`.
// I can't have a reference to `form`.
// But I need to link state between the ModelUpdateForm and its inputs.
// Anyway, this is never going to work.
<ModelInput type="text" valueLink={form.modelValueLink("name")} />
</ModelUpdateForm>;
}
});
Weird workaround that I'm not sure is an officially sanctioned way to deal with it and fear might break in future React versions or have unintended consequences: var ProfileUpdateForm = React.createClass({
render: function() {
return <ModelUpdateForm
model={@props.user}
do={function(form) {
// Instead of taking children, ModelUpdateForm takes a `do` function prop.
// It passes itself to `do` which give you a reference to which you can link its inputs.
return <div>
<ModelInput type="text" valueLink="form.modelValueLink("name")} />
</div>;
}}
/>;
}
});
Another idea I've been kicking around and haven't tried would be to create some sort of linker object. Here's the hypothetical end result: var ProfileUpdateForm = React.createClass({
render: function() {
var valueLinker = new ModelUpdateForm.ValueLinker()
return <ModelUpdateForm model={@props.user} valueLinker={valueLinker}>
<ModelInput type="text" valueLink={valueLinker.linkState("name")} />
</ModelUpdateForm>;
}
});
tl;dr - The way React typically wants you to do things, ProfileUpdateForm would have to manage the state. But what I wanted to build was a reusable model-bound form component. If I have to write a lot of model-binding code every time I write a new form, then there's no point to trying to make a reusable component at all. So you start having to try weird-ish ways to get it to become feasible.I have similarish form components [2] which need to do this the hacky way in the meantime (cloning [3] their children in order to pass the form prop they need all the way down):
<forms.RenderForm form={ProductForm} initial={this.props.product} ref="productForm">
<Container>
<Row>
<Field name="productName" md="8"/>
<Field name="tags" md="4"/>
</Row>
...
[1] https://github.com/facebook/react/issues/2112[2] https://github.com/insin/newforms-bootstrap
[3] http://facebook.github.io/react/docs/clone-with-props.html
I haven't had a chance to use react-router, but it's great to hear that they've put in the work to make server-side rendering a reality. I only hear positive things. Kudos.
I'm particularly interested in hearing about your ansible + docker setup. I've been using both a lot lately, and trying to figure out the best way to use them together.
It's turtles all the way down. Well, at least until you get to the guy doing all this with a Makefile with some inline sed.
You may need a session for authentication, but that's it.
This is simply not true. Google announced that they can crawl single page apps just fine nearly a year ago (http://googlewebmastercentral.blogspot.com/2014/05/understan...) and although Bing hasn't announced anything they are likely working on the same thing if it's not already rolled out.
Google does this already; it works. Rendering on the server has little actual value in 2015 but it some how became a critical feature all of the JS frameworks are fighting for without proper explanation of its benefit.
EDIT: It's fine if you disagree and I don't even mind being downvoted, but please do explain.
There is life outside of Google, you know. There are other search engines, other crawlers that are not search engines, other programs people use on your website that are neither browsers nor crawlers.
A couple of examples off the top of my head:
If you link to a web page on Reddit, they run a simple crawler to try and extract an image they can use as a thumbnail representation: https://github.com/reddit/reddit/blob/af09fa8dee69bef4f65a16...
If you link to a URL in Slack, they do something similar: https://api.slack.com/docs/unfurling
Now this is just one anecdote about one pair of eyeballs but I'm a old-school PC full browser using pair of eyeballs, I suspect more and more people and machines are consuming web content in new ways, including without a Javascript interpreter mediating the web experience for them.
Google may be able to index SPAs but they can't do it nearly as effectively as static HTML - which is why still recommend you use progressive enhancement rather than going JavaScript-only: http://googlewebmastercentral.blogspot.com/2014/10/updating-...
Also even with this enabled I think you'll still incur the ranking hit for startup perf.
I have. It's a simple thing to test as well.
I took a certain pleasure in the opposite recently, by writing on a few simple .html files on an Apache server with headers in <h\d> and content in either <p> or <ul>
Wel... "If it's worth doing, it's worth overdoing".