Building with AdonisJS & Inertia
We'll learn how to use InertiaJS with AdonisJS 6 to build a feature-complete application, called PlotMyCourse. Our application will use server-side rendering (SSR), Vue 3, and Shadcn-Vue. It'll feature organizations, drag-and-drop, and lots of forms.
Module 1 › Getting Started (5 lessons)
Lesson 1.0
What Is InertiaJS?
In this lesson, we'll introduce InertiaJS. We'll discuss what it is, what it helps with, its adapters, and more.
Lesson 1.1
What We'll Be Building
At the end of this series, we'll have a feature-complete application with organizations, teams, drag-and-drop ordering, password reset, and more! So, let's take a second to see our end goal and walk through the app.
Lesson 1.2
Creating Our AdonisJS App With InertiaJS
In this lesson, we'll create a new AdonisJS 6 application with the InertiaJS Starter Kit. We'll then walk through the Inertia-specific aspects of our project structure and briefly discuss the configuration steps taken when adding Inertia.
Lesson 1.3
Server-Side Rendering (SSR) vs Client-Side Rendering (CSR)
In this lesson, we'll discuss the differences between InertiaJS in a server-side rendered (SSR) and a client-side rendered (CSR) application. We'll then compare when you would want to choose one over the other and the pros and cons of both.
Lesson 1.4
Setting Up TailwindCSS, Shadcn-Vue, and Automatic Component Imports
In this lesson, we'll install and configure Shadcn-Vue and TailwindCSS. We'll then set up automatic imports for all of our local Vue components.
Module 2 › The Basics (10 lessons)
Lesson 2.0
The Flow of Pages and Page Props
In this lesson, we'll talk about the flow InertiaJS follows when rendering pages, from AdonisJS to our Vue application. Then, we'll talk about passing props to our Vue page components.
Lesson 2.1
Sharing Data from AdonisJS to Vue via Inertia
In this lesson, we'll learn how to pass data from AdonisJS to Vue using Inertia as the broker. We'll discuss passing data from our controllers, from middleware, and globally via the Inertia shared data configuration.
Lesson 2.2
Linking Between Pages & Page State Flow
In this lesson, we'll learn how to link from page to page the InertiaJS way. We'll then inspect how InertiaJS gets and updates our page's stateful information via our page props.
Lesson 2.3
The Link Component and Programmatic Linking
In this lesson, we'll explore Inertia's Link component and its props. We'll then examine how to link between pages programmatically using Inertia's router.
Lesson 2.4
Global Components and Hydration Mismatch in Action
In this lesson, we'll learn how to register components globally inside our Vue application. We'll also learn what to watch out for and examine a hydration mismatch in action.
Lesson 2.5
Partial and Lazy Data Loading and Evaluation
In this lesson, we'll learn about Inertia's partial reload functionality that allows us to refresh only specifically specified prop items for our page. We'll also examine lazy properties and how our props are evaluated with partial reloads.
Lesson 2.6
Creating A Layout
In this lesson, we'll learn how to create a layout component and apply it to all our pages, the Inertia way.
Lesson 2.7
Default Layouts & Overwriting the Default Layout
In this lesson, we'll inspect how Inertia injects our layout component and the data passed to it. We'll also learn how we can overwrite our default layout from our page components.
Lesson 2.8
Specifying Page Titles & Meta Tags
In this lesson, we'll learn how we can append information into the head of our document with Inertia on a per-page basis. We'll then create our own head component, wrapping Inertia's, to allow easier global changes.
Lesson 2.9
What Code Can & Can't Be Shared Between AdonisJS & Inertia
In this lesson, we'll discuss what code we can and cannot share between AdonisJS and Inertia.
Module 3 › Working with Forms (7 lessons)
Lesson 3.0
Inertia Form Basics
In this lesson, we'll introduce the basics of working with form in Inertia. We'll set up our register form with its fields, get our form state set up, and send off a post request to one of our AdonisJS routes.
Lesson 3.1
Form Validation & Displaying Errors
In this lesson, we'll add validation to our POST handler for our register route. We'll then update our form fields to check for and display any validation errors that may have occurred.
Lesson 3.2
The useForm Helper
In this lesson, we'll introduce the useForm helper composable provided by InertiaJS. We'll refactor our current form to use the useForm helper instead and see how it can help manage our form state, errors, and submission.
Lesson 3.3
Common useForm Methods & Options
In this lesson, we'll walk through some of the more common methods and options we have with the useForm helper, like adding form errors, maintaining scroll position, mutating values prior to submission, and more.
Lesson 3.4
Creating A FormInput Vue Component
In this lesson, we'll create a reusable FormInput Vue Component using our current form field as a starting point.
Lesson 3.5
Cross-Site Request Forgery (CSRF) Protection in InertiaJS
In this lesson, we'll learn how cross-site request forgery (CSRF) protection between AdonisJS and InertiaJS behaves in our application.
Lesson 3.6
What Are Some of Inertia's Limitations
In this lesson, we'll discuss a couple of Inertia's request and routing limitations and how we can circumvent them by reaching for axios or fetch instead.
Module 4 › Database & Project Scaffolding (8 lessons)
Lesson 4.0
Understanding Our Database Schema
In this lesson, we'll walk through a diagram of our application's database schema to understand how things relate to one another.
Lesson 4.1
Defining Our Migrations & Foreign Keys
In this lesson, we'll create our migrations, models, and some of our controllers. We'll then fill out our migrations and define our relationship's foreign key constraints.
Lesson 4.2
Defining Our Lucid Models & Relationships
In this lesson, we'll convert our migrations into Lucid Models and define both sides of the relationships so they're ready to go.
Lesson 4.3
Creating A Lucid Model Mixin for our Organization Relationship
In this lesson, we'll learn how we can extract repetitive relationships, and other model properties/methods, into a mixin. We'll also learn what to look out for when using decorators within a TypeScript mixin.
Lesson 4.4
Seeding Our Initial Database Data
In this lesson, we'll create a seeder file to create the initial data we'll need in our database to get going. For now, that's just going to be our application's roles.
Lesson 4.5
Typing Lucid Models in Inertia with DTOs
In this lesson, we'll learn how we can specify types for our Lucid Models easily using DTOs we'll generate directly from our models.
Lesson 4.6
Completing Our AppLayout & Navigation Bar
In this lesson, we'll finish setting up our application's layout shell and navigation bar.
Lesson 4.7
Creating A Toast Message Manager
Learn how to implement a user feedback manager in your app using toast messages and vue-sonner. We'll integrate our flash message manager with state provided from AdonisJS' flash messages store to display success and error messages.
Module 5 › Authentication & Onboarding (7 lessons)
Lesson 5.0
User Registration with InertiaJS
In this lesson, we'll complete our user registration flow by validating our registration form data, creating a new user, logging that user in, and forwarding them to the next page in the flow.
Lesson 5.1
Splitting Our Routes Between Auth & Web
In this lesson, we'll split our routes into two files: auth and web. Our auth routes file will contain all our authentication-based route definitions and our web routes will contain the remaining.
Lesson 5.2
Logging Out Users
In this lesson, we'll hook up our logout user menu button to a POST route to logout an authenticated user.
Lesson 5.3
Onboarding Newly Registered Users
In this lesson, we'll create our onboarding flow for newly registered users. Before users can enter the application, they'll need to have at least one organization set up so everything works smoothly.
Lesson 5.4
Logging In Users & Displaying Exceptions
In this lesson, we'll add the ability to login to our application. We'll then discuss the differences between errors and errorsBag and how we can display long-lived exception messages as an alternative to our toast manager.
Lesson 5.5
Adding the Remember Me Token
In this lesson, we'll enable the remember me feature on our auth login flow and add the remember me tokens table to our database.
Lesson 5.6
Forgot Password & Password Reset
In this lesson, we'll walk through setting up the complete forgot password flow including, creating a password reset token with time-expiry, sending an email notification with a password reset link, verifying the token, and resetting the users password.
Module 6 › The User's Organizations (7 lessons)
Lesson 6.0
Setting & Loading the User's Active Organization
In this lesson, we'll set up our organization middleware and actions that'll be in charge of loading the user's active organization and role
Lesson 6.1
Listing the User's Organizations
In this lesson, we'll update our organization middleware to query all the user's organizations. We'll then provide everything into our Vue page state via Inertia and begin building our organization select component.
Lesson 6.2
The Form Dialog Component & Adding Organizations
In this lesson, we'll add a new form dialog component that simplifies the create and update forms we'll use throughout our application. We'll then use this component to add a create organization dialog within our organization selector.
Lesson 6.3
Switching Between Organizations
In this lesson, we'll add the ability for our users to change which of their organizations is their active organization via our organization selector.
Lesson 6.4
Creating A UseResourceActions Composable
In this lesson, we'll create a composable that'll be in charge of maintaining form and dialog state for the resources throughout our application, starting with our organizations.
Lesson 6.5
Editing the Active Organization
In this lesson, we'll make use of our useResourceActions composable to add the ability for our user's to edit their active organization.
Lesson 6.6
The Confirm Delete Dialog & Deleting the Active Organization
In this lesson, we'll create a reusable confirm deletion dialog and bind its state into our use resource actions composable. We'll then incorporate this all together to allow users to delete their active organization.
Module 7 › Difficulties, Statuses, & Access Levels (8 lessons)
Lesson 7.0
Listing & Creating Difficulties
In this lesson, we'll create a page to list the active organization's difficulties. Then, we'll add the ability to create a new difficulty and add a new color picker type to our FormInput component.
Lesson 7.1
Updating Difficulties
In this lesson, we'll add the ability to update an organization's difficulties using our useResourceActions composable.
Lesson 7.2
Confirming & Deleting Difficulties
In this lesson, we'll add the ability to delete an organization's difficulties. We'll also make use of our ConfirmDeleteDialog component to confirm the deletion action with our user.
Lesson 7.3
Replacing A Course's Deleted Difficulty
In this lesson, we'll add the ability to gracefully handle instances where a required relationship's record is being deleted. When a difficulty is being used by a course, we'll have our users select a replacement difficulty for the one being deleted.
Lesson 7.4
Reusable VineJS Exists In Organization Validation
In this lesson, we'll take our difficulty's exists in organization VineJS validation and make it reusable so we can easily use it for our statuses, access levels, courses, etc.
Lesson 7.5
Sorting Difficulties with Drag & Drop
In this lesson, we'll allow our user's to customize the ordering of their difficulties via drag-and-drop using VueDraggable. When they commit a change by dropping an item, we'll persist the updated sort to our database.
Lesson 7.6
Creating A Reusable Sorting Vue Component
In this lesson, we'll extract the drag-and-drop logic we added in the last lesson into a reusable Vue component so we can easily make use of the same behavior for our access levels & statuses.
Lesson 7.7
Replicating Behaviors for Access Levels & Statuses
In this lesson, we'll replicate everything we've done for difficulties to add our access levels and statuses.
Module 8 › Courses (6 lessons)
Lesson 8.0
Querying & Listing An Organization's Courses
In this lesson, we'll query the active organization's courses and list them out in a table.
Lesson 8.1
Creating A New Course
In this lesson, we'll add the ability to create a new course within the active organization.
Lesson 8.2
Editing & Updating Courses
In this lesson, we'll add the ability to edit and update a course within the active organization.
Lesson 8.3
Deleting Courses
In this lesson, we'll add the ability to delete courses from an organization with confirmation from our user.
Lesson 8.4
Showing A Course's Details
In this lesson, we'll add our courses show page, which will be in charge of displaying the course details along with its modules & lessons. In this lesson we'll lay the groundwork, then in the next module we'll add in our modules & lessons.
Lesson 8.5
The Tag Selector
In this lesson, we'll define a reusable tag selector component that we'll use for our difficulties, access levels, and statuses. This component will accept props that will automatically send a patch request to our server to update values as they change.
Module 9 › Modules & Lessons (8 lessons)
Lesson 9.0
Querying & Listing Sortable Course Modules
In this lesson, we'll query and add a sortable list of a course's modules on the courses show page.
Lesson 9.1
Creating, Editing, & Deleting Course Modules
In this lesson, we'll add the ability to create, edit, and delete a course's modules using the reusable components and composables we've created in past lessons.
Lesson 9.2
Creating & Listing Sortable Course Lessons
In this lesson, we'll add the ability to create new lessons within a course's module. We'll then list the lessons within their designated module using the order specified by the user.
Lesson 9.3
Editing & Deleting Course Lessons
In this lesson, we'll add the ability to edit and delete lessons from a course's module. When editing, we'll also decrement the order field for all lessons within the module after the lesson being deleted.
Lesson 9.4
Adding A Publish Date & Time Input
In this lesson, we'll add publish at date & time fields to our lesson form. We'll learn how we can split these two values apart for their inputs and join them back together before sending to the server. We'll also touch on timezone considerations.
Lesson 9.5
Patching Tag Changes for our Modules & Lessons
In this lesson, we’ll incorporate our Tag Selector component into our modules and lessons to facilitate easy visibility and updates of their statuses and access levels.
Lesson 9.6
Storing Module Order Changes from Vue Draggable
In this lesson, we'll persist sort order changes to the database when dragging and dropping a course's modules using Vue Draggable
Lesson 9.7
Storing Lesson Order Changes & Handling Cross-Module Drag & Drops
In this lesson, save the changes made to lessons inside a course when a user uses drag-and-drop to move a lesson. Users can change the lesson order inside a single module or move a lesson into a new module, so we'll need to handle both use cases.