rx-angular / rx-angular

Reactive Extensions for Angular.
https://www.rx-angular.io/
MIT License
1.89k stars 193 forks source link

ISR Angular 17 not working #1647

Closed SkyZeroZx closed 7 months ago

SkyZeroZx commented 10 months ago

Today update my aplication to Angular 17 with ISR and use currently Angular SSR ( Previous Angular Universal ) , the caching of ISR not work and not show the comment in the HTML (by default use in memory or custom ) or register in Redis ( i use a custom handler)

image

My server.ts file , and the end of file add the ISR , but the documentation currently not show the new configurations of Angular SSR in Angular 17 , possible the error is for commonEngine replace the previous use with Angular is different.

` export function app(): express.Express { const server = express(); const distFolder = join(process.cwd(), 'dist/apps/MY_FOLDER/browser'); const indexHtml = existsSync(join(distFolder, 'index.original.html')) ? join(distFolder, 'index.original.html') : join(distFolder, 'index.html');

const redisCacheHandler = new RedisCacheHandler({
    host: env['CACHE_HOST'] || '',
    name: env['CACHE_NAME'] || '',
    port: Number(env['CACHE_PORT']),
    ttl: Number(env['CACHE_TTL']),
    username: env['CACHE_USERNAME'] || '',
    password: env['CACHE_PASSWORD'] || ''
});

const isr = new ISRHandler({
    indexHtml,
    cache: redisCacheHandler,
    buildId: environment.buildTimestamp.toString(),
    invalidateSecretToken: env['CACHE_REVALIDATE_SECRET_TOKEN'] || '',
    enableLogging: isDevMode()
});

const commonEngine = new CommonEngine();

server.set('view engine', 'html');
server.set('views', distFolder);

// Example Express Rest API endpoints
// server.get('/api/**', (req, res) => { });
// Serve static files from /browser
server.get(
    '*.*',
    express.static(distFolder, {
        maxAge: '1y'
    })
);

// All regular routes use the Angular engine
server.get('*', (req, res, next) => {
    const { protocol, originalUrl, baseUrl, headers } = req;

    commonEngine
        .render({
            bootstrap,
            documentFilePath: indexHtml,
            url: `${protocol}://${headers.host}${originalUrl}`,
            publicPath: distFolder,
            providers: [{ provide: APP_BASE_HREF, useValue: baseUrl }]
        })
        .then((html) => res.send(html))
        .catch((err) => next(err));
});

server.get(
    '*',
    async (req, res, next) => await isr.serveFromCache(req, res, next),
    async (req, res, next) => await isr.render(req, res, next)
);

return server;

} `

Environment

Angular CLI: 17.0.1 Node: 18.17.1 OS: win32 x64

Package Version

"@angular/animations": "17.0.1", "@angular/cdk": "17.0.0", "@angular/common": "17.0.1", "@angular/compiler": "17.0.1", "@angular/core": "17.0.1", "@angular/forms": "17.0.1", "@angular/platform-browser": "17.0.1", "@angular/platform-browser-dynamic": "17.0.1", "@angular/platform-server": "17.0.1", "@angular/router": "17.0.1", "@angular/service-worker": "17.0.1", "@angular/ssr": "17.0.0", "rxjs": "^7.8.1", "typescript": "5.2.2"

eneajaho commented 9 months ago

Hello @SkyZeroZx This is a known issue. Because in v17, Angular changed ng serve to not use the server.ts, so it's going to be hard to debug ISR locally.

The other issue is, the changed structure of the server.ts file.

If you use the v16 style, everything should still just work.

If you just added SSR in v17, there's no support for that yet, but we are working on it!

Should come later this year!

htrex commented 9 months ago

If you use the v16 style, everything should still just work.

could you please explain what do you mean with "use v16 style" ?

jginorio commented 9 months ago

Hello!

I stumbled upon this issue while experiencing some difficulties with Angular 17 too. Upon reviewing your code, it seems that the problem persists because you still have:


// All regular routes use the Angular engine
server.get('*', (req, res, next) => {
    const { protocol, originalUrl, baseUrl, headers } = req;

    commonEngine
        .render({
            bootstrap,
            documentFilePath: indexHtml,
            url: `${protocol}://${headers.host}${originalUrl}`,
            publicPath: distFolder,
            providers: [{ provide: APP_BASE_HREF, useValue: baseUrl }]
        })
        .then((html) => res.send(html))
        .catch((err) => next(err));
});

You are supposed to swap out that code with this one:

    server.get(
        '*',
        // Serve page if it exists in cache
        async (req, res, next) => await isr.serveFromCache(req, res, next),
        // Server side render the page and add to cache if needed
        async (req, res, next) => await isr.render(req, res, next)
    );

My issue is that as soon as I do this I get the following error:

