D
D
Dasha Tsiklauri2017-07-15 15:34:19
Angular
Dasha Tsiklauri, 2017-07-15 15:34:19

SSR: what should be the principle of state caching in angular universal?

There is a web server on express, angular universal is washed down on it. It works in such a way that for each incoming server rendering request, it creates a new instance of ngModuleRef, bootstrap it, waits for the application to stabilize (isStable=true) and renders. The essence of the problem: the stores store data sets, requests that receive data from the API on the grid go for a long time (volumes ~ 2-3 mb), but could be reused as on the client, that is, download 1 time and then take it from the store (page 5 is rendered -6 sec). We started digging ngExpressEngine , reworked this piece of code:

const moduleRefPromise = setupOptions.aot ?
        platformServer(extraProviders).bootstrapModuleFactory(moduleFactory as NgModuleFactory<{}>) :
        platformDynamicServer(extraProviders).bootstrapModule(moduleFactory as Type<{}>);

      moduleRefPromise.then((moduleRef: NgModuleRef<{}>) => {
        handleModuleRef(moduleRef, callback);
      });

to one to reuse the module:
if (!moduleR) {
                const moduleRefPromise = setupOptions.aot ?
                    platformServer(extraProviders).bootstrapModuleFactory(<NgModuleFactory<{}>>moduleFactory) :
                    platformDynamicServer(extraProviders).bootstrapModule(<Type<{}>>moduleFactory);

                moduleRefPromise.then((moduleRef: NgModuleRef<{}>) => {
                    moduleR = moduleRef;
                    handleModuleRef(moduleR, callback, options.req, options.res);
                });
            } else {
                handleModuleRef(moduleR, callback, options.req, options.res);
            }

where moduleR is passed through the closure from the outer function. Removed moduleRef.destroy() inside handleModuleRef.
But now, with each subsequent request, the result of the very first one is returned. Is it possible to somehow "destabilize" the application or kick it with a different source url? Or how to correctly implement caching of an existing module? (on the extreme, you will have to raise a local cache proxy to api for heavy requests).

Answer the question

In order to leave comments, you need to log in

2 answer(s)
D
Dasha Tsiklauri, 2017-07-18
@dasha_programmist

Digging and debugging helped to come up with this handleModuleRef code

function handleModuleRef(moduleRef: NgModuleRef<{}>, callback: Function, req, res) {
    const state = moduleRef.injector.get(PlatformState);
    const appRef = moduleRef.injector.get(ApplicationRef);
    const router = appRef.components[0].instance.router;
    const zone = appRef.components[0].instance.zone;
    zone.run(() => {
        router.navigateByUrl(req.originalUrl);
    });
    appRef.isStable
        .filter((isStable: boolean) => isStable)
        .first()
        .subscribe((stable) => {
            const bootstrap = moduleRef.instance['ngOnBootstrap'];
            bootstrap && bootstrap();

            if (!res || !res.finished) callback(null, state.renderToString());
        });
}

We went into the handleModuleRef method and if everything is clear with the first request - the application is unstable (isStable=false), then with the subsequent ones it was not clear how to destabilize it in order to start the ChangeDetection cycle. As we know, ChangeDetection works from top to bottom in the hierarchy, that is, from the main component to all the underlying ones, that is, if we have N components in the application, then the complexity of such an operation is O (N). Thus, we can destabilize the application directly by providing a new URL for the router that we received from the main component. The trick is that isStable is essentially a property of the NgZone zone (which is one for the entire application) and we need to destabilize it. Therefore, the router code should be run inside zone.run(...). The application hawala a new route, the zone destabilizes and we wait until it becomes stable (that is, there will not be a single task in the queue inside the zone). Rendering. Profit!
Consequences:
1) similar to the browser - memory flows over time, it saves that everything is running in the docker and everything rises by itself;
2) a constant and not entirely predictable state of the entire application.
The rendering speed accelerated on average 2-3-4 times on different components in its own way.

O
ozknemoy, 2017-07-15
@ozknemoy

look here https://github.com/ozknemoy/a4 the meaning is that a global variable is stored in the html header (it is stuffed with requests to the database, everything is automatic), then it is read out by the service on the front. ngExpressEngine is also used. since when they have not yet filed it into a separate module

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question