2024-08-30

How to Set Up Inertia Components in a Modular Laravel app

I’ve recently been refactoring a big Laravel app into separate modules, following Mateus Guimarães’ excellent Modular Laravel course on Laracasts. One specific topic not covered was how to put front-end components (i.e., from Vue, React, Svelte) inside the module too. This is a quick guide on how I was able to get it to work inside my application.

1. Tell Inertia where to look for front end templates

In my case I’m using a modules folder, so in app.js/ts we need to add a line to the array of paths to look for Vue files:

// ...
createInertiaApp({
	resolve: (name) => {
		const pages = import.meta.glob([
			"./Pages/**/*.vue",
			"../../modules/**/*.vue",
		]);
		for (const path in pages) {
		// ...
		}
})

2. Put templates in the module

You could set this up in many ways, but I’m choosing a Pages/ directory directly inside the module. For instance, my CheckIn module looks like this:

modules/
	CheckIn/
		...
		Pages/
			Bear/
				Edit.vue
				Index.vue
				Show.vue
			BighornSheep/

And in the CheckInController, I reference the component like this:

<?php

namespace Modules\CheckIn\Http\Controllers;

use Inertia\Response;

class CheckInController
{
	public function index(): Response
	{
		return inertia('CheckIn/Pages/Index');
	}
}

3. Fix component references in tests

If your asserting whether or not a component is rendered in your tests, there’s one more step you need to take. In config/inertia.php, add an additional path to the path_pages array.

[
	// ...
	"testing" => [
		"ensure_pages_exist" => true,
		"page_paths" => [
			".../resources/js/Pages",
			"modules",
		],
		// ...
	],
]

And finally, in the test:

<?php

test('can access the check-ins page', function () {
	$response = $this->get('/check-ins')
		->assertInertia(fn (Assert $page) => $page
			->component('CheckIn/Pages/Index')
		);
	$response->assertStatus(200);
});

I like this approach because the component string, e.g. CheckIn/Pages/Bear/Index is consistent in the controllers and the tests.