aurelia / skeleton-server-render

A skeleton for setting up Aurelia for server-rendering.
MIT License
22 stars 0 forks source link

Implement Server Render and Client Continue #1

Closed EisenbergEffect closed 6 years ago

EisenbergEffect commented 7 years ago

We want to implement server-side rendering for Aurelia as this is an important feature for a number of scenarios within our community. It's also key to continued adoption of the framework as well as library relevancy. Below, I've outlined five phases we need to move through. Reaching Phase Four would be considered a successful, v1 implementation. Phase Five is an important optimization (and probably the most difficult task here).

Phase One: Running Under Node

Basic App

The first test to pass is being able to run a simple Aurelia app under node and produce a string of HTML. This doesn't need to involve any web framework integration. It should be possible with pure Node. Goals of this test are:

Components

The second test of this phase involves creating a couple of custom elements and leveraging the compose element, producing an app with more parts. With this in place, we want to be able to accomplish the same three goals as above.

Navigation App

The final test of this phase is to add the router and set up two or three routes. We'll want to feed the route location into the app, possibly by having another history implementation. With this in place, again we want to accomplish the same three goals as above.

Phase Two: Serving From Express

Once phase one is complete, independent of any framework, we want to begin integrating this with a web framework. In the end, we'd like to make it simple to integrate this with any framework, but for our first step, we should build with Express. At the end of this, we want to take the final test app from phase one and be able to render it to the browser with Express. The Express server should respond correctly to the browser's location by serving the correct route.

This phase gets us the most basic form of server-render, which can be used to satisfy SEO requirements.

Phase Three: Continue (Simple)

In phase three we need to write a small, ES5 library that is able to patch the server-rendered Aurelia output with a client-side running Aurelia app. This library would need to capture input from the user before the Aurelia app is ready in the client, then coordinate with the aurelia framework to swap the server rendering app with the new client-rendered version. Finally, it will need to pass along any captured user events to the client app for processing. For example, if someone clicked a button before the client-side app was finished loading, that needs to be captured, stored and then replayed when the Aurelia app is ready.

When this phase is complete, we have what most people in the community would call "feature complete" server rendering.

Phase Four: ASP.NET Core Integration

With everything running in the native JavaScript environment, we then want to start branching out into other environments. .NET is a huge section of our community and we've got new customers in the .NET space whose plans are contingent on this feature. So, we want to work with Steve Sanderson and the JavaScriptServices project to get full integration of server render into their ASP.NET Core projects.

When this is done, we can probably ship v1.

Phase Five: Continue (Optimized)

Immediately after we get to this point, we'll want to look for ways to optimize the client-side continuation code. Instead of regenerating the entire app on the client, we should look to build something similar to Aurelia's progressive enhancement capability, that rather than creating DOM, uses the DOM that is already present. It's more complex than enhance though, since binding has already taken place, repeaters have already rendered, etc. We just need to connect up component classes and bindings and "continue" from that point on.

niieani commented 7 years ago

I'd just like to add that Phase One is mostly done. Rendering HTML of the app, including routing works as expected, today. The one remaining bug that I found is that all the href attributes pointing to a route, render as href="undefined". We'd need to run more tests for other things, but aside for this small bug I was able to run the skeleton navigation fully on the server.

One more caveat is that we cannot currently render SVG elements, as jsdom is missing SVG polyfills.

Phase Two is very simple, and I'd estimate it at one or two days of work. In line with the forward-thinking of Aurelia, I would propose Koa.js instead of Express. It is developed mostly by the same team as Express, but is based on ES6 concepts like Aurelia, as opposed to Express which is built on top of ES5. Koa's APIs are very similar to Express, with the main difference being that Koa is based on Promises and ES6 Generators, whereas Express uses callbacks.

Phase Three and Five is what I think is the hardest and will take the most time.

EisenbergEffect commented 7 years ago

I'm fine with Koa for this phase, if when we get to phase 4 we create something for express in addition to asp.net. Basically, it doesn't matter to me what we do up front, but before we release we need to make sure we have a couple of the "most popular" server frameworks working.

EisenbergEffect commented 7 years ago

For phase three, we may be able to leverage https://github.com/angular/preboot I don't want to have that dependency. I'd like to stay true with Aurelia's existing method of having all our own dependencies for the core. But, we may be able to leverage a lot of the code there to build our own Aurelia-specific version.

EisenbergEffect commented 7 years ago

I'd also like to note that it's ok for us to write the continuation library in TypeScript, but it needs to compile into a JS file that does not require a module loader. So, basically IIFE.

niieani commented 7 years ago

Perhaps we can just use Node's core APIs instead of adding any of the dependencies, like Express or Koa. The code will be very simple, so I do not think we would even need to use any of their advanced APIs.

EisenbergEffect commented 7 years ago

I'm happy to defer to your expertese in that. My main goal would be to make it as portable as possible.

On Jan 11, 2017 8:46 AM, "Bazyli Brzóska" notifications@github.com wrote:

