Skip to content

Installation

The fastest way to get started with Viper is to generate a new application using our starter kit:

Terminal window
laravel new app --using=ozmos/viper-vue-shadcn
cd app && bun i && composer dev

Below are the instructions for installing Viper WITHOUT using a starter kit.

Create a new laravel app without existing templates/starter kits.

laravel new app

Install the Viper Laravel plugin as well as required dependencies

Terminal window
composer require ozmos/viper spatie/laravel-data spatie/typescript-transformer spatie/laravel-typescript-transformer tightenco/ziggy

Register the routes

routes/web.php
\Ozmos\Viper\Facades\Viper::routes();

Register the middleware

bootstrap/app.php
return Application::configure(basePath: dirname(__DIR__))
->withRouting(
// ...
)
->withMiddleware(function (Middleware $middleware) {
$middleware->web(
append: [\Ozmos\Viper\Middleware\HandleViperRequests::class]
);
})
->withExceptions(function (Exceptions $exceptions) {
// ...
})
->create();

Create the base layout file:

resources/views/app.blade.php
<html lang="en">
<head>
@viperHead
@routes
@vite(['resources/js/app.ts'])
</head>
<body>
@viper
</body>
</html>

Add the needed typescript transformer config

php artisan vendor:publish --provider="Spatie\LaravelTypeScriptTransformer\TypeScriptTransformerServiceProvider"
config/typescript-transformer.php
<?php
return [
// add the compiled path to type discovery
'auto_discover_types' => [app_path(), base_path('.viper/compiled')],
'collectors' => [
Spatie\TypeScriptTransformer\Collectors\DefaultCollector::class,
Spatie\TypeScriptTransformer\Collectors\EnumCollector::class,
// add the Viper collector
Ozmos\Viper\Collectors\PageCollector::class,
],
// optional but recommended, place the ts file in the js folder
'output_file' => resource_path('js/types/generated.d.ts'),
];

Install the required npm packages

Terminal window
bun add @ozmos/viper-vue @ozmos/vite-plugin-viper vue vue-router @tanstack/vue-query ziggy-js @vitejs/plugin-vue

Register the viper vite plugin BEFORE the vue plugin

vite.config.ts
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import tailwindcss from '@tailwindcss/vite';
import vue from '@vitejs/plugin-vue';
import viper from '../viper/packages/vite-plugin-viper/src/index';
export default defineConfig({
plugins: [
laravel({
input: ['resources/css/app.css', 'resources/js/app.ts'],
refresh: true,
}),
tailwindcss(),
viper(),
vue(),
],
});

Create your entry file resources/js/app.ts

import { createApp, h } from 'vue';
import { RouterView } from 'vue-router';
import { QueryClient, VueQueryPlugin } from '@tanstack/vue-query';
import { ViperPlugin } from '@ozmos/viper-vue';
import { router } from './pages/routes';
const queryClient = new QueryClient();
createApp({ render: () => h(RouterView) })
.use(router)
.use(VueQueryPlugin, { queryClient })
.use(ViperPlugin, {
router,
queryClient,
formatTitle: title => title || 'Laravel',
})
.mount(document.getElementById('app')!);

Create a stub pages/routes.ts file so that it doesn’t error during first build. This will get replaced once you run the vite server.

resources/js/pages/routes.ts
export const router = {};

Create your first page:

resources/js/pages/index.vue
<template>
<h1>My Viper App</h1>
<p>The server time is {{ serverTime }}</p>
</template>
<script setup lang="ts">
import { usePage } from '@ozmos/viper-vue';
const page = usePage<ViperGen.Index>();
const { data: serverTime } = page.useQuery('serverTime');
</script>
<php>
return new class {
#[\Ozmos\Viper\Attrs\Prop]
public function serverTime(): string
{
return now()->toIso8601String();
}
};
</php>

Now serve your app and head to localhost:8000

Terminal window
composer dev
# or separately run php artisan serve and vite

Make sure to generate the types! This has to be done after the vite server has started otherwise the .viper/ compiled folder won’t exist yet

Terminal window
php artisan typescript:transform