• This repository has been archived on 15/Sep/2023
  • Stars
    star
    151
  • Rank 246,057 (Top 5 %)
  • Language
    TypeScript
  • License
    MIT License
  • Created over 2 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Incremental Static Regeneration for Angular

Incremental Static Regeneration for Angular

A library that enables Angular Universal applications to generate static pages at runtime and then update them incrementally on demand or on a schedule.

πŸ“° Documentation

πŸ“° ISR Blog post

Features

  • ⏰ Scheduled cache invalidation
  • ▢️ On-demand cache invalidation
  • πŸ”Œ Plugin based cache handlers
  • πŸ‘Œ No build changes required!
  • πŸ…°οΈ Supports Angular Universal
  • πŸ›‘οΈ NgModules & Standalone Compatible

How to use it?

  1. Install npm package
npm install ngx-isr
# or
yarn add ngx-isr
# or
pnpm add ngx-isr
  1. Initialize ISRHandler inside server.ts
const isr = new ISRHandler({
  indexHtml,
  invalidateSecretToken: 'MY_TOKEN', // replace with env secret key ex. process.env.REVALIDATE_SECRET_TOKEN
  enableLogging: !environment.production
});
  1. Add invalidation url handler
server.use(express.json());
server.post("/api/invalidate", async (req, res) => await isr.invalidate(req, res));
  1. Replace Angular default server side rendering with ISR rendering

Replace

server.get('*',
  (req, res) => {
    res.render(indexHtml, { req, providers: [{ provide: APP_BASE_HREF, useValue: req.baseUrl }] });
  }
);

with

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),
);

You can also pass providers to each of the ISRHandler methods.

server.get('*',
  ...
    async (req, res, next) => await isr.render(req, res, next, {
      providers: [
        { provide: APP_BASE_HREF, useValue: req.baseUrl }, // <-- Needs to be provided when passing providers
        { provide: CUSTOM_TOKEN, useValue: 'Hello from ISR' },
        CustomService
      ]
    }),
);

It is also possible to pass a modifyCachedHtml or modifyGeneratedHtml callbacks to the ISRHandler methods. These methods provide a way to modify the html served from cache or the html that is generated on the fly.

Important: Use these methods with caution as the logic written can increase the processing time.

server.get('*',
  // Serve page if it exists in cache
  async (req, res, next) => await isr.serveFromCache(req, res, next, {
    modifyCachedHtml: (req, cachedHtml) => {
        return `${cachedHtml}<!-- Hello, I'm a modification to the original cache! -->`;
    }
  }),
  // Server side render the page and add to cache if needed
  async (req, res, next) => await isr.render(req, res, next, {
    modifyGeneratedHtml: (req, html) => {
      return `${html}<!-- Hello, I'm modifying the generatedHtml before caching it! -->`
    }
  }),
);

ISRHandler provides APP_BASE_HREF by default. And if you want pass providers into the methods of ISRHandler, you will also have to provide APP_BASE_HREF token.

  1. Add revalidate key in route data

Example:

{
  path: "example",
  component: ExampleComponent,
  data: { revalidate: 5 },
}

NOTE: Routes that don't have revalidate key in data won't be handled by ISR. They will fallback to Angular default server side rendering pipeline.

  1. Register providers To register the ngx-isr providers, you can either import NgxIsrModule in your AppServerModule or provide provideISR in your AppServerModule providers.

Or, if you are in a standalone app, you can register the providers in your app.config.server.ts file.

  • Register using NgxIsrModule
import { NgxIsrModule } from 'ngx-isr/server'; // <-- Import module from library

@NgModule({
  imports: [
    ...
    NgxIsrModule.forRoot()  // <-- Use it in module imports
  ]
})
export class AppServerModule {}
  • Register using the provideISR function
import { provideISR } from 'ngx-isr/server';

@NgModule({
  providers: [
    provideISR() // <-- Use it in module providers
  ]
})
export class AppServerModule {}
  • Register using the provideISR function in standalone app
import { provideISR } from 'ngx-isr/server';

const serverConfig: ApplicationConfig = {
  providers: [
    provideServerRendering(),
    provideISR() // <-- Use it in config providers
  ],
};

When registering the providers, NgxIsrService will be initialized and will start to listen to route changes, only on the server side, so the browser bundle won't contain any extra code.

Changelog

Version 0.5.5

Features

  • feat: allow NgxIsrService to be used in application code without bringing the whole library in the browser bundle
  • feat: separate the library into secondary entry points for server and browser

BREAKING CHANGES:

Imports now should be done from ngx-isr/server and ngx-isr/browser instead of ngx-isr;

// Before
import { NgxIsrModule } from 'ngx-isr';

// After
import { NgxIsrModule } from 'ngx-isr/server';

// Before
import { provideISR } from 'ngx-isr';

// After
import { provideISR } from 'ngx-isr/server';

Things exported from ngx-isr/server:

  • NgxIsrModule
  • provideISR
  • ISRHandler
  • FileSystemCacheHandler and FileSystemCacheOptions

Things exported from ngx-isr/browser:

  • NgxIsrService