Error: Cannot find module 'html'
    at require (./node_modules/express/lib/%20sync:2:1)
    at View (./node_modules/express/lib/view.js:81:14)
    at render (./node_modules/express/lib/application.js:587:12)
    at render (./node_modules/express/lib/response.js:1039:7)
    at executor (./node_modules/@rx-angular/isr/fesm2022/rx-angular-isr-server.mjs:468:13)
    at constructor (./node_modules/zone.js/fesm2015/zone-node.js:1342:21)
    at <anonymous> (./node_modules/@rx-angular/isr/fesm2022/rx-angular-isr-server.mjs:464:12)
    at Generator.next (<anonymous>)
    at asyncGeneratorStep (./node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js:3:1)
    at _next (./node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js:22:1) {
  code: 'MODULE_NOT_FOUND'
}
eneajaho commented 9 months ago

There's an issue with Angular Local Dev Server that runs SSR by default inside the vite dev server and doesn't use the server.ts, so we cannot debug anything when it comes to things we do in server.ts file (adding isr for example).

So, currently, I'm looking at how this issue get resolved, so we can make the right decision when it comes to designing a new API interface for the library.

https://github.com/angular/angular-cli/issues/26323

rdesimone commented 8 months ago

There's an issue with Angular Local Dev Server that runs SSR by default inside the vite dev server and doesn't use the server.ts, so we cannot debug anything when it comes to things we do in server.ts file (adding isr for example).

IMO, this happens also with a production build.

Error: Cannot find module 'html'
    at webpackEmptyContext (/dist/server/main.js:1:1529692)
    at new View (/dist/server/main.js:1:720938)
    at app.render (/dist/server/main.js:1:687515)
    at res.render (/dist/server/main.js:1:706098)
    at /dist/server/main.js:1:4827143
    at new ZoneAwarePromise (/dist/server/main.js:1:1506743)
    at /dist/server/main.js:1:4827006
    at Generator.next (<anonymous>)
    at asyncGeneratorStep (/dist/server/main.js:1:2806921)
    at _next (/dist/server/main.js:1:2807225) {
  code: 'MODULE_NOT_FOUND'

Any idea how to make ISR work with Angular 17 SSR at least in production?

Thanks!

rdesimone commented 8 months ago

It seems to work when forcing the installation of @nguniversal/express-engine (16.2.0).

Not sure what we loose when not using the new CommonEngine.

jasonrichdarmawan commented 8 months ago

Hi, I am new to both Angular 17 and @rx-angular/isr.

Should we downgrade @nguniversal/express-engine to v16 if we want to use @rx-angular/isr for now?

=== TL:DR

The reason of why it is better to downgrade @nguniversal/express-engine to v16 instead of Angular to v16.

The requirements:

  1. Mobile UX flow is navigate to the next component.
  2. Desktop UX flow is scroll to the next component.

To avoid issue of the shared link is broken, we do not use route to lazy load component, i.e.:

  1. checkout/slot-and-tockets
  2. checkout/your-details
  3. checkout/payment

The use case if we use route to lazy load component:

  1. user A (mobile user) share the link to his desktop or maybe to user B (desktop user)
  2. he / user B opened the link on his desktop, the link is broken.

The current solution is to use custom render to simulate scroll or navigate to the next component. This introduces new problem, the feature became too big because nothing is lazy loaded.

Angular 17 introduced the @defer syntax which the value is too good to pass up.

ngAl-13 commented 7 months ago

Greetings, our team currently employs ISR with Angular version 16 in our production environment. We are considering upgrading to Angular version 17 to leverage its enhanced features. Could you please confirm if ISR is fully compatible with Angular version 17, allowing us to take full advantage of its capabilities? Your response would be greatly appreciated. Thank you.

eneajaho commented 7 months ago

Hello, I've been working on adding support for the new CommonEngine and new standalone bootstrap API-s (the changes internally at the library are not much, just the public API now supports both old and the new way). https://github.com/rx-angular/rx-angular/pull/1680

Serving using ng serve still won't use the server.ts file so we will have to fallback to building/watching and serving using node manually instead of having only one command (checkout the linked issue above).

I also created a demo app in the repository to test out some use-cases and it looks to work fine.

After some more polishing, I'm looking forward to have a new release later this week.

Thanks for your patience.

eneajaho commented 7 months ago

Hello, The new released version 17.1.0 includes the fix for the new application builder, please try it and let me know if everything is working fine.

Feel free to report any bugs you may encounter.

Also, because in v17 the dev server doesn't use the server.ts file, you can build and serve the node server in parallel -> more info here.

Thanks for your patience.

smartsuhani commented 7 months ago

I'm facing strange issue while working with FileSystemCacheHandler, in this process only first route is cached properly, Both components contains exact same code, which route is hit first is cached well with firebase data calls, after that no other routes are cached, Is someone else also facing the same thing? code for both components are same as below.

image

this is the cached file with data that was cached in the browser/cached/__home.html, this was the first component route that I hit, image

Now this is the second cached file without data that I hit after the /home.

image

and this is how I display in html for both the components,

image

Any help regarding this would be really appreciated.

slemont3 commented 4 months ago

Hi @eneajaho

Thanks for adding support for the Common Engine, that's great! I'm trying to implement ISR in my Angular v17 app based on the example from your ssr-isr code. However, I can't get it to work and would like to debug locally whether the caching actually works or not. Alas, I have not been successful. It might be very trivial but any tip would be highly appreciated.

I'm running my testing Angular app locally as described here: node dist/angular17/server/server.mjs