next-laravel-bridge
v1.1.1
Published
A complete NPM package for integrating Next.js with Laravel - Sanctum Authentication, form management, and centralized API configuration
Downloads
686
Maintainers
Readme
Next.js Laravel Bridge
A complete NPM package that facilitates integration between Next.js and Laravel, providing ready-to-use solutions for authentication, form management, API requests, pagination, uploads and more.
🚀 Features
🔐 Laravel Sanctum Authentication
- React Provider for authentication state management
useAuthhook for login/logout operations- New: ACL Support (
useGate,<Can>) for roles & permissions - Next.js Middleware to protect routes
withAuthandwithGuestHOCs for pages- SSR support with
getServerSideAuth
🔍 Query (React Query style)
useLaravelQuery- GET requests with automatic cachinguseLaravelMutation- POST/PUT/DELETE mutations- Automatic cache invalidation
- Automatic refetch (window focus, interval)
📄 Laravel Pagination
useLaravelPagination- Standard paginationuseCursorPagination- Cursor pagination (infinite scroll)- Complete navigation (next, prev, goTo)
📁 File Upload
useLaravelUpload- Simple upload with progressuseMultiUpload- Multiple parallel uploads- Validation (size, MIME type)
- Upload cancellation
🔔 Toast Notifications
NotificationProvider- Toast systemuseLaravelNotifications- Notification hook- Helpers:
success(),error(),warning(),info() - Customizable positions and durations
📡 Broadcasting (Laravel Echo)
EchoProvider- Laravel Echo ProvideruseChannel- Public channelsusePrivateChannel- Private channelsusePresence- Presence channels- Pusher and Soketi support
📝 Form Management
useLaravelForm- Hook for forms- Automatic Laravel validation error mapping
- Support for complex validations
🧪 Test Utilities
MockAuthProvider- Auth mock for tests- Helpers to mock Laravel API
- Test utilities (wait, waitFor, etc.)
📦 Installation
npm install next-laravel-bridgeOptional Dependencies
To use broadcasting (WebSockets):
npm install laravel-echo pusher-js1. Providers (App Router)
// app/providers.tsx
'use client';
import {
SanctumAuthProvider,
NotificationProvider,
} from 'next-laravel-bridge';
export function Providers({ children }: { children: React.ReactNode }) {
return (
<SanctumAuthProvider>
<NotificationProvider position="top-right">
{children}
</NotificationProvider>
</SanctumAuthProvider>
);
}
// app/layout.tsx
import { Providers } from './providers';
export default function RootLayout({ children }) {
return (
<html>
<body>
<Providers>{children}</Providers>
</body>
</html>
);
}2. API Configuration
import { LaravelApiClient } from 'next-laravel-bridge';
const apiClient = new LaravelApiClient({
baseURL: process.env.NEXT_PUBLIC_LARAVEL_API_URL,
});📖 Usage
Authentication
import { useAuth } from 'next-laravel-bridge';
function LoginForm() {
const { login, isLoading, user, logout } = useAuth();
const handleSubmit = async (e) => {
e.preventDefault();
await login({ email, password });
};
if (user) {
return <button onClick={logout}>Logout</button>;
}
return <form onSubmit={handleSubmit}>...</form>;
}Page Protection
// With HOC
import { withAuth } from 'next-laravel-bridge';
function DashboardPage() {
return <div>Protected Dashboard</div>;
}
export default withAuth(DashboardPage, {
redirectTo: '/login',
requiredRoles: ['admin'],
});// With Middleware (middleware.ts)
import { createAuthMiddleware } from 'next-laravel-bridge';
export default createAuthMiddleware({
protectedRoutes: ['/dashboard', '/profile/*'],
loginRoute: '/login',
publicRoutes: ['/', '/about'],
});Access Control (ACL)
import { useGate, Can } from 'next-laravel-bridge';
function AdminPanel() {
const { can, hasRole } = useGate();
return (
<div>
<h1>Admin Panel</h1>
{/* Component Way */}
<Can ability="edit-posts" else={<p>Access Denied</p>}>
<button>Edit Posts</button>
</Can>
{/* Hook Way */}
{hasRole('admin') && (
<button>Delete User</button>
)}
{can('view-reports') && (
<ReportsComponent />
)}
</div>
);
}Requests with Cache
import { useLaravelQuery, useLaravelMutation } from 'next-laravel-bridge';
function UserList() {
const { data: users, isLoading, refetch } = useLaravelQuery({
endpoint: '/api/users',
params: { page: 1 },
cacheTime: 5 * 60 * 1000, // 5 minutes
});
const { mutate: createUser } = useLaravelMutation({
endpoint: '/api/users',
method: 'POST',
invalidateQueries: ['/api/users'],
onSuccess: () => alert('User created!'),
});
return (
<div>
{users?.map(user => <UserCard key={user.id} user={user} />)}
<button onClick={() => createUser({ name: 'John' })}>
Add
</button>
</div>
);
}Pagination
import { useLaravelPagination } from 'next-laravel-bridge';
function PostList() {
const {
data: posts,
currentPage,
lastPage,
nextPage,
prevPage,
goToPage,
isLoading
} = useLaravelPagination({
endpoint: '/api/posts',
perPage: 10,
});
return (
<div>
{posts.map(post => <PostCard key={post.id} post={post} />)}
<div>
<button onClick={prevPage} disabled={currentPage === 1}>
Previous
</button>
<span>{currentPage} / {lastPage}</span>
<button onClick={nextPage} disabled={currentPage === lastPage}>
Next
</button>
</div>
</div>
);
}File Upload
import { useLaravelUpload } from 'next-laravel-bridge';
function FileUploader() {
const { upload, progress, isUploading, error, result } = useLaravelUpload({
endpoint: '/api/files',
maxSize: 10 * 1024 * 1024, // 10MB
allowedTypes: ['image/*', 'application/pdf'],
onSuccess: (response) => console.log('Uploaded:', response.url),
});
return (
<div>
<input
type="file"
onChange={(e) => e.target.files?.[0] && upload(e.target.files[0])}
/>
{isUploading && <progress value={progress} max="100" />}
{error && <p className="error">{error.message}</p>}
</div>
);
}Notifications
import { useLaravelNotifications } from 'next-laravel-bridge';
function MyComponent() {
const { success, error, notify } = useLaravelNotifications();
const handleSave = async () => {
try {
await saveData();
success('Data saved!', 'Success');
} catch (e) {
error('An error occurred', 'Error');
}
};
// Advanced notification
const handleAdvanced = () => {
notify({
type: 'info',
title: 'New update',
message: 'A new version is available',
duration: 0, // Permanent
action: {
label: 'Update',
onClick: () => updateApp(),
},
});
};
}Broadcasting (WebSockets)
import { EchoProvider, useChannel, usePresence } from 'next-laravel-bridge';
// Provider
function App() {
return (
<EchoProvider
config={{
driver: 'pusher',
key: process.env.NEXT_PUBLIC_PUSHER_KEY,
cluster: 'eu',
authEndpoint: '/api/broadcasting/auth',
}}
>
<ChatRoom />
</EchoProvider>
);
}
// Component
function ChatRoom() {
const { events, isConnected } = useChannel('chat-room', {
'message.new': (message) => console.log('New:', message),
});
const { members } = usePresence('room.1');
return (
<div>
<p>Status: {isConnected ? '🟢 Connected' : '🔴 Disconnected'}</p>
<p>Users online: {members.length}</p>
</div>
);
}🔧 Laravel Configuration
// app/Http/Kernel.php
protected $middlewareGroups = [
'api' => [
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
// ...
],
];
// config/cors.php
'paths' => ['api/*', 'sanctum/csrf-cookie', 'broadcasting/auth'],
'supports_credentials' => true,📁 Package Structure
src/
├── api/ # Laravel API Client
├── auth/ # Sanctum Authentication
├── forms/ # Form Management
├── query/ # React Query style requests
├── pagination/ # Laravel Pagination
├── upload/ # File Upload
├── notifications/ # Toast System
├── broadcasting/ # Laravel Echo / WebSockets
├── ssr/ # SSR Support
├── testing/ # Test Utilities
└── utils/ # Helpers and constants🧪 Tests
npm run test # Run tests
npm run test:watch # Watch mode
npm run test:coverage # With coverage📚 Documentation
Full documentation is available at next-laravel-bridge.vercel.app.
📄 License
MIT © Jourdan Totonde
