While I personally think that having a separate NodeJS Express server for handling SSR is good solution it's not always possible to do so in every environment.
Therefore we can provide a simple and easily solution that enables Universal on any platform or framework.
Draft implementation: https://github.com/angular/universal/pull/999
Framework and Platform agnostic Angular Universal rendering.
npm install @nguniversal/socket-engine @nguniversal/common --save
const socketEngine = require('@nguniversal/socket-engine');
// * NOTE :: leave this as require() since this file is built Dynamically from webpack
const {AppServerModuleNgFactory, LAZY_MODULE_MAP} = require('./dist/server/main');
socketEngine.startSocketEngine(AppServerModuleNgFactory);
This will the socket engine which internally hosts a TCP Socket server.
The default port is 9090 and host of localhost
You may want to leave this as a plain .js file since it is so simple and to make deploying it easier, but it can be easily transpiled from Typescript.
Your client can be whatever language, framework or platform you like.
Aslong as it can connect to a TCP Socket (which all frameworks can) then you're good to go.
This example will use JS for simplicity
import * as net from 'net';
const client = net.createConnection(9090, 'localhost', () => {
const renderOptions = {id: 1, url: '/path',
document: '<app-root></app-root>'} as SocketEngineRenderOptions;
client.write(JSON.stringify(renderOptions));
});
client.on('data', data => {
const res = JSON.parse(data.toString()) as SocketEngineResponse;
server.close();
done();
});
Draft implementation: https://github.com/angular/universal/pull/1003
Another proposed implementation thats very similar to the above Socket Engine, but instead of using a TCP Socket as the transport it uses GRPC.
This will make consuming it much easier since we can provide the .proto file and you're good to go.
Feel free to discuss advantages of both implementations.
This is perfect! ECommerce are realy need this feature.
I think GRPC engine will be much more better than TCP.
@lionskape We're happy to hear why one might be better than the other.
We may also end up implementing both, since they're simply implementations of an Interface they're relatively easy to maintain
Hey @Toxicable thank you very much for this draft. After some thoughts this looks like a really interesting idea because all communication is done via TCP and no further language bindings are required to communicate with the renderer code (Like I did with J2V8 in my own solution). This allows a larger adoption, still Node.js is required (Maybe I just have to get rid of the idea to do it without Node.js at all).
A few questions:
Is there a way to consume the libraries? At the moment the PR is still failing. It would be great if there is a possibilitiy to consume them, so I can implement a Java solution in the next days.
Is there a way to stop the server or should we just terminate/kill the Node.js process executing the script?
Does ls-routes and the function createFactoryAndGetRoutes allow us to retrieve all routes including the lazy loaded root routes? That would be really helpful to handle routing in my Java middleware
What are your thoughts about cookies? Do you have some techniques in mind how to pass the session/cookies from language X to the TCP server and back?
Btw: I try to keep things simple, so I prefer TCP over gRPC. But I can also implement a Java gRPC version if you are interested.
Best,
Simon
@swaechter
Is there a way to consume the libraries?
Right now there's no way to consume the libs. However you can just copy paste it into your app (note you'll need to copy paste Common Engine aswell.
Is there a way to stop the server or should we just terminate/kill the Node.js process executing the script?
The function returns a handler which you can call server.stop()
Does ls-routes and the function createFactoryAndGetRoutes...
This was a mistake on my part, the ls-routes is in a separate PR, I accidentally put it into the socket-engine one.
However for that one, yes it can retrieve all routes, lazy and eager, although it's just lsRoutes the function createFactoryAndGetRoutes shouldn't be exposed as a public api.
What are your thoughts about cookies?
I havn't put any effort into cookies just yet, but that's definitely something we can add onto these new additions. Right now i'd just like to keep it simple and make sure it solves the problems that people have with Universal on other platforms.
still Node.js is required
It will really always be a requirement, sure other tools such as J2V8 allow you to get around it but simply using Nodejs is a much much simpler solution.
What's the ETA on this? Will there be documentation/examples?
@yanshuf0 It is our highest priority at the moment.
It's currently blocked on a few Bazel issues but once they're resolved then it shouldn't be far away.
It's hard to give a timeline since there's a bunch of factors that can throw that out the window, such as my avilablity, blockers, other release related issues.
Initially there will be a quick doc on how to get started just so we can get it out as fast as possible.
But we will add better examples and docs later on.
You can track them here
https://github.com/angular/universal/pull/1003
https://github.com/angular/universal/pull/999
When you ask for "when is it ready?" ask first "what could I do to make it quicker/better?"
@dherges ok?
@Toxicable So what is the status of the Java component of Universal?
@inunotaisho26
There wont be a Java specific component.
This proposal opens up generic transports for Angular Universal
Either one of these will require a small amount of code to talk to them on the Java side but it will be very minimal.
Take a look at this example here in Nodejs, the equivilent of this is what needs to be done in Java.
https://github.com/angular/universal/blob/ea6f7b13b70c40b55ce72bd549e2dfb56ca146db/modules/socket-engine/README.md#usage-client
Current status:
Socket Engine: This is mostly done, just requires a review.
GRPC Engine: Blocked on a bazel issue at the moment.
Hey @Toxicable, if you don't mind could you please give an example on how could I use the suggested solution. Sorry, I'm an Android developer that just side track into front-end dev to create an ad-landing for our app, so a lot of this stuff is still very new to me.
I got stuck at this step in the official tutorial as our backend is in Java/ Spring. I have a rough idea of putting the Usage Server section in your solution into the server.ts file and the Usage Client need to be translated into Java and should go into our backend side. Is that correct?
@vxhviet This is not ready yet, there is still work to be done before we can release this.
Hello @Toxicable. I think it's really nice if we can pass some pre-fetched data to the TCP server to avoid additional API requests or passing user's selected locale (like we usually do window._some_name = { some_json_data };). Or at least we can pass cookies to TCP server to deal with APIs that have authentication enabled.
Thanks.
@9you The TCP server will simply be running your application through platformServer.
So any sort of caching should be done through there, which is not at the TCP Server level or in the scope of this proposal.
How use @nguniversal/socket-engine with @nguniversal/module-map-ngfactory-loader?
Function startSocketEngine: doesn't provide Providers parameter.
How use
@nguniversal/socket-enginewith@nguniversal/module-map-ngfactory-loader?Function
startSocketEngine: doesn't provideProvidersparameter.
Have same issue
How use
@nguniversal/socket-enginewith@nguniversal/module-map-ngfactory-loader?
FunctionstartSocketEngine: doesn't provideProvidersparameter.Have same issue
Thanks to @nguniversal/common, I could implements thrift-engine by myself.
(why not use gRPC? because I use java server and gRPC has heavy dependencies for java).
Thanks to
@nguniversal/common, I could implementsthrift-engineby myself.
Impressive. But it may be not necessary because to solve this problem you need just simple add providers argument to the _engine_. Im already working on that pull request but I have some issues with a building application.
You can help fix this issues and _providers_ feature for socket-engine will be sooner.
@gosp see #1003
What do RenderOptions do? To get a template for a particular route, you just need pass the url parameter. And, moreover, you always need to pass the <app-root></app-root> value to the document parameter, otherwise there will be an error. And to send a GET request, you must pass it to the url parameter either (e.g. /details/12). So, the id parameter is also not clear for what.
So what exactly do these parameters do?
The id parameter is not used for rendering. It's used by the client to identify which request the content was rendered for. Since we're using bidirectional sockets here there's no request/response like with HTTP, therefore you need some identifier to figure out what response from the universal server correspondence to the request you just made
@Toxicable so if I want to make a several request at the same session I must define a several id accordingly, is it correct?
And what does the document parameter?
Hmm... Has anyone used something like https://github.com/zeit/pkg to package whole node + app with dependencies into one binary?
Binary compile targets:
Hi,
I want to know if there is a solution to get the cookies server side. How can I achieve this using this lib ?
Thank you.
really need this feature (or an implementation for Universal PHP)
When will this be released?
Hello can someone provide some example of how this should be used with php backend?
Can the team please provide a tentative date for this release, that would help us wait on this if it isn't too far away from now. Thanks!
@vinay-akkipet I'd hate to be negative but I think they are focusing on angular 9 and ivy
@tayambamwanza Yes, we understand that. But Angular 9.0 (with full Ivy support) and 9.1 were already released
@sergey-morenets Lol not at the time that I posted the comment, 13 January.
@nguniversal/socket-engine and @nguniversal/common have been released throughout versions 6.0.0-9.1.0. Is anything missing?
@LayZeeDK That's fine. Do we already have socket-engine integration with Java/Spring Boot?
@LayZeeDK That's fine. Do we already have socket-engine integration with Java/Spring Boot?
I haven't tried out any of these releases, but if this proposal has been implemented as part of them, we just need to spin up the socket engine and connect to it through a TCP socket as described by OP.
@Toxicable , Can you please explain the flow and high level logic of your implementation. I am new to Angular and as I can understand from the code, the agnostic platform (Python, Java, php etc) is creating a conection to port 9090 of Node API server passing the SocketEngineRenderOptions and is returning the SocketEngineResponse, which is the prerendered page to Angular which will then render it on the Browser. Is it right?
Also I want to understand that whether Node will still be needed in backend to make this work and therefore will there be a need of Node server once we deploy it into production.
And if the above client and server side code works, can you please provide some documentation? Thanks
Most helpful comment
When you ask for "when is it ready?" ask first "what could I do to make it quicker/better?"