This repository was archived by the owner on Apr 12, 2024. It is now read-only.
This repository was archived by the owner on Apr 12, 2024. It is now read-only.
Server side rendering discussion #2104
Closed
Description
I would like to create a module that will make server-side rendering in node.js possible. I've done this before in my own project and wanted to discuss technical details.
So, the goals of the module:
- Make server return fully rendered html on first request, then move to client side rendering seamlessly.
- Support html5 routing defined through $routeProvider on the server.
- As little changes to client-only rendering as possible.
How do I want to do that:
- Module will be a Connect/Express middleware that you can app.use().
- Use jsdom to create & work with DOM.
- To enable client-side rendering, developer will need to provide all html code as templates and use only
<ng-include>
and<ng-view>
in main html file. - On request, a new DOM is created and these
<ng-include>
-s are filled with rendered html. When ready (see below), the full DOM is serialized and sent to the browser (or crawler). In browser, the contents of<ng-include>
-s are discarded and re-rendered, creating all services and controllers, binding all needed event handlers. - When rendering on server, $http requests are re-routed to use the same server.
- If $routeProvider didn't match anything, the middleware will yield back to Express to serve later middleware or a 404 page.
Problems to solve:
- jsdom will need to be extended with sufficient userAgent and location/history APIs.
- The 'page ready' event is something to think about. I could use the $browser.notifyWhenNoOutstandingRequests() internal API, but maybe it could be better to introduce a $ready event on $rootScope.
- I'll need a way to intercept angular bootstrapping to be able to catch this 'page ready' event. It is currently done in ngScenario, but I think it could be better (for example, it doesn't support asynchronous bootstrapping).
- If we find a way to cleanly intercept angular bootstrapping on the page, we could have a single angular codebase residing in node process, serving all pages by just creating injectors. This should make page serving performance comparable to more traditional template-based servers.
- $routeProvider will need to be extended to provide an event when no routes are matched. Currently it's an
otherwise
clause which usually redirects to base, but in server environment it's bad practice. Preferably even on the client side if a route is unknown, we should redirect the browser to new url, as the server can have something else there (statics, etc), or 404 page. - It would be nice to cache all $http requests that are done on the server, and package them together with html, so that first render in browser would not ask for the same information again.
- I don't know how to test this whole endeavor. I can make e2e and unit tests to prove that jsdom is nice behaving browser, but I'm not sure what to do about ensuring that the browser will always get correct state when served with this method.
So, what do you think? Is it viable? Did you plan to do something similar?