As web development continues to evolve, developers often find themselves needing to migrate applications between different stacks to meet modern project requirements. One common scenario is converting a Node.js theme (typically based on EJS, Pug, or Handlebars) into a full-stack Laravel application using Vue.js and Inertia.js.
This comprehensive guide will walk you through how to take an existing Node.js theme and convert it into a clean, component-based Laravel + Vue + Inertia.js application. We’ll cover everything from preparing your Laravel project to restructuring your front-end components for modern, maintainable code.
📌 Why Convert From Node.js to Laravel + Vue + Inertia?
Here are a few reasons you might want to switch:
- Separation of concerns: Laravel offers a robust backend while Vue handles a reactive, modern frontend.
- Inertia.js: Bridges Laravel and Vue beautifully, enabling single-page app (SPA) experiences without the complexity of building an API.
- Better developer tools: Laravel provides great tooling out of the box like Eloquent ORM, Blade components, Laravel Mix/Vite, and more.
- Maintainability: Vue components offer a more modular structure than traditional server-rendered templates.
🛠 Step 1: Understand Your Node.js Theme Structure
Before converting, audit your existing Node.js project.
Your directory might look like:
/views
├─ layout.ejs
├─ home.ejs
├─ partials/
├─ header.ejs
├─ footer.ejs
/public
├─ css/
├─ js/
├─ images/
Take note of:
- Page layouts and structure
- How routes are defined
- Dynamic data being injected (e.g.,
<%= user.name %>) - Front-end assets (Bootstrap, jQuery, etc.)
⚙️ Step 2: Set Up Laravel with Vue and Inertia
Start by installing a fresh Laravel project.
composer create-project laravel/laravel laravel-inertia-app
cd laravel-inertia-app
Install Laravel Breeze with Vue + Inertia:
composer require laravel/breeze --dev
php artisan breeze:install vue
npm install && npm run dev
php artisan migrate
You now have:
- Laravel backend
- Vue.js frontend
- Inertia.js integration for SPA-like behavior
🧩 Step 3: Set Up the Directory Structure
In Laravel:
- Vue components go in:
resources/js/Components - Pages go in:
resources/js/Pages - Layouts can go in:
resources/js/Layouts
Create basic folders if needed:
mkdir -p resources/js/Components resources/js/Pages resources/js/Layouts
📥 Step 4: Convert Your HTML Templates into Vue Components
Let’s say your home.ejs contains:
<%- include('partials/header') %>
<h1>Welcome <%= user.name %></h1>
<%- include('partials/footer') %>
You can convert this to a Vue + Inertia page:
resources/js/Layouts/Layout.vue
<template>
<div>
<Header />
<main><slot /></main>
<Footer />
</div>
</template>
<script setup>
import Header from '../Components/Header.vue'
import Footer from '../Components/Footer.vue'
</script>
resources/js/Pages/Home.vue
<template>
<Layout>
<h1>Welcome {{ user.name }}</h1>
</Layout>
</template>
<script setup>
import Layout from '../Layouts/Layout.vue'
defineProps({ user: Object })
</script>
📁 Step 5: Move CSS, JS, and Images
Move public assets from your Node.js project into the Laravel structure.
- CSS →
resources/css/ - JavaScript →
resources/js/ - Images →
public/images/
Import any CSS in resources/js/app.js:
import '../css/theme.css';
If you’re using Bootstrap or another framework:
npm install bootstrap
Then include it:
import 'bootstrap/dist/css/bootstrap.min.css';
🧠 Step 6: Migrate Dynamic Logic
Convert template logic (like EJS or Pug) into Vue syntax.
EJS example:
<% if (user.isAdmin) { %>
<p>Admin Panel</p>
<% } %>
Vue equivalent:
<p v-if="user.isAdmin">Admin Panel</p>
EJS loop:
<ul>
<% items.forEach(function(item) { %>
<li><%= item.name %></li>
<% }); %>
</ul>
Vue loop:
<ul>
<li v-for="item in items" :key="item.id">{{ item.name }}</li>
</ul>
🌐 Step 7: Create Routes and Controllers in Laravel
Define a route that returns an Inertia page:
routes/web.php
use Inertia\Inertia;
Route::get('/', function () {
return Inertia::render('Home', [
'user' => Auth::user()
]);
});
Create controllers for more complex logic:
Route::get('/dashboard', [DashboardController::class, 'index']);
In your controller:
public function index()
{
return Inertia::render('Dashboard', [
'user' => Auth::user(),
'data' => SomeModel::all()
]);
}
📝 Step 8: Handling Forms and POST Requests
Using Inertia and Vue, forms are simple and reactive.
Example Form:
<template>
<form @submit.prevent="submit">
<input v-model="form.name" type="text" />
<button type="submit">Submit</button>
</form>
</template>
<script setup>
import { useForm } from '@inertiajs/vue3'
const form = useForm({ name: '' })
const submit = () => {
form.post('/submit')
}
</script>
Laravel Route:
Route::post('/submit', function () {
// Handle form logic
});
🔔 Step 9: Flash Messages & Validation
Laravel automatically flashes session messages.
Backend:
return redirect('/')->with('success', 'Form submitted successfully!');
Vue Page:
<p v-if="$page.props.flash.success">{{ $page.props.flash.success }}</p>
To handle validation errors, Inertia will return them and make them available via form.errors.
🧱 Step 10: Modularize Your UI
Split your UI into reusable Vue components like:
Navbar.vueSidebar.vueUserCard.vue
Place them in resources/js/Components and reuse them as needed:
<Navbar />
<UserCard :user="user" />
This makes your Laravel + Vue theme scalable and easy to maintain.
🧪 Bonus Tips
- Use Laravel Mix or Vite (default from Laravel 9+) for asset bundling.
- Use Inertia middleware to share global data like authenticated user, flash messages, etc.
- If migrating from a CMS-based Node.js app, consider using Laravel’s Blade if needed for email templates or fallback rendering.
✅ Final Thoughts
Migrating a theme from Node.js to Laravel + Vue.js + Inertia may seem daunting at first, but once you break it down:
- You get a clean separation of logic and UI
- You benefit from Laravel’s robust backend features
- Vue.js provides a modern, reactive frontend
- Inertia makes routing and data-sharing seamless
Advantages of Laravel + Vue + Inertia:
- No need for separate API + SPA codebases
- Less boilerplate than REST or GraphQL APIs
- Smooth developer experience
Whether you’re moving to Laravel for better backend capabilities or standardizing on a PHP stack, this conversion is a worthwhile investment.
📣 Want to Learn More?
Let me know if you’d like a downloadable boilerplate or GitHub example repo!

Leave a Reply