Perhaps we can just use Node's core APIs instead of adding any of the dependencies, like Express or Koa. The code will be very simple, so I do not think we would even need to use any of their advanced APIs.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/aurelia/skeleton-server-render/issues/1#issuecomment-271922139, or mute the thread https://github.com/notifications/unsubscribe-auth/AAIBnQOYgUWw71-GPDiEneNLN6T5BiVSks5rRQdbgaJpZM4LgQhu .

rquast commented 7 years ago

I'd really like to see phase 1 implemented. @niieani simply being able to output static html covers most of my use cases. I'd like to use your model (via jsdom) as a light weight alternative to prerender.io/phantomjs for SEO. I'd also like to use aurelia as a static site generator.. something like what gatsby for react does.

niieani commented 7 years ago

@rquast Both Phase One and Phase Two are operational, though in a rough state (done very quickly as a demo for a London presentation). It's all available in the ssr branch of the skeleton-navigation repo.

Kukks commented 7 years ago

What's the state on this?

jlaustill commented 7 years ago

What is the status on this? More importantly, how can I help? I'm a seasoned node.js/knockout guy so I'd be happy to help if I can.

EisenbergEffect commented 7 years ago

@niieani Can you set @jlaustill in the right direction?

niieani commented 7 years ago

@EisenbergEffect I've been speaking with @JeroenVinke over the weekend, perhaps @jlaustill would like to work with Jeroen on this?

Sadly, I've got my hands full currently, however I'm still negotiating the potential sponsoring of my time to get this feature done.

@jlaustill After reading through this issue and looking here, what are your questions regarding how to proceed? I'd be happy to answer them here, and it would be good if we do this publicly, since others can benefit too.

chulian1819 commented 7 years ago

will wait until this framework is isomorphic to give it a try, performance boost of ssr is a must

jlaustill commented 7 years ago

@niieani After looking this over and getting the example repo to work and then exploring other options I think I've decided that prerender is a better option hands down. SO much simpler and achieves the same end goal, at least for my needs. Is there any work being done on aurelia and prerender at all or is the goal just ssr?

JeroenVinke commented 7 years ago

@jlaustill SSR has the focus right now, but that doesn't mean we can't take a look at prerendering if there's a need for it, after we've added SSR.

stalniy commented 7 years ago

Probably phase #3 can be eliminated in case of some one uses HTTP2 and pushes clientside js together with index.html file

stalniy commented 7 years ago

Possible solution for step #5.

As far as I see the best option would be to provide global state object for all components and then somehow decide which where should be used. Also it means that first time app loads, Aurelia needs to setup all bindings but don't update DOM. I guess it should work out of the box because bindings updates DOM only if their respective values are changed, correct?

If so, it means that Aurelia should have a mechanism which allows to specify binding/component state for the whole component tree.

masoudtahmasebi93 commented 6 years ago

What's the state on this? I've a website running with Aurelia and the loading has become very annoying Can this feature be applied to existing applications too?

EisenbergEffect commented 6 years ago

It's almost ready for release. We've been working on the final bits of performance improvements and a particular router compatibility issue. We're hoping to have an official SSR release very soon. For load times, I recommend that you break up your app into multiple bundles and try to load only what is necessary at the start. You might find it helpful to break up the bundles by feature or by role.

AmitM30 commented 6 years ago

we too have four domains running on it (production) for almost a year now. After a lot of optimizations and hacks we, we are able to successfully load static pages quite fast (passes Lightbox 3G test comfortably most of the time), but completely dynamic pages take some time to load.

This would be an awesome feature, given it would be possible to integrate this to existing applications.

flieks commented 6 years ago

This is great news, so thanks for still working on this! Once it's released, i will modify my project to get better SEO. And probably get back into aurelia development for new stuff

AmitM30 commented 6 years ago

@niieani the ssr branch seems to be pretty stale. Is there a way I could start looking the code to make it work with my existing Aurelia implementation (it is based off skeletal navigation webpack).

niieani commented 6 years ago

@AmitM30 yeah, skeleton-navigation is not the place to look for the new SSR implementation. Please see the appropriate repos in the Aurelia organization and await a blog post.

AmitM30 commented 6 years ago

hey @niieani. Sorry but I was checking the repo as per an earlier comment from you: https://github.com/aurelia/skeleton-server-render/issues/1#issuecomment-276179940

I’ll wait

inmchfw commented 6 years ago

Have a look at this PR from @JeroenVinke : https://github.com/aurelia/skeleton-navigation/pull/871

behzad888 commented 6 years ago

+1

Alexander-Taran commented 6 years ago

kinda shipped?

can be closed?

EisenbergEffect commented 6 years ago

Closing this. Phases 4 and 5 can be separate issues.

vanderstack commented 6 years ago

Can you point me to the issues which will be tracking phase 4 or 5? I am trying to augment my aurelia project to use razor templates and would like to track the progress of this feature.

EisenbergEffect commented 6 years ago

Ooops! Must have gotten distracted and forgot to create them ;) Here they are: