Inertia.js: "Monolith" Hiện Đại – Đỉnh cao của Full-stack Laravel
Lavarel

Inertia.js: "Monolith" Hiện Đại – Đỉnh cao của Full-stack Laravel

Author

Admin System

@root

Ngày xuất bản

20 Mar, 2026

Lượt xem

2 Lượt

Inertia_JS

Chào các "thợ code" tương lai và các "lão làng" đang tìm kiếm những công cụ mới! Hôm nay, Giảng viên Creyt sẽ cùng các bạn "mổ xẻ" một "viên ngọc" trong thế giới lập trình full-stack, đó là Inertia.js. Hãy quên đi những cuộc tranh cãi bất tận giữa SPA và MPA, Inertia.js sẽ đưa chúng ta đến một chân trời mới – nơi mà bạn có thể có cả hai! Nó giống như một chiếc xe hybrid vậy, vừa mạnh mẽ, tiết kiệm nhiên liệu của động cơ đốt trong, lại vừa êm ái, thân thiện môi trường của động cơ điện. Tuyệt vời phải không?

Inertia.js là gì và để làm gì?

Nói một cách dễ hiểu nhất, Inertia.js là một "bộ điều hợp" (adapter) thần kỳ cho phép bạn xây dựng ứng dụng đơn trang (Single Page Application - SPA) mà không cần phải viết API. Nghe có vẻ "phi lý" đúng không? Nhưng đó chính là điều Inertia.js làm được!

Thường thì, để có một SPA mượt mà, bạn sẽ cần:

  1. Backend (ví dụ: Laravel): Xây dựng một đống API RESTful hoặc GraphQL để cung cấp dữ liệu.
  2. Frontend (ví dụ: Vue, React, Svelte): Xây dựng toàn bộ giao diện, gọi API, quản lý trạng thái, định tuyến client-side, v.v...

Điều này dẫn đến hai vấn đề lớn:

  • API Fatigue (Mệt mỏi với API): Bạn phải thiết kế, xây dựng, bảo trì một bộ API riêng biệt, rồi lại viết code frontend để tiêu thụ chúng. Giống như bạn phải nấu hai bữa ăn riêng biệt cho cùng một người vậy – tốn công sức gấp đôi.
  • Context Switching (Chuyển đổi ngữ cảnh): Bạn phải liên tục chuyển đổi tư duy giữa backend (PHP, cơ sở dữ liệu) và frontend (JavaScript, cấu trúc component). Não bộ của chúng ta đâu phải là siêu máy tính đâu, đúng không?

Inertia.js ra đời để giải quyết bài toán này. Nó cho phép bạn sử dụng bộ định tuyến (routing) và bộ điều khiển (controller) của Laravel như thể bạn đang trả về các trang HTML truyền thống, nhưng thực tế, nó lại trả về các component JavaScript! Khi bạn click vào một đường link Inertia, thay vì tải lại toàn bộ trang, Inertia sẽ gửi một yêu cầu XHR (Ajax) đến server, server trả về một JSON chứa dữ liệu (props) và tên component cần render, sau đó Inertia sẽ tự động cập nhật giao diện mà không cần reload trang. Voilà! Bạn có một SPA mượt mà mà vẫn giữ được sự đơn giản của kiến trúc "monolith" truyền thống. Đó là lý do tôi gọi nó là "Monolith hiện đại" – mạnh mẽ của SPA nhưng đơn giản của MPA.

Illustration

Code Ví Dụ Minh Họa: Inertia.js với Laravel và Vue 3

Để các bạn dễ hình dung, chúng ta hãy cùng nhau xây dựng một ví dụ đơn giản với Laravel và Vue 3 nhé. Giả sử chúng ta muốn hiển thị danh sách các bài viết.

Bước 1: Cài đặt Inertia vào dự án Laravel

Đầu tiên, bạn cần cài đặt các gói cần thiết cho Laravel:

composer require inertiajs/inertia-laravel
php artisan inertia:middleware

Sau khi chạy php artisan inertia:middleware, một file HandleInertiaRequests.php sẽ được tạo trong app/Http/Middleware. Bạn cần đăng ký middleware này trong app/Http/Kernel.php:

