Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/internachi/modular/llms.txt

Use this file to discover all available pages before exploring further.

Overview

The ViewPlugin automatically registers view namespaces for your modules, allowing you to reference module views using the module-name::view.name syntax.

How It Works

The plugin discovers the resources/views directory in each module and registers it as a view namespace with Laravel’s view factory.

Discovery Process

  1. Find View Directories: Locates resources/views directories in all modules
  2. Register Namespaces: Registers each directory with the module’s name as the namespace
  3. Integration: Works seamlessly with Laravel’s view system

Source Code

public function discover(FinderFactory $finders): iterable
{
    return $finders
        ->viewDirectoryFinder()
        ->withModuleInfo()
        ->values()
        ->map(fn(ModuleFileInfo $dir) => [
            'namespace' => $dir->module()->name,
            'path' => $dir->getRealPath(),
        ]);
}

public function handle(Collection $data)
{
    $data->each(fn(array $d) => $this->factory->addNamespace($d['namespace'], $d['path']));
}

Expected Module Structure

app-modules/
  blog/
    resources/
      views/
        posts/
          index.blade.php
          show.blade.php
          create.blade.php
        layouts/
          app.blade.php

Activation

The plugin uses the AfterResolving attribute to activate after Laravel’s view factory is resolved:
#[AfterResolving(ViewFactory::class, parameter: 'factory')]
class ViewPlugin extends Plugin
{
    public function __construct(
        protected ViewFactory $factory,
    ) {
    }
}

Usage Examples

Rendering Views

// In a controller
public function index()
{
    return view('blog::posts.index', [
        'posts' => Post::all(),
    ]);
}

// Return specific view
public function show(Post $post)
{
    return view('blog::posts.show', compact('post'));
}

In Blade Templates

{{-- Include a module view --}}
@include('blog::posts.card', ['post' => $post])

{{-- Extend a module layout --}}
@extends('blog::layouts.app')

@section('content')
    <h1>Blog Post</h1>
@endsection

{{-- Use view composer --}}
@each('blog::posts.card', $posts, 'post')

In Routes

Route::get('/posts', function () {
    return view('blog::posts.index');
});

Route::view('/about', 'blog::pages.about');

Checking View Existence

if (view()->exists('blog::posts.custom')) {
    return view('blog::posts.custom');
}

return view('blog::posts.default');

View Namespace Priority

When a view is requested, Laravel checks:
  1. Module’s resources/views directory (registered by this plugin)
  2. Application’s resources/views/vendor/{module} directory (for customization)
This allows you to override module views in your main application:
resources/
  views/
    vendor/
      blog/
        posts/
          index.blade.php  # Overrides module's index view

Integration with Blade Components

Module views work alongside Blade components. The BladePlugin handles component registration separately:
{{-- Use a module's traditional view --}}
@include('blog::posts.card')

{{-- Use a module's Blade component --}}
<x-blog::post-card :post="$post" />
View namespaces are registered automatically when modules are discovered. No manual configuration is required.

View Composers

You can register view composers for module views in your module’s service provider:
namespace Modules\Blog\Providers;

use Illuminate\Support\Facades\View;
use Illuminate\Support\ServiceProvider;
use Modules\Blog\View\Composers\PostComposer;

class BlogServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        // Compose specific view
        View::composer('blog::posts.index', PostComposer::class);
        
        // Compose all views in namespace
        View::composer('blog::*', function ($view) {
            $view->with('siteName', 'My Blog');
        });
    }
}

See Also