Things exported from ngx-isr/models:

  • CacheHandler
  • CacheISRConfig (renamed from ISROptions)
  • CacheData
  • INgxIsrService and NgxIsrState
  • ISRHandlerConfig
  • InvalidateConfig
  • RenderConfig
  • ServeFromCacheConfig
  • RouteISRConfig

Version 0.5.4

Features

  • feat: refactor FileSystem cache handler from scratch (fixes: #35)
  • fix: buildId can be null but also undefined, added a check for it

Version 0.5.3

Features

  • feat: Introduce RouteISRConfig interface for better type safety in route data

    How to use it?

    const routes: Rotues = [{
      path: 'home',
      component: HomeComponent,
      data: { revalidate: 0 } as RouteISRConfig // πŸ‘ˆ Add type to route data
    }];
  • feat: Added build id support

    What is it and why do we need it?

    The build id is a unique identifier that is generated for each build. It is used to invalidate the cache when a new build is deployed. So, when a new build is deployed, every page that will be requested will be server-rendered again and not served from the cache. This way, the users will always get the latest version of the application.

    Useful when you have an external cache handler like Redis.

    How to use it?

    To use it, you need to pass the build id to the ISRHandler constructor. Angular itself doesn't generate a build id. But we can generate it using the environment file. What we can do is to set field in the environment file called buildId and set it to: new Date().getTime(),.

    Ex. environment.ts:

    export const environment = {
      production: false,
      buildId: new Date().getTime() + '', // We need to convert it to string because the buildId is a string
    };

    This way we will have a unique build id for each build because the buildId will evaluated at build time. Then, we pass the build id to the ISRHandler constructor.

    Ex. server.ts:

    import { environment } from './src/environments/environment';
    
    const isr = new ISRHandler({
      .. other options
      buildId: environment.buildTimestamp // Pass the build id
    });
  • fix: Fixed a bug where the cache was not invalidated when the build id changed

Breaking changes:

  • ISROptions is being deprecated. Use CacheISRConfig instead.

Version 0.5.2

  • feat: Migrate repository to nx workspace
  • feat: Added provideISR provider function
  • chore: Update example RedisCacheHandler to use a prefix

License

MIT

More Repositories

1

point-of-sale-angular

Point of sale web application UI built with Angular.
TypeScript
82
star
2

ngx-libs

Angular Libraries Support lists community libs support for each Angular version
TypeScript
76
star
3

dating-client

A dating application built on top of Angular, NGRX, Bootstrap and RxJS.
TypeScript
37
star
4

dating-api

Dating app API built on top of .Net 5
C#
23
star
5

bms

Business Management System made with Laravel
PHP
16
star
6

cool-console

Angular library that displays cool messages in console.
TypeScript
15
star
7

observable-store

An observable store built with rxjs, ideal for small/medium projects.
TypeScript
14
star
8

point-of-sale-laravel

Point of Sale Laravel API application
PHP
13
star
9

ng-tauri

Angular and Tauri app
TypeScript
11
star
10

bcrypto

A text encyptor/decryptor using seed based encrypting and binary digits & React.js
JavaScript
10
star
11

angular-isr

Angular Incremental Static Regeneration POC
TypeScript
10
star
12

angular-state-crud

Angular CRUD implementation with different state management libraries
TypeScript
10
star
13

budget-tracker-api

A budget tracker API built with Laravel 6
PHP
10
star
14

sprout-music

A music player built with Angular 9 and (Electron coming soon)
TypeScript
7
star
15

price-box-ng

Price Box Component built with Angular 8
TypeScript
7
star
16

taskman

A Task Manager built with Laravel and React.js
PHP
7
star
17

encrypt

A simple binary to char encryptor/decryptor made with JS
JavaScript
6
star
18

c

C Programming Exercises
C
5
star
19

dogify

A Google Chrome Extension that changes all images in a website into puppies.
JavaScript
5
star
20

logicminimization

Logic Minimization using table method, C Script
C
4
star
21

cms

Blog CMS built with PHP & MySQL (Not Secure)
CSS
4
star
22

hamming

A JS script for converting every binary code in Hamming Code
HTML
4
star
23

gallery-grid

A simple gallery site built with CSS Grid
CSS
4
star
24

isr-multiple-domains

HTML
3
star
25

doc-signer

Free PDF Signer
TypeScript
3
star
26

ngx-signal-experimental

Angular Signals Implementation experimental
TypeScript
3
star
27

face-recognition-reactjs

A face recognition app made with React.js and Clarifai Api
JavaScript
3
star
28

eneajaho

Readme
2
star
29

techfest-ionic

TypeScript
2
star
30

ToursApi

C#
2
star
31

rxjs-workshop

Angular project used for an internal RxJS workshop
TypeScript
1
star
32

angular-material-dashboard-setup

Dashboard built with Angular Material
TypeScript
1
star
33

just-angular

Just Angular website
TypeScript
1
star
34

universal-zoneless

TypeScript
1
star
35

test-migrations

Test migrations
TypeScript
1
star
36

itest-api

iTest backend application
C#
1
star
37

signals-crud

1
star