// app/Http/Kernel.php

protected $middlewareGroups = [
    'web' => [
        // ... các middleware khác
        \App\Http\Middleware\HandleInertiaRequests::class,
    ],

    'api' => [
        // ...
    ],
];

Tiếp theo, tạo file Blade gốc mà Inertia sẽ "neo" vào. File này thường là resources/views/app.blade.php:

<!-- resources/views/app.blade.php -->
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">

        <title>Laravel Inertia</title>

        @vite(['resources/js/app.js', 'resources/css/app.css'])
        @inertiaHead
    </head>
    <body>
        @inertia
    </body>
</html>

Bước 2: Cài đặt Frontend (Vue 3)

Cài đặt các gói JavaScript cần thiết (đảm bảo bạn đã có Node.js và npm/yarn):

npm install @inertiajs/vue3 vue @vitejs/plugin-vue
npm install

Cập nhật file vite.config.js để hỗ trợ Vue:

// vite.config.js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import vue from '@vitejs/plugin-vue';

export default defineConfig({
    plugins: [
        laravel({
            input: ['resources/css/app.css', 'resources/js/app.js'],
            refresh: true,
        }),
        vue({
            template: {
                transformAssetUrls: {
                    base: null,
                    includeAbsolute: false,
                },
            },
        }),
    ],
});

Khởi tạo Inertia trong resources/js/app.js:

// resources/js/app.js
import './bootstrap';
import '../css/app.css';

import { createApp, h } from 'vue';
import { createInertiaApp } from '@inertiajs/vue3';
import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers';

createInertiaApp({
    title: (title) => `${title} - My App`,
    resolve: (name) => resolvePageComponent(`./Pages/${name}.vue`, import.meta.glob('./Pages/**/*.vue')),
    setup({ el, App, props, plugin }) {
        createApp({ render: () => h(App, props) })
            .use(plugin)
            .mount(el);
    },
    progress: {
        color: '#4B5563',
    },
});

Bước 3: Tạo Controller và Component Vue

Tạo Controller (Laravel):

// app/Http/Controllers/PostController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Inertia\Inertia;

class PostController extends Controller
{
    public function index()
    {
        // Giả lập dữ liệu bài viết
        $posts = [
            ['id' => 1, 'title' => 'Bài viết 1', 'content' => 'Nội dung bài viết thứ nhất'],
            ['id' => 2, 'title' => 'Bài viết 2', 'content' => 'Nội dung bài viết thứ hai'],
            ['id' => 3, 'title' => 'Bài viết 3', 'content' => 'Nội dung bài viết thứ ba'],
        ];

        // Trả về component Vue 'Posts/Index' với dữ liệu $posts
        return Inertia::render('Posts/Index', [
            'posts' => $posts,
            'appName' => config('app.name'),
        ]);
    }

    public function show($id)
    {
        $post = ['id' => $id, 'title' => 'Bài viết ' . $id, 'content' => 'Đây là nội dung chi tiết của bài viết ' . $id];
        return Inertia::render('Posts/Show', [
            'post' => $post,
        ]);
    }
}

Tạo Routes (Laravel):

// routes/web.php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\PostController;

Route::get('/', function () {
    return Inertia::render('Welcome');
});

Route::get('/posts', [PostController::class, 'index'])->name('posts.index');
Route::get('/posts/{id}', [PostController::class, 'show'])->name('posts.show');

Tạo Component Vue (Frontend):

Tạo thư mục resources/js/Pages và các file Welcome.vue, Posts/Index.vue, Posts/Show.vue.

<!-- resources/js/Pages/Welcome.vue -->
<script setup>
import { Head, Link } from '@inertiajs/vue3';

defineProps({
    appName: String,
});
</script>

<template>
    <Head title="Welcome" />
    <div class="container">
        <h1>Chào mừng đến với {{ appName }}!</h1>
        <p>Đây là trang chào mừng của ứng dụng Inertia Laravel.</p>
        <p>
            <Link :href="route('posts.index')">Xem danh sách bài viết</Link>
        </p>
    </div>
