vite-plugin-inertia-modules
v0.3.0
Published
Serve Inertia pages from Composer packages. Build modular Laravel apps where each module ships its own frontend.
Downloads
1,046
Maintainers
Readme
vite-plugin-inertia-modules
Serve Inertia pages straight from Composer packages.
Build modular Laravel + Inertia applications where each module is a Composer package that ships its own backend and its own pages — discovered, compiled, and resolved automatically by the host application's Vite.
// In a controller, anywhere:
return Inertia::render('payments::Invoices/Index', ['invoices' => $invoices]);composer require acme/payments # pages included. No publishing, no copying.The problem
Inertia resolves page components inside the host application — there is no built-in way for a Composer package to ship pages. The usual workarounds all hurt: publishing stubs means updates never reach the app, and isolated builds (Nova-style) duplicate the framework runtime and break visual consistency.
This plugin makes Composer packages first-class page providers. Pages live in
the package, are compiled by the host's Vite (one bundle, shared chunks,
normal code splitting), and are addressed with a module::Page namespace.
Installation
npm install -D vite-plugin-inertia-modulesRequires Vite 5+ and an Inertia app (React, Vue, or Svelte — pages must use the same framework as the host).
Quick start
1. Declare the module in your package's composer.json:
{
"name": "acme/payments",
"extra": {
"inertia-modules": {
"module": "payments",
"pages": "resources/js/pages"
}
}
}2. Register the plugin in the host's vite.config.ts:
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import react from '@vitejs/plugin-react';
import inertiaModules from 'vite-plugin-inertia-modules';
export default defineConfig({
plugins: [
laravel({ input: ['resources/js/app.tsx'], refresh: true }),
inertiaModules(),
react(),
],
});3. Use the unified resolver in resources/js/app.tsx:
import { createInertiaApp } from '@inertiajs/react';
import { resolvePage } from 'virtual:inertia-modules';
createInertiaApp({
resolve: resolvePage, // handles both app pages and module pages
// ...
});Using SSR? Make the same swap in resources/js/ssr.tsx.
4. Render module pages from anywhere in your Laravel code:
Inertia::render('payments::Invoices/Index'); // from acme/payments
Inertia::render('Dashboard'); // regular app page, as alwaysThat's it. composer require a new module while npm run dev is running and
the browser reloads with its pages available.
How it works
The plugin reads vendor/composer/installed.json (Composer 2's authoritative
registry of installed packages) and collects every package that declares an
extra["inertia-modules"] manifest. It then exposes a virtual module —
virtual:inertia-modules — containing lazy import.meta.glob maps for the
app's pages and each module's pages, plus the resolvePage function that
routes module::Page names to the right loader.
Because everything goes through the host's Vite, you keep one React/Vue/Svelte
runtime, shared vendor chunks, per-page code splitting, and HMR — including
HMR for files inside vendor/.
Options
inertiaModules({
manifestKey: 'inertia-modules', // key under "extra" in composer.json
appPages: '/resources/js/pages', // host app pages (root-relative)
pages: 'resources/js/pages', // default pages dir inside packages
extensions: ['tsx', 'jsx'], // tried in order; e.g. ['vue'] or ['svelte']
virtualId: 'virtual:inertia-modules' // rename the virtual module if you like
});| Option | Default | Description |
| ------------- | -------------------------- | ---------------------------------------------------- |
| manifestKey | 'inertia-modules' | Key under extra that marks a package as a module |
| appPages | '/resources/js/pages' | Where the host app's own pages live |
| pages | 'resources/js/pages' | Default pages path inside packages (overridable per package via the manifest) |
| extensions | ['tsx', 'jsx'] | Page extensions, tried in order |
| virtualId | 'virtual:inertia-modules'| Id of the generated virtual module |
TypeScript
Add the bundled ambient types to your tsconfig.json:
{
"compilerOptions": {
"types": ["vite-plugin-inertia-modules/client"]
}
}If you customize virtualId, declare the module yourself using the same shape
as client.d.ts.
Writing a module package
- Pages go in
resources/js/pages(or wherever your manifest points). - Declare the host-provided libraries (
react,@inertiajs/react, your design system) aspeerDependencies— never bundle your own copy. - Backend concerns (routes, migrations, config) are regular Laravel package territory; this plugin only cares about pages.
- Local development with Composer path repositories works out of the box — symlinks are resolved and allowed in the dev server.
Caveats
- Module pages must use the same UI framework as the host app.
- Composer 2 is required (
vendor/composer/installed.json). - Pages are discovered at (re)build time; installing a module triggers a reload in dev, but adding files to a module's pages dir may require restarting the dev server in some setups.
