Setting Up Modular Laravel Applications: A Step-by-Step Guide

Dr. Adam Nielsen
3 min readAug 15, 2024

--

Working on large Laravel applications can become challenging as your project grows. Navigating through various directories like app/Http, app/Services, resources/views, resources/js for Vue files, and even tests/, can be overwhelming. Over time, your route files can also become bloated, making it difficult to maintain an overview of which controllers, models, routes, and other components are associated with a specific feature.

This is where modular architecture in Laravel comes into play. By breaking down your application into self-contained modules, you can keep related files together, making your codebase more organized and easier to manage.

In this article, I’ll guide you through setting up a modular architecture in Laravel. We’ll walk through the steps to create a modules directory, configure your composer.json file for autoloading, and set up service providers, routes, views, and tests within your module.

Why Use Modular Architecture?

Modular architecture allows you to:

  • Improve Code Organization: Keep related components like controllers, models, routes, and views together.
  • Increase Maintainability: Simplify navigation through the codebase, especially in large projects.

Step 1: Create a Modules Directory

First, let’s create a modules directory at the root level of your Laravel application. This directory will contain all the individual modules you create.

Step 2: Update composer.json for PSR-4 Autoloading

To make sure your modules are autoloaded by Laravel, you need to update the composer.json file with the correct namespace configuration. Add the Modules\\ namespace to the autoload section:

"autoload": {
"psr-4": {
"App\\": "app/",
"Database\\Factories\\": "database/factories/",
"Database\\Seeders\\": "database/seeders/",
"Modules\\": "modules/" // <- you need to add this
},
}

After making this change, run the following command to regenerate the autoload files:

composer dump-autoload

With this setup, you can now place your services, controllers, models, and other classes within the modules directory. For example, you might have a structure like this:

modules/
Blog/
Http/
Models/
Services/
Blades/
Tests/
routes.php
BlogServiceProvider.php

Step 3: Setting Up a Service Provider for Your Module

Next, you’ll need to create a service provider for your module. This service provider will handle loading routes, views, and any other module-specific configuration.

Create a new service provider within your module’s directory and register it in config/app.php file under the providers array:

'providers' => [
...
Modules\Blog\Providers\BlogServiceProvider::class,
],

Inside your BlogServiceProvider, load the routes and views from the current module's directory:

namespace Modules\Blog\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\View;

class BlogServiceProvider extends ServiceProvider
{
public function boot()
{
$this->loadRoutesFrom(__DIR__ . '/routes.php');
$this->loadViewsFrom(__DIR__ . '/Blades', 'blog');
}
}

Step 4: Organizing Routes, Views, and Tests

Loading Routes

Create a routes directory within your module and define your routes in a web.php file:

// modules/Blog/routes/web.php

use Illuminate\Support\Facades\Route;

Route::middleware(['web'])
->group(function () {
Route::get('/blog', 'BlogController@index')->name('blog.index');
});

Remember to manually apply the web middleware. In routes/web.php, the web middleware is automatically applied, but that doesn't happen in your custom routes.php file. So you'll need to explicitly add it to ensure your routes have the correct session, CSRF protection, and other middleware features.

Loading Views

When loading views in your controllers, use the namespace specified in the service provider:

// modules/Blog/Http/Controllers/BlogController.php

namespace Modules\Blog\Http\Controllers;

use App\Http\Controllers\Controller;

class BlogController extends Controller
{
public function index()
{
return view('blog::index');
}
}

Updating Tailwind CSS Configuration

If you’re using Tailwind CSS, make sure to update your tailwind.config.js to scan for classes within your modules directory:

module.exports = {
content: [
'./resources/**/*.blade.php',
'./resources/**/*.js',
'./resources/**/*.vue',
'./modules/**/*.blade.php',
'./modules/**/*.js',
'./modules/**/*.vue',
],
theme: {
extend: {},
},
plugins: [],
}

Setting Up Tests for Your Module

If you want to include tests within your module, create a tests directory inside your module and update your phpunit.xml file to include a custom test suite for your module:

<testsuite name="modules">
<directory suffix="Test.php">./modules/*/Tests</directory>
</testsuite>

Now, you can write tests for your module in the modules/Blog/tests directory, and they will be included when you run phpunit. If you only want to run the tests of your modules testsuite, run phpunit --testsuite=modules .

Conclusion

Setting up a modular structure in Laravel can significantly improve your workflow, especially when working on large applications. By keeping related files together and leveraging Laravel’s service providers, you can make your application more organized and maintainable. Follow the steps outlined in this guide, and you’ll be on your way to mastering modular architecture in Laravel.

I hope you found this guide helpful. Happy coding!

--

--