Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork16
eidellev/inertiajs-adonisjs
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
Inertia.js lets you quickly build modern single-pageReact, Vue and Svelte apps using classic server-side routing and controllers.
AdonisJS is a fully featured web framework focused onproductivity and developer ergonomics.
- Feature parity with the official Inertia backend adapters
- Full compatibility with all official client-side adapters
- Easy setup
- Quality documentation
# NPMnpm i @eidellev/inertia-adonisjs# or Yarnyarn add @eidellev/inertia-adonisjs
This library depends on twoAdonisJS core libraries:@adonisjs/view and@adonisjs/session.If you started off with theapi orslim project structure you will need toinstall these separately:
# NPMnpm i @adonisjs/viewnpm i @adonisjs/session# or Yarnyarn add @adonisjs/viewyarn add @adonisjs/session# Additionally, you will need to configure the packages:node ace configure @adonisjs/viewnode ace configure @adonisjs/session
You can register the package, generate additional files and install additionaldependencies by running:
node ace configure @eidellev/inertia-adonisjs
Inertia will query you on your preferences (e.g. which front-end framework youprefer and if you want server side rendering) and generate additional files.
The configuration forinertia-adonisjs is set in/config/inertia.ts:
import{InertiaConfig}from'@ioc:EidelLev/Inertia';exportconstinertia:InertiaConfig={view:'app',};
Add Inertia middleware tostart/kernel.ts:
Server.middleware.register([()=>import('@ioc:Adonis/Core/BodyParser'),()=>import('@ioc:EidelLev/Inertia/Middleware'),]);
exportdefaultclassUsersController{publicasyncindex({ inertia, request}:HttpContextContract){constusers=awaitUser.all();returninertia.render('Users/IndexPage',{ users});}}
Lazy responses are useful when you want to render a page without some data that should be loaded initially.
importInertiafrom'@ioc:EidelLev/Inertia';exportdefaultclassUsersController{publicasyncindex({ inertia, request}:HttpContextContract){constusers=awaitUser.all();returninertia.render('Users/IndexPage',{ users,lazyProp:Inertia.lazy(()=>{return{lazy:'too lazy'};}),});}}
The data will be loaded on demand by the explicit Inertia visit with option
{ only:['lazyProp'];}
There are situations where you may want to access your prop data in your rootEdge template. For example, you may want to add a meta description tag,Twitter card meta tags, or Facebook Open Graph meta tags.
<metaname="twitter:title"content="{{page.title}}">
Sometimes you may even want to provide data that will not be sent to yourJavaScript component.
returninertia.render('Users/IndexPage',{ users},{metadata:'...' :'...'});
Sometimes you need to access certain data on numerous pages within yourapplication. For example, a common use-case for this is showing the current userin the site header. Passing this data manually in each response isn't practical.In these situations shared data can be useful.
In order to add shared props, editstart/inertia.ts:
importInertiafrom'@ioc:EidelLev/Inertia';Inertia.share({errors:(ctx)=>{returnctx.session.flashMessages.get('errors');},// Add more shared props here});
Traditionally in Adonis, we have access to the context instance eg. paramsinside view (.edge) that we can use to help build our dynamic routes.But with inertia, we lose access to the context instance entirely.
We can overcome this limitation by passing the contextinstance as a shared data prop:
// start/inertia.tsimportInertiafrom'@ioc:EidelLev/Inertia';Inertia.share({params:({ params})=>params,});
Then we can access the params in our component like so:
import{usePage}from'@inertiajs/inertia-react';const{ params}=usePage().props;stardust.route('users.show',{id:params.id});
If you have a page that doesn't need a corresponding controller method, like anFAQ or about page, you can route directly to a component.
// /start/routes.tsimportRoutefrom'@ioc:Adonis/Core/Route';Route.inertia('about','About');// You can also pass root template data as the third parameter:Route.inertia('about','About',{metadata:'...'});
Sometimes it's necessary to redirect to an external website, or even anothernon-Inertia endpoint in your app, within an Inertia request.This is possible using a server-side initiated window.location visit.
Route.get('redirect',async({ inertia})=>{inertia.location('https://inertiajs.com/redirects');});
When Inertia detects that it's running in a Node.js environment,it will automatically render the provided page object to HTML and return it.
After configuring the the package usingace configure and enabling SSR,you will need to editwebpack.ssr.config.js.Set it up as you have your regular encore config tosupport your client-side framework of choice.
Create a new entrypointresources/js/ssr.js (orssr.ts/ssr.tsxif you prefer to use Typescript).
Your entrypoint code will depend on your client-side framework of choice:
importReactfrom'react';importReactDOMServerfrom'react-dom/server';import{createInertiaApp}from'@inertiajs/react';exportdefaultfunctionrender(page){returncreateInertiaApp({ page,render:ReactDOMServer.renderToString,resolve:(name)=>require(`./Pages/${name}`),setup:({ App, props})=><App{...props}/>,});}
import{createSSRApp,h}from'vue';import{renderToString}from'@vue/server-renderer';import{createInertiaApp}from'@inertiajs/vue3';exportdefaultfunctionrender(page){returncreateInertiaApp({ page,render:renderToString,resolve:(name)=>require(`./Pages/${name}`),setup({ app, props, plugin}){returncreateSSRApp({render:()=>h(app,props),}).use(plugin);},});}
importVuefrom'vue';import{createRenderer}from'vue-server-renderer';import{createInertiaApp}from'@inertiajs/vue2';exportdefaultfunctionrender(page){returncreateInertiaApp({ page,render:createRenderer().renderToString,resolve:(name)=>require(`./Pages/${name}`),setup({ app, props, plugin}){Vue.use(plugin);returnnewVue({render:(h)=>h(app,props),});},});}
import{createInertiaApp}from'@inertiajs/svelte';importcreateServerfrom'@inertiajs/svelte/server';createServer((page)=>createInertiaApp({ page,resolve:(name)=>require(`./Pages/${name}.svelte`),}),);
In a separate terminal run encore for SSR in watch mode:
node ace ssr:watch
node ace ssr:build
❗In most cases you do not want the compiled javascript for ssr committedto source control.To avoid it, please add the
inertiadirectory to.gitignore.
By default, SSR assets will be emitted toinertia/ssr directory. If youprefer to use a different directory, you can change it by setting thebuildDirectory parameter:
// /config/inertia.ts{ssr:{enabled:true,buildDirectory:'custom_path/ssr'}}
You will also need to configure your SSR webpack config to output files tothe same path.
Building isomorphic apps often comes with additional complexity.In some cases you may prefer to render only certain public routes on theserver while letting the rest be rendered on the client.Luckily you can easily opt out of SSR by configuring a list of components thatwill rendered on the server, excluding all other components.
{ssr:{enabled:true,allowList:['HomePage','Login']}}
AdonisJS provides us with powerful authentication and authorization APIs through@adonisjs/auth. After installing and setting up@adonisjs/auth you will needto set up exception handling to make it work with Inertia.
First, let's use@adonisjs/auth in our controller to authenticate the user:
// app/Controllers/Http/AuthController.tspublicasynclogin({ auth, request, response}:HttpContextContract){constloginSchema=schema.create({email:schema.string({trim:true},[rules.email()]),password:schema.string(),});const{ email, password}=awaitrequest.validate({schema:loginSchema,messages:{required:'This field is required',email:'Please enter a valid email',},});awaitauth.use('web').attempt(email,password);response.redirect('/');}
By default, AdonisJS will send an HTTP 400 response, which inertia does not knowhow to handle. Therefore, we will intercept this exception and redirect back toour login page (we can also optionally preserve the error message with flash messages).
// app/Exceptions/Handler.tsimport{HttpContextContract}from'@ioc:Adonis/Core/HttpContext';importHttpExceptionHandlerfrom'@ioc:Adonis/Core/HttpExceptionHandler';importLoggerfrom'@ioc:Adonis/Core/Logger';exportdefaultclassExceptionHandlerextendsHttpExceptionHandler{protectedstatusPages={'403':'errors/unauthorized','404':'errors/not-found','500..599':'errors/server-error',};constructor(){super(Logger);}publicasynchandle(error:any,ctx:HttpContextContract){const{ session, response}=ctx;/** * Handle failed authentication attempt */if(['E_INVALID_AUTH_PASSWORD','E_INVALID_AUTH_UID'].includes(error.code)){session.flash('errors',{login:error.message});returnresponse.redirect('/login');}/** * Forward rest of the exceptions to the parent class */returnsuper.handle(error,ctx);}}
To enable automatic asset refreshing, you simply need to tell Inertia what thecurrent version of your assets is. This can be any string(letters, numbers, or a file hash), as long as it changeswhen your assets have been updated.
To configure the current asset version, editstart/inertia.ts:
importInertiafrom'@ioc:EidelLev/Inertia';Inertia.version('v1');// You can also pass a function that will be lazily evaluated:Inertia.version(()=>'v2');
If you are using Adonis's built-in assets managerwebpack encoreyou can also pass the path to the manifest file to Inertia and the currentversion will be set automatically:
Inertia.version(()=>Inertia.manifestFile('public/assets/manifest.json'));
You can set up the inertia root div in your view using the @inertia tag:
<body>@inertia</body>
This project happily accepts contributions.
After cloning the project run
npm cinpx husky install# This sets up the project's git hooksThis project adheres to thesemantic versioning convention,therefore all commits must beconventional.
After staging your changes usinggit add, you can use thecommitlint CLIto write your commit message:
npx commit
- Make sure you add tests that cover your changes
- Make sure all tests pass:
npmtest- Make sure eslint passes:
npm run lint
- Make sure your commit message is valid:
npx commitlint --edit
Thank you to all the people who already contributed to this project!
If you have a question or found a bug, feel free toopen an issue.
About
Topics
Resources
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Sponsor this project
Uh oh!
There was an error while loading.Please reload this page.