</template>

<style scoped>
.container {
    max-width: 800px;
    margin: 50px auto;
    padding: 20px;
    border: 1px solid #eee;
    border-radius: 8px;
    box-shadow: 0 2px 4px rgba(0,0,0,0.1);
    text-align: center;
}
h1 {
    color: #333;
}
p {
    color: #666;
    line-height: 1.6;
}
a {
    color: #007bff;
    text-decoration: none;
}
a:hover {
    text-decoration: underline;
}
</style>
<!-- resources/js/Pages/Posts/Index.vue -->
<script setup>
import { Head, Link } from '@inertiajs/vue3';

defineProps({
    posts: Array,
    appName: String,
});
</script>

<template>
    <Head title="Danh sách bài viết" />
    <div class="container">
        <h1>{{ appName }} - Danh sách Bài viết</h1>
        <ul>
            <li v-for="post in posts" :key="post.id">
                <Link :href="route('posts.show', post.id)">{{ post.title }}</Link>
            </li>
        </ul>
        <p>
            <Link :href="route('welcome')">Quay lại trang chủ</Link>
        </p>
    </div>
</template>

<style scoped>
.container {
    max-width: 800px;
    margin: 50px auto;
    padding: 20px;
    border: 1px solid #eee;
    border-radius: 8px;
    box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
h1 {
    color: #333;
    text-align: center;
}
ul {
    list-style: none;
    padding: 0;
}
li {
    margin-bottom: 10px;
    background-color: #f9f9f9;
    padding: 10px 15px;
    border-radius: 5px;
}
li a {
    color: #007bff;
    text-decoration: none;
    font-weight: bold;
}
li a:hover {
    text-decoration: underline;
}
</style>
<!-- resources/js/Pages/Posts/Show.vue -->
<script setup>
import { Head, Link } from '@inertiajs/vue3';

defineProps({
    post: Object,
});
</script>

<template>
    <Head :title="post.title" />
    <div class="container">
        <h1>{{ post.title }}</h1>
        <p>{{ post.content }}</p>
        <p>
            <Link :href="route('posts.index')">Quay lại danh sách</Link>
        </p>
    </div>
</template>

<style scoped>
.container {
    max-width: 800px;
    margin: 50px auto;
    padding: 20px;
    border: 1px solid #eee;
    border-radius: 8px;
    box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
h1 {
    color: #333;
    text-align: center;
}
p {
    color: #666;
    line-height: 1.6;
}
a {
    color: #007bff;
    text-decoration: none;
}
a:hover {
    text-decoration: underline;
}
</style>

Chạy ứng dụng:

php artisan serve
npm run dev

Bây giờ, khi bạn truy cập http://127.0.0.1:8000/, bạn sẽ thấy trang chào mừng. Khi click vào "Xem danh sách bài viết", trang sẽ chuyển đổi mượt mà mà không reload toàn bộ trang! Đó chính là phép màu của Inertia.js.

Mẹo (Best Practices) để ghi nhớ hoặc dùng thực tế

  1. "Controller là vua, Component là quân sư": Hãy giữ cho logic nghiệp vụ nằm trong controller Laravel. Controller sẽ quyết định dữ liệu nào cần lấy, xử lý form, và trả về component nào với props tương ứng. Component chỉ đơn thuần là hiển thị dữ liệu và xử lý tương tác UI nhỏ. Đừng cố gắng nhét logic phức tạp vào component nếu nó thuộc về backend.
  2. Chia sẻ dữ liệu toàn cục (Shared Data): Inertia cho phép bạn chia sẻ dữ liệu cho tất cả các component mà không cần truyền thủ công qua từng Inertia::render(). Hãy dùng Inertia::share() trong HandleInertiaRequests middleware để chia sẻ những thứ như thông tin người dùng đang đăng nhập, cài đặt ứng dụng, hoặc flash messages. Nó giống như việc bạn "treo bảng thông báo chung" ở sảnh chính vậy, ai đi qua cũng có thể đọc được.
  3. Partial Reloads (Tải lại một phần): Đây là một tính năng cực kỳ hữu ích. Thay vì tải lại toàn bộ props của trang, bạn có thể chỉ định chỉ tải lại một số props nhất định khi có thay đổi (ví dụ: sau khi gửi form tìm kiếm hoặc filter). Điều này giúp tối ưu hiệu suất đáng kể, đặc biệt với các trang có nhiều dữ liệu. Hãy hình dung bạn chỉ thay đổi một món ăn trên bàn tiệc chứ không phải dọn dẹp và bày lại toàn bộ bàn.
  4. Form Handling "Thần thánh": Inertia cung cấp các helper useForm (Vue) hoặc useForm (React) giúp quản lý trạng thái form, validation errors và loading states một cách dễ dàng. Hãy tận dụng chúng để có trải nghiệm người dùng mượt mà và code sạch sẽ.
  5. Giữ cho các Component đơn giản: Vì Laravel controller đã xử lý logic chính, các component frontend của bạn có thể tập trung hoàn toàn vào việc hiển thị và tương tác UI. Điều này giúp component dễ đọc, dễ bảo trì và dễ tái sử dụng hơn.
  6. Sử dụng Link Component: Luôn sử dụng component <Link> của Inertia thay vì thẻ <a> HTML truyền thống để đảm bảo việc chuyển trang diễn ra mượt mà như SPA. Khi bạn dùng <a>, trình duyệt sẽ reload toàn bộ trang, làm mất đi lợi ích của Inertia.

Ứng dụng/Website đã ứng dụng Inertia.js

Inertia.js, dù không phải là một "gã khổng lồ" như React hay Vue, nhưng đã được rất nhiều dự án và công ty nhỏ đến vừa tin dùng vì sự hiệu quả và đơn giản của nó. Nó đặc biệt được yêu thích trong cộng đồng Laravel.

  • Internal Tools & Dashboards: Các ứng dụng quản lý nội bộ, dashboard admin, nơi mà trải nghiệm người dùng mượt mà là quan trọng nhưng không cần sự phức tạp của một kiến trúc microservice hoặc API độc lập hoàn toàn. Laravel Nova (một công cụ quản trị của Laravel) cũng sử dụng Inertia ở một mức độ nào đó để cung cấp giao diện tương tác.
  • SaaS Products (Sản phẩm phần mềm dịch vụ): Nhiều startup và công ty SaaS nhỏ đã chọn Inertia.js để xây dựng các ứng dụng của họ nhanh chóng, tận dụng tốc độ phát triển của Laravel và trải nghiệm người dùng tốt của SPA.
  • Marketing Websites với tính năng tương tác: Các trang web giới thiệu sản phẩm, dịch vụ cần có các phần tương tác như form, lọc dữ liệu, nhưng vẫn muốn giữ SEO tốt (nhờ server-side rendering ban đầu) và đơn giản trong việc triển khai.
  • Các dự án cá nhân và Freelance: Với khả năng giảm thiểu sự phức tạp, Inertia.js là lựa chọn tuyệt vời cho các nhà phát triển độc lập muốn xây dựng ứng dụng full-stack nhanh chóng mà không phải "vật lộn" với việc xây dựng và bảo trì API.

Inertia.js thực sự là một "người bạn" đắc lực cho những ai muốn có tốc độ phát triển của một ứng dụng monolith truyền thống nhưng vẫn khao khát trải nghiệm người dùng mượt mà, nhanh nhẹn của một SPA. Hãy thử và cảm nhận sự "nhẹ nhõm" mà nó mang lại nhé!

Thuộc Series: Lavarel

Bài giảng này được tự động xuất bản ngẫu nhiên từ thư viện kiến thức. Đừng quên đón xem các Từ khoá Hướng Dẫn tiếp theo nhé!

#tech #cyberpunk #laravel
Chỉnh sửa bài viết

Bình luận (0)

Vui lòng Đăng Nhập để Bình luận

Hỗ trợ Markdown cơ bản
Nguyễn Văn A
1 ngày trước

Tính năng này đỉnh quá ad ơi, chờ mãi mới thấy một blog Tiếng Việt có UI/UX xịn như vầy!