{"id":19479217,"url":"https://github.com/pmb0/nestjs-tsx-views","last_synced_at":"2025-07-24T10:06:51.274Z","repository":{"id":37027676,"uuid":"321074231","full_name":"pmb0/nestjs-tsx-views","owner":"pmb0","description":"Server-side JSX/TSX rendering for your NestJS application","archived":false,"fork":false,"pushed_at":"2025-07-22T04:08:35.000Z","size":1436,"stargazers_count":28,"open_issues_count":14,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-07-22T06:39:00.266Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","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/pmb0.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"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":"2020-12-13T13:41:39.000Z","updated_at":"2025-02-24T07:45:58.000Z","dependencies_parsed_at":"2023-11-08T05:39:46.317Z","dependency_job_id":"3f9dec59-6fca-41b6-be81-c6b2531a2750","html_url":"https://github.com/pmb0/nestjs-tsx-views","commit_stats":{"total_commits":216,"total_committers":3,"mean_commits":72.0,"dds":0.2685185185185185,"last_synced_commit":"dca9636b781c792a755f0c47e48d1a034fd194a2"},"previous_names":[],"tags_count":17,"template":false,"template_full_name":null,"purl":"pkg:github/pmb0/nestjs-tsx-views","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pmb0%2Fnestjs-tsx-views","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pmb0%2Fnestjs-tsx-views/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pmb0%2Fnestjs-tsx-views/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pmb0%2Fnestjs-tsx-views/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pmb0","download_url":"https://codeload.github.com/pmb0/nestjs-tsx-views/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pmb0%2Fnestjs-tsx-views/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266823659,"owners_count":23990051,"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","status":"online","status_checked_at":"2025-07-24T02:00:09.469Z","response_time":99,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":[],"created_at":"2024-11-10T19:53:22.944Z","updated_at":"2025-07-24T10:06:51.247Z","avatar_url":"https://github.com/pmb0.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003ch1\u003enestjs-tsx-views\u003c/h1\u003e\n  \u003ca href=\"https://www.npmjs.com/package/nestjs-tsx-views\"\u003e\n    \u003cimg src=\"https://badge.fury.io/js/nestjs-tsx-views.svg\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://coveralls.io/r/pmb0/nestjs-tsx-views?branch=master\"\u003e\n    \u003cimg src=\"https://img.shields.io/coveralls/pmb0/nestjs-tsx-views/master.svg\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/pmb0/nestjs-tsx-views/actions?query=workflow%3ATests\"\u003e\n    \u003cimg src=\"https://github.com/pmb0/nestjs-tsx-views/workflows/Tests/badge.svg\"\u003e\n  \u003c/a\u003e\n  \u003cp\u003e\n    React SSR module for \u003ca href=\"https://docs.nestjs.com/techniques/mvc\"\u003eNestJS MVC\u003c/a\u003e\n  \u003c/p\u003e\n\u003c/div\u003e\n\n# Example\n\nController:\n\n```ts\nimport { Controller, Get, Render } from \"@nestjs/common\";\nimport { MyViewProps } from \"./views/my-view\";\n\n@Controller()\nexport class AppController {\n  @Get()\n  @Render(\"my-view\")\n  index(): MyViewProps {\n    return { name: \"world\" };\n  }\n}\n```\n\n`views/my-view.tsx`:\n\n```tsx\nimport React, { ReactElement } from \"react\";\nimport { MainLayout } from \"./layouts/main\";\n\nexport interface MyViewProps {\n  name: string;\n  title: string;\n}\n\nconst MyView = ({ name, ...props }: MyViewProps): ReactElement =\u003e (\n  \u003cdiv\u003eHello {name}\u003c/div\u003e\n);\n\nexport default MyView;\n```\n\n# Highlights \u003c!-- omit in toc --\u003e\n\n- Fast, since the JSX/TSX files do not have to be transpiled on-the-fly with every request\n- Separate NestJS modules can use their own views directories (see [multi module example](https://github.com/pmb0/nestjs-tsx-views/blob/master/example/multiple-modules))\n- Works with compiled files (`.js` / `node`) and uncompiled files (`.tsx` / `ts-node`, `ts-jest`, ...)\n- Provides React contexts\n- Supports execution of GraphQL queries from JSX components\n\n# Table of contents \u003c!-- omit in toc --\u003e\n\n- [Example](#example)\n- [Usage](#usage)\n  - [Synchronous configuration](#synchronous-configuration)\n  - [Asynchronous configuration](#asynchronous-configuration)\n  - [React Context](#react-context)\n  - [GraphQL](#graphql)\n  - [Configuration](#configuration)\n- [License](#license)\n\n# Usage\n\n```sh\n$ npm install --save nestjs-tsx-views\n```\n\nImport the module with `TsxViewsModule.register(...)` or `TsxViewsModule.registerAsync(...)`.\n\n## Synchronous configuration\n\nUse `TsxViewsModule.register()`. Available options are described in the [TsxViewsModuleOptions interface](#configuration).\n\n```ts\n@Module({\n  imports: [\n    TsxViewsModule.register({\n      viewsDirectory: resolve(__dirname, \"./views\"),\n      prettify: true,\n      forRoutes: [AppController],\n    }),\n  ],\n})\nexport class MyModule {}\n```\n\n## Asynchronous configuration\n\nIf you want to use retrieve you [TSX views options](#configuration) dynamically, use `TsxViewsModule.registerAsync()`. Use `useFactory` and `inject` to import your dependencies. Example using the `ConfigService`:\n\n```ts\n@Module({\n  imports: [\n    TsxViewsModule.registerAsync({\n      useFactory: (config: ConfigService) =\u003e ({\n        viewsDirectory: resolve(__dirname, './views'),\n        prettify: config.get('PRETTIFY_HTML'\n        )\n        forRoutes: [AppController],\n      }),\n      inject: [ConfigService],\n    }),\n  ],\n})\nexport class MyModule {}\n```\n\n## React Context\n\n1. Define a React context:\n\n```tsx\nimport { createContext } from 'react'\n\nexport interface MyContextProps {\n  name: string\n}\n\nexport const MyContext = createContext\u003cMyContextProps | undefined\u003e\n```\n\n2. Set the context in your controller (or provider):\n\n```ts\n@Controller()\nexport class AppController {\n  constructor(private readonly ssr: TsxViewsService) {}\n\n  @Get()\n  @Render(\"my-view\")\n  index() {\n    this.#ssr.addContext(MyContext, { name: \"My context data\" });\n\n    return {};\n  }\n}\n```\n\n3. Use it somewhere in your component:\n\n```tsx\nimport { useContext } from \"react\";\nimport { MyContext } from \"./my-context\";\n\nexport function MyComponent() {\n  const { name } = useContext(MyContext);\n  return \u003cspan\u003eHallo, {name}!\u003c/span\u003e;\n}\n```\n\n## GraphQL\n\nThis module supports the execution of GraphQL queries from the TSX template. For this purpose `graphql`, `@apollo/client` and `cross-fetch` have to be installed separately:\n\n```sh\n$ npm install --save @apollo/client cross-fetch graphql\n```\n\nSee `example/graphql/app.module.ts` for a working example of how to configure the NestJS module. View example:\n\n```ts\n// example/graphql/views/my-view.tsx\n\nexport interface Film {\n  id: string;\n  title: string;\n  releaseDate: string;\n}\n\nexport interface AllFilms {\n  allFilms: {\n    films: Film[];\n  };\n}\n\nconst MY_QUERY = gql`\n  query AllFilms {\n    allFilms {\n      films {\n        id\n        title\n        releaseDate\n      }\n    }\n  }\n`;\n\nexport interface MyViewProps {\n  name: string;\n  title: string;\n}\n\nconst MyView = (props: MyViewProps): ReactElement =\u003e {\n  const { data, error } = useQuery\u003cAllFilms\u003e(MY_QUERY);\n\n  if (error) {\n    throw error;\n  }\n\n  return (\n    \u003cMainLayout {...props}\u003e\n      \u003ch2\u003eFilms:\u003c/h2\u003e\n      {data?.allFilms.films.map((film) =\u003e (\n        \u003cul key={film.id}\u003e\n          {film.title} ({new Date(film.releaseDate).getFullYear()})\n        \u003c/ul\u003e\n      ))}\n    \u003c/MainLayout\u003e\n  );\n};\n\nexport default MyView;\n```\n\n## Configuration\n\nnestjs-tsx-views can be configured with the following options:\n\n```ts\nexport interface TsxViewsModuleOptions extends ReactViewsOptions {\n  /**\n   * The directory where your views (`.tsx` files) are stored. Must be\n   * specified.\n   */\n  viewsDirectory: string;\n\n  /**\n   * [Doctype](https://developer.mozilla.org/en-US/docs/Glossary/Doctype) to\n   * be used. */\n  doctype?: string;\n\n  /**\n   * If activated, the generated HTML string is formatted using\n   * [prettier](https://github.com/prettier/prettier)\n   */\n  prettify?: boolean;\n\n  /**\n   * With this optional function the rendered HTML document can be modified. For\n   * this purpose a function must be defined which gets the HTML `string` as\n   * argument. The function returns a modified version of the HTML string as\n   * `string`.\n   */\n  transform?: (html: string) =\u003e string | Promise\u003cstring\u003e;\n\n  /**\n   * Excludes routes from the currently processed middleware.\n   *\n   * @param {(string | RouteInfo)[]} routes\n   * @returns {MiddlewareConfigProxy}\n   */\n  exclude?: (string | RouteInfo)[];\n\n  /**\n   * Attaches passed either routes or controllers to the currently configured middleware.\n   * If you pass a class, Nest would attach middleware to every path defined within this controller.\n   *\n   * @param {(string | Type | RouteInfo)[]} routes\n   * @returns {MiddlewareConsumer}\n   */\n  forRoutes?: (string | Type\u003cController\u003e | RouteInfo)[];\n}\n```\n\n# License\n\nnestjs-tsx-views is distributed under the MIT license. [See LICENSE](./LICENSE) for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpmb0%2Fnestjs-tsx-views","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpmb0%2Fnestjs-tsx-views","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpmb0%2Fnestjs-tsx-views/lists"}