{"id":13781220,"url":"https://github.com/eidellev/inertiajs-adonisjs","last_synced_at":"2025-05-11T14:34:51.815Z","repository":{"id":37086337,"uuid":"316962591","full_name":"eidellev/inertiajs-adonisjs","owner":"eidellev","description":null,"archived":false,"fork":false,"pushed_at":"2023-08-01T17:24:47.000Z","size":3041,"stargazers_count":279,"open_issues_count":17,"forks_count":16,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-05-09T02:47:38.510Z","etag":null,"topics":["adonisjs","inertiajs","ssr","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/eidellev.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null},"funding":{"github":"eidellev"}},"created_at":"2020-11-29T13:55:49.000Z","updated_at":"2025-03-12T20:30:13.000Z","dependencies_parsed_at":"2024-01-15T04:07:22.270Z","dependency_job_id":"172e1545-678a-444f-9b31-c41dcaa1ce6e","html_url":"https://github.com/eidellev/inertiajs-adonisjs","commit_stats":{"total_commits":195,"total_committers":8,"mean_commits":24.375,"dds":"0.17948717948717952","last_synced_commit":"e6fee21567d08e659b038aa345994ab6caa4677a"},"previous_names":[],"tags_count":43,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eidellev%2Finertiajs-adonisjs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eidellev%2Finertiajs-adonisjs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eidellev%2Finertiajs-adonisjs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eidellev%2Finertiajs-adonisjs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/eidellev","download_url":"https://codeload.github.com/eidellev/inertiajs-adonisjs/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253580341,"owners_count":21930928,"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":["adonisjs","inertiajs","ssr","typescript"],"created_at":"2024-08-03T18:01:23.976Z","updated_at":"2025-05-11T14:34:51.403Z","avatar_url":"https://github.com/eidellev.png","language":"TypeScript","funding_links":["https://github.com/sponsors/eidellev"],"categories":["TypeScript","Packages","Adapters"],"sub_categories":["Server-side"],"readme":"# Inertia.js AdonisJS Provider\n\n![Typescript](https://img.shields.io/npm/types/typescript?style=for-the-badge)\n\u003ca href=\"https://adonisjs.com/\"\u003e\n\u003cimg src=\"https://img.shields.io/badge/%E2%96%B2%20adonis-v5-5a45ff?style=for-the-badge\"\u003e\n\u003c/a\u003e\n\u003ca href=\"https://prettier.io/\"\u003e\n\u003cimg alt=\"code style: prettier\" src=\"https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=for-the-badge\"\u003e\n\u003c/a\u003e\n\u003ca href=\"\"\u003e\n\u003ca href=\"https://www.npmjs.com/package/semantic-release\"\u003e\n\u003cimg src=\"https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg?style=for-the-badge\"/\u003e\n\u003c/a\u003e\n\n## What is this all about?\n\n[Inertia.js](https://inertiajs.com/) lets you quickly build modern single-page\nReact, Vue and Svelte apps using classic server-side routing and controllers.\n\n[AdonisJS](https://adonisjs.com/) is a fully featured web framework focused on\nproductivity and developer ergonomics.\n\n### Project goals\n\n- Feature parity with the official Inertia backend adapters\n- Full compatibility with all official client-side adapters\n- Easy setup\n- Quality documentation\n\n## Installation\n\n```shell\n# NPM\nnpm i @eidellev/inertia-adonisjs\n\n# or Yarn\nyarn add @eidellev/inertia-adonisjs\n```\n\n## Required AdonisJS libraries\n\nThis library depends on two `AdonisJS` core libraries: `@adonisjs/view` and `@adonisjs/session`.\nIf you started off with the `api` or `slim` project structure you will need to\ninstall these separately:\n\n```shell\n# NPM\nnpm i @adonisjs/view\nnpm i @adonisjs/session\n\n# or Yarn\nyarn add @adonisjs/view\nyarn add @adonisjs/session\n\n# Additionally, you will need to configure the packages:\nnode ace configure @adonisjs/view\nnode ace configure @adonisjs/session\n```\n\n## Setup\n\nYou can register the package, generate additional files and install additional\ndependencies by running:\n\n```shell\nnode ace configure @eidellev/inertia-adonisjs\n```\n\nInertia will query you on your preferences (e.g. which front-end framework you\nprefer and if you want server side rendering) and generate additional files.\n\n![Invoke example](invoke.gif 'node ace invoke @eidellev/inertia-adonisjs')\n\n### Configuration\n\nThe configuration for `inertia-adonisjs` is set in `/config/inertia.ts`:\n\n```typescript\nimport { InertiaConfig } from '@ioc:EidelLev/Inertia';\n\nexport const inertia: InertiaConfig = {\n  view: 'app',\n};\n```\n\n### Register inertia middleware\n\nAdd Inertia middleware to `start/kernel.ts`:\n\n```typescript\nServer.middleware.register([\n  () =\u003e import('@ioc:Adonis/Core/BodyParser'),\n  () =\u003e import('@ioc:EidelLev/Inertia/Middleware'),\n]);\n```\n\n## Making an Inertia Response\n\n```typescript\nexport default class UsersController {\n  public async index({ inertia, request }: HttpContextContract) {\n    const users = await User.all();\n\n    return inertia.render('Users/IndexPage', { users });\n  }\n}\n```\n\n## Making lazy Inertia Response\n\nLazy responses are useful when you want to render a page without some data that should be loaded initially.\n\n```typescript\nimport Inertia from '@ioc:EidelLev/Inertia';\n\nexport default class UsersController {\n  public async index({ inertia, request }: HttpContextContract) {\n    const users = await User.all();\n\n    return inertia.render('Users/IndexPage', {\n      users,\n      lazyProp: Inertia.lazy(() =\u003e {\n        return { lazy: 'too lazy' };\n      }),\n    });\n  }\n}\n```\n\nThe data will be loaded on demand by the explicit Inertia visit with option\n\n```typescript\n{\n  only: ['lazyProp'];\n}\n```\n\n## Root template data\n\nThere are situations where you may want to access your prop data in your root\nEdge template. For example, you may want to add a meta description tag,\nTwitter card meta tags, or Facebook Open Graph meta tags.\n\n```blade\n\u003cmeta name=\"twitter:title\" content=\"{{ page.title }}\"\u003e\n```\n\nSometimes you may even want to provide data that will not be sent to your\nJavaScript component.\n\n```typescript\nreturn inertia.render('Users/IndexPage', { users }, {  metadata: '...' : '...' });\n```\n\n## Shared data\n\nSometimes you need to access certain data on numerous pages within your\napplication. For example, a common use-case for this is showing the current user\nin the site header. Passing this data manually in each response isn't practical.\nIn these situations shared data can be useful.\n\nIn order to add shared props, edit `start/inertia.ts`:\n\n```typescript\nimport Inertia from '@ioc:EidelLev/Inertia';\n\nInertia.share({\n  errors: (ctx) =\u003e {\n    return ctx.session.flashMessages.get('errors');\n  },\n  // Add more shared props here\n});\n```\n\n### Sharing route params\n\nTraditionally in Adonis, we have access to the context instance eg. params\ninside view (.edge) that we can use to help build our dynamic routes.\nBut with inertia, we lose access to the context instance entirely.\n\nWe can overcome this limitation by passing the context\ninstance as a shared data prop:\n\n```typescript\n// start/inertia.ts\nimport Inertia from '@ioc:EidelLev/Inertia';\n\nInertia.share({\n  params: ({ params }) =\u003e params,\n});\n```\n\nThen we can access the params in our component like so:\n\n```typescript\nimport { usePage } from '@inertiajs/inertia-react';\n\nconst { params } = usePage().props;\nstardust.route('users.show', { id: params.id });\n```\n\n## Route Helper\n\nIf you have a page that doesn't need a corresponding controller method, like an\nFAQ or about page, you can route directly to a component.\n\n```typescript\n// /start/routes.ts\nimport Route from '@ioc:Adonis/Core/Route';\n\nRoute.inertia('about', 'About');\n\n// You can also pass root template data as the third parameter:\nRoute.inertia('about', 'About', { metadata: '...' });\n```\n\n## Redirects\n\n### External redirects\n\nSometimes it's necessary to redirect to an external website, or even another\nnon-Inertia endpoint in your app, within an Inertia request.\nThis is possible using a server-side initiated window.location visit.\n\n```typescript\nRoute.get('redirect', async ({ inertia }) =\u003e {\n  inertia.location('https://inertiajs.com/redirects');\n});\n```\n\n## Advanced\n\n### Server-side rendering\n\nWhen Inertia detects that it's running in a Node.js environment,\nit will automatically render the provided page object to HTML and return it.\n\n#### Setting up server side rendering\n\nAfter configuring the the package using `ace configure` and enabling SSR,\nyou will need to edit `webpack.ssr.config.js`.\nSet it up as you have your regular encore config to\nsupport your client-side framework of choice.\n\n#### Adding an additional entrypoint\n\nCreate a new entrypoint `resources/js/ssr.js` (or `ssr.ts`/`ssr.tsx`\nif you prefer to use Typescript).\n\nYour entrypoint code will depend on your client-side framework of choice:\n\n##### React\n\n```jsx\nimport React from 'react';\nimport ReactDOMServer from 'react-dom/server';\nimport { createInertiaApp } from '@inertiajs/react';\n\nexport default function render(page) {\n  return createInertiaApp({\n    page,\n    render: ReactDOMServer.renderToString,\n    resolve: (name) =\u003e require(`./Pages/${name}`),\n    setup: ({ App, props }) =\u003e \u003cApp {...props} /\u003e,\n  });\n}\n```\n\n##### Vue3\n\n```javascript\nimport { createSSRApp, h } from 'vue';\nimport { renderToString } from '@vue/server-renderer';\nimport { createInertiaApp } from '@inertiajs/vue3';\n\nexport default function render(page) {\n  return createInertiaApp({\n    page,\n    render: renderToString,\n    resolve: (name) =\u003e require(`./Pages/${name}`),\n    setup({ app, props, plugin }) {\n      return createSSRApp({\n        render: () =\u003e h(app, props),\n      }).use(plugin);\n    },\n  });\n}\n```\n\n##### Vue2\n\n```javascript\nimport Vue from 'vue';\nimport { createRenderer } from 'vue-server-renderer';\nimport { createInertiaApp } from '@inertiajs/vue2';\n\nexport default function render(page) {\n  return createInertiaApp({\n    page,\n    render: createRenderer().renderToString,\n    resolve: (name) =\u003e require(`./Pages/${name}`),\n    setup({ app, props, plugin }) {\n      Vue.use(plugin);\n      return new Vue({\n        render: (h) =\u003e h(app, props),\n      });\n    },\n  });\n}\n```\n\n##### Svelte\n\n```javascript\nimport { createInertiaApp } from '@inertiajs/svelte';\nimport createServer from '@inertiajs/svelte/server';\n\ncreateServer((page) =\u003e\n  createInertiaApp({\n    page,\n    resolve: (name) =\u003e require(`./Pages/${name}.svelte`),\n  }),\n);\n```\n\n#### Starting the SSR dev server\n\nIn a separate terminal run encore for SSR in watch mode:\n\n```shell\nnode ace ssr:watch\n```\n\n#### Building SSR for production\n\n```shell\nnode ace ssr:build\n```\n\n\u003e ❗In most cases you do not want the compiled javascript for ssr committed\n\u003e to source control.\n\u003e To avoid it, please add the `inertia` directory to `.gitignore`.\n\n#### Customizing SSR output directory\n\nBy default, SSR assets will be emitted to `inertia/ssr` directory. If you\nprefer to use a different directory, you can change it by setting the\n`buildDirectory` parameter:\n\n```typescript\n// /config/inertia.ts\n{\n  ssr: {\n    enabled:true,\n    buildDirectory: 'custom_path/ssr'\n  }\n}\n```\n\n**You will also need to configure your SSR webpack config to output files to\nthe same path.**\n\n#### Opting Out of SSR\n\nBuilding isomorphic apps often comes with additional complexity.\nIn some cases you may prefer to render only certain public routes on the\nserver while letting the rest be rendered on the client.\nLuckily you can easily opt out of SSR by configuring a list of components that\nwill rendered on the server, excluding all other components.\n\n```typescript\n{\n  ssr: {\n    enabled:true,\n    allowList: ['HomePage', 'Login']\n  }\n}\n```\n\n### Authentication\n\nAdonisJS provides us with powerful authentication and authorization APIs through\n`@adonisjs/auth`. After installing and setting up `@adonisjs/auth` you will need\nto set up exception handling to make it work with Inertia.\n\nFirst, let's use `@adonisjs/auth` in our controller to authenticate the user:\n\n```typescript\n// app/Controllers/Http/AuthController.ts\npublic async login({ auth, request, response }: HttpContextContract) {\n  const loginSchema = schema.create({\n    email: schema.string({ trim: true }, [rules.email()]),\n    password: schema.string(),\n  });\n\n  const { email, password } = await request.validate({\n    schema: loginSchema,\n    messages: {\n      required: 'This field is required',\n      email: 'Please enter a valid email',\n    },\n  });\n\n  await auth.use('web').attempt(email, password);\n\n  response.redirect('/');\n}\n\n```\n\nBy default, AdonisJS will send an HTTP 400 response, which inertia does not know\nhow to handle. Therefore, we will intercept this exception and redirect back to\nour login page (we can also optionally preserve the error message with flash messages).\n\n```typescript\n// app/Exceptions/Handler.ts\n\nimport { HttpContextContract } from '@ioc:Adonis/Core/HttpContext';\nimport HttpExceptionHandler from '@ioc:Adonis/Core/HttpExceptionHandler';\nimport Logger from '@ioc:Adonis/Core/Logger';\n\nexport default class ExceptionHandler extends HttpExceptionHandler {\n  protected statusPages = {\n    '403': 'errors/unauthorized',\n    '404': 'errors/not-found',\n    '500..599': 'errors/server-error',\n  };\n\n  constructor() {\n    super(Logger);\n  }\n\n  public async handle(error: any, ctx: HttpContextContract) {\n    const { session, response } = ctx;\n\n    /**\n     * Handle failed authentication attempt\n     */\n    if (['E_INVALID_AUTH_PASSWORD', 'E_INVALID_AUTH_UID'].includes(error.code)) {\n      session.flash('errors', { login: error.message });\n      return response.redirect('/login');\n    }\n\n    /**\n     * Forward rest of the exceptions to the parent class\n     */\n    return super.handle(error, ctx);\n  }\n}\n```\n\n### Asset Versioning\n\nTo enable automatic asset refreshing, you simply need to tell Inertia what the\ncurrent version of your assets is. This can be any string\n(letters, numbers, or a file hash), as long as it changes\nwhen your assets have been updated.\n\nTo configure the current asset version, edit `start/inertia.ts`:\n\n```typescript\nimport Inertia from '@ioc:EidelLev/Inertia';\n\nInertia.version('v1');\n\n// You can also pass a function that will be lazily evaluated:\nInertia.version(() =\u003e 'v2');\n```\n\nIf you are using Adonis's built-in assets manager [webpack encore](https://docs.adonisjs.com/guides/assets-manager)\nyou can also pass the path to the manifest file to Inertia and the current\nversion will be set automatically:\n\n```typescript\nInertia.version(() =\u003e Inertia.manifestFile('public/assets/manifest.json'));\n```\n\n## Setting Up View\n\nYou can set up the inertia root div in your view using the @inertia tag:\n\n```blade\n\u003cbody\u003e\n  @inertia\n\u003c/body\u003e\n```\n\n## Contributing\n\nThis project happily accepts contributions.\n\n### Getting Started\n\nAfter cloning the project run\n\n```shell\nnpm ci\nnpx husky install # This sets up the project's git hooks\n```\n\n### Before Making a Commit\n\nThis project adheres to the [semantic versioning](https://semver.org/) convention,\ntherefore all commits must be [conventional](https://github.com/conventional-changelog/commitlint).\n\nAfter staging your changes using `git add`, you can use the `commitlint CLI`\nto write your commit message:\n\n```shell\nnpx commit\n```\n\n### Before Opening a Pull Request\n\n- Make sure you add tests that cover your changes\n- Make sure all tests pass:\n\n```shell\nnpm test\n```\n\n- Make sure eslint passes:\n\n```shell\nnpm run lint\n```\n\n- Make sure your commit message is valid:\n\n```shell\nnpx commitlint --edit\n```\n\n**Thank you to all the people who already contributed to this project!**\n\n## Issues\n\nIf you have a question or found a bug, feel free to [open an issue](https://github.com/eidellev/inertiajs-adonisjs/issues).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feidellev%2Finertiajs-adonisjs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feidellev%2Finertiajs-adonisjs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feidellev%2Finertiajs-adonisjs/lists"}