{"id":13580544,"url":"https://github.com/nestjs/ng-universal","last_synced_at":"2025-05-15T16:03:53.144Z","repository":{"id":39635819,"uuid":"149779462","full_name":"nestjs/ng-universal","owner":"nestjs","description":"Angular Universal module for Nest framework (node.js) 🌷","archived":false,"fork":false,"pushed_at":"2025-05-06T00:21:37.000Z","size":3246,"stargazers_count":443,"open_issues_count":26,"forks_count":68,"subscribers_count":10,"default_branch":"master","last_synced_at":"2025-05-06T01:27:12.725Z","etag":null,"topics":["angular","angular-universal","nest","nestjs","nodejs","server-side-rendering","typescript"],"latest_commit_sha":null,"homepage":"https://nestjs.com","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nestjs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2018-09-21T15:05:13.000Z","updated_at":"2025-04-04T04:27:30.000Z","dependencies_parsed_at":"2024-03-16T12:03:28.423Z","dependency_job_id":"1846374b-dd05-4d07-8f96-899b25c22502","html_url":"https://github.com/nestjs/ng-universal","commit_stats":{"total_commits":1022,"total_committers":26,"mean_commits":39.30769230769231,"dds":0.3405088062622309,"last_synced_commit":"0334084783fa9ad0ea41da2bcebc99004e58fcbb"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nestjs%2Fng-universal","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nestjs%2Fng-universal/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nestjs%2Fng-universal/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nestjs%2Fng-universal/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nestjs","download_url":"https://codeload.github.com/nestjs/ng-universal/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254374402,"owners_count":22060609,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["angular","angular-universal","nest","nestjs","nodejs","server-side-rendering","typescript"],"created_at":"2024-08-01T15:01:52.888Z","updated_at":"2025-05-15T16:03:53.089Z","avatar_url":"https://github.com/nestjs.png","language":"TypeScript","readme":"\u003cp align=\"center\"\u003e\n  \u003ca href=\"http://nestjs.com/\" target=\"blank\"\u003e\u003cimg src=\"https://nestjs.com/img/logo_text.svg\" width=\"320\" alt=\"Nest Logo\" /\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n[travis-image]: https://api.travis-ci.org/nestjs/nest.svg?branch=master\n[travis-url]: https://travis-ci.org/nestjs/nest\n[linux-image]: https://img.shields.io/travis/nestjs/nest/master.svg?label=linux\n[linux-url]: https://travis-ci.org/nestjs/nest\n\n  \u003cp align=\"center\"\u003eA progressive \u003ca href=\"http://nodejs.org\" target=\"blank\"\u003eNode.js\u003c/a\u003e framework for building efficient and scalable server-side applications.\u003c/p\u003e\n    \u003cp align=\"center\"\u003e\n\u003ca href=\"https://www.npmjs.com/~nestjscore\"\u003e\u003cimg src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /\u003e\u003c/a\u003e\n\u003ca href=\"https://www.npmjs.com/~nestjscore\"\u003e\u003cimg src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /\u003e\u003c/a\u003e\n\u003ca href=\"https://www.npmjs.com/~nestjscore\"\u003e\u003cimg src=\"https://img.shields.io/npm/dm/@nestjs/core.svg\" alt=\"NPM Downloads\" /\u003e\u003c/a\u003e\n\u003ca href=\"https://coveralls.io/github/nestjs/nest?branch=master\"\u003e\u003cimg src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#5\" alt=\"Coverage\" /\u003e\u003c/a\u003e\n\u003ca href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"\u003e\u003cimg src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/nest#backer\"\u003e\u003cimg src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/nest#sponsor\"\u003e\u003cimg src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /\u003e\u003c/a\u003e\n  \u003ca href=\"https://paypal.me/kamilmysliwiec\"\u003e\u003cimg src=\"https://img.shields.io/badge/Donate-PayPal-dc3d53.svg\"/\u003e\u003c/a\u003e\n  \u003ca href=\"https://twitter.com/nestframework\"\u003e\u003cimg src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social\u0026label=Follow\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n  \u003c!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)--\u003e\n\n## Description\n\nAngular [Universal](https://github.com/angular/universal) module for [Nest](https://github.com/nestjs/nest).\n\n## Installation\n\nUsing the Angular CLI:\n\n```bash\n$ ng add @nestjs/ng-universal\n```\n\nOr manually:\n\n```bash\n$ npm i @nestjs/ng-universal\n```\n\n## Example\n\nSee full example [here](https://github.com/kamilmysliwiec/universal-nest).\n\n## Usage\n\nIf you have installed the module manually, you need to import `AngularUniversalModule` in your Nest application.\n\n```typescript\nimport { Module } from '@nestjs/common';\nimport { join } from 'path';\nimport { AngularUniversalModule } from '@nestjs/ng-universal';\n\n@Module({\n  imports: [\n    AngularUniversalModule.forRoot({\n      bootstrap: AppServerModule,\n      viewsPath: join(process.cwd(), 'dist/{APP_NAME}/browser')\n    })\n  ]\n})\nexport class ApplicationModule {}\n```\n\n## API Spec\n\nThe `forRoot()` method takes an options object with a few useful properties.\n\n| Property            | Type                | Description                                                                |\n| ------------------- | ------------------- | -------------------------------------------------------------------------- |\n| `viewsPath`         | string              | The directory where the module should look for client bundle (Angular app) |\n| `bootstrap`         | Function            | Angular server module reference (`AppServerModule`).                       |\n| `templatePath`      | string?             | Path to index file (default: `{viewsPaths}/index.html`)                    |\n| `rootStaticPath`    | string?             | Static files root directory (default: `*.*`)                               |\n| `renderPath`        | string?             | Path to render Angular app (default: `*`)                                  |\n| `extraProviders`    | StaticProvider[]?   | The platform level providers for the current render request                |\n| `inlineCriticalCss` | boolean?            | Reduce render blocking requests by inlining critical CSS. (default: true)  |\n| `cache`             | boolean? \\| object? | Cache options, description below (default: `true`)                         |\n| `errorHandler`      | Function?           | Callback to be called in case of a rendering error                         |\n\n### Cache\n\n| Property       | Type               | Description                                                                    |\n| -------------- | ------------------ | ------------------------------------------------------------------------------ |\n| `expiresIn`    | number?            | Cache expiration in milliseconds (default: `60000`)                            |\n| `storage`      | CacheStorage?      | Interface for implementing custom cache storage (default: in memory)           |\n| `keyGenerator` | CacheKeyGenerator? | Interface for implementing custom cache key generation logic (default: by url) |\n\n```typescript\nAngularUniversalModule.forRoot({\n  bootstrap: AppServerModule,\n  viewsPath: join(process.cwd(), 'dist/{APP_NAME}/browser'),\n  cache: {\n    storage: new InMemoryCacheStorage(),\n    expiresIn: DEFAULT_CACHE_EXPIRATION_TIME,\n    keyGenerator: new CustomCacheKeyGenerator()\n  }\n});\n```\n\n### Example for CacheKeyGenerator:\n\n```typescript\nexport class CustomCacheKeyGenerator implements CacheKeyGenerator {\n  generateCacheKey(request: Request): string {\n    const md = new MobileDetect(request.headers['user-agent']);\n    const isMobile = md.mobile() ? 'mobile' : 'desktop';\n    return (request.hostname + request.originalUrl + isMobile).toLowerCase();\n  }\n}\n```\n\n## Request and Response Providers\n\nThis tool uses `@nguniversal/express-engine` and will properly provide access to the Express Request and Response objects in you Angular components. Note that tokens must be imported from the `@nestjs/ng-universal/tokens`, not `@nguniversal/express-engine/tokens`.\n\nThis is useful for things like setting the response code to 404 when your Angular router can't find a page (i.e. `path: '**'` in routing):\n\n```ts\nimport { Response } from 'express';\nimport { Component, Inject, Optional, PLATFORM_ID } from '@angular/core';\nimport { isPlatformServer } from '@angular/common';\nimport { RESPONSE } from '@nestjs/ng-universal/tokens';\n\n@Component({\n  selector: 'my-not-found',\n  templateUrl: './not-found.component.html',\n  styleUrls: ['./not-found.component.scss']\n})\nexport class NotFoundComponent {\n  constructor(\n    @Inject(PLATFORM_ID)\n    private readonly platformId: any,\n    @Optional()\n    @Inject(RESPONSE)\n    res: Response\n  ) {\n    // `res` is the express response, only available on the server\n    if (isPlatformServer(this.platformId)) {\n      res.status(404);\n    }\n  }\n}\n```\n\n## Custom Webpack\n\nIn some situations, it may be required to customize the `webpack` build while using `@nestjs/ng-universal`, especially when additional dependencies are included (that rely on native Node.js code).\n\nTo add a customizable `webpack` config to your project, it is recommended to install [@angular-builders/custom-webpack](https://www.npmjs.com/package/@angular-builders/custom-webpack) in the project and to set your builders appropriately.\n\n### Example Custom Webpack\n```typescript\n// webpack.config.ts\nimport { Configuration, IgnorePlugin } from 'webpack'\nimport {\n  CustomWebpackBrowserSchema,\n  TargetOptions\n} from '@angular-builders/custom-webpack'\nimport nodeExternals from 'webpack-node-externals'\n\nexport default (\n  config: Configuration\n  _options: CustomWebpackBrowserSchema,\n  targetOptions: TargetOptions\n) =\u003e {\n  if (targetOptions.target === 'server') {\n    config.resolve?.extensions?.push('.mjs', '.graphql', '.gql')\n\n    config.module?.rules?.push({\n      test: /\\.mjs$/,\n      include: /node_modules/,\n      type: 'javascript/auto'\n    });\n\n    config.externalsPresets = { node: true }\n\n    (config.externals as Array\u003cany\u003e).push(\n      nodeExternals({ allowlist: [/^(?!(livereload|concurrently|fsevents)).*/]})\n    );\n\n    config.plugins?.push(\n      new IgnorePlugin({\n        checkResource: (resource: string) =\u003e {\n          const lazyImports = [\n            '@nestjs/microservices',\n            '@nestjs/microservices/microservices-module',\n            '@nestjs/websockets/socket-module',\n            'cache-manager',\n            'class-validator',\n            'class-transform',\n          ];\n\n          if (!lazyImpots.includes(resource)) {\n            return false;\n          }\n\n          try {\n            require.resolve(resource)\n          } catch (_err: any) {\n            return true;\n          }\n          return false;\n        }\n      })\n    );\n  }\n  return config;\n};\n\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://twitter.com/kammysliwiec)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n","funding_links":["https://opencollective.com/nest","https://paypal.me/kamilmysliwiec"],"categories":["TypeScript","Table of contents"],"sub_categories":["Angular"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnestjs%2Fng-universal","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnestjs%2Fng-universal","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnestjs%2Fng-universal/lists"}