สร้างเว็บด้วย Laravel 9 + Vue 3 + Inertiajs + bootstrap5 ทำงานได้ดีเยี่ยม

Sharing is caring!

หวนคืนนึกถึง Php ที่คุ้นเคย Laravel ที่ยังเคยใช้งานเมื่อยังมีแค่เวอร์ชั่น 7 แค่นั้น และปัจจุบันมีถึง 10 เวอร์ชั่นเข้าไปแล้ว มีเหตุให้ต้องคิดถึงเครื่องมือเหล่านี้ พอดีได้เริ่มติดตั้ง และทดลองใช้งาน เลยอยากที่จะบันทึกไว้เป็นไกไลด์สำหรับใช้ทำในครั้งถัด ๆ ไป เอาแบบพอใช้งานได้ โดย

  • Laravel 9 ขึ้นไปเพราะต้องการกำหนด PHP เวอร์ชั่นต่ำคือ PHP8 ในการรันโปรเจคนี้
  • Vue3 เพราะความรวดเร็วในการพัฒนา (เลือกที่ตัวเองถนัด)
  • Inertia.js สารารถสร้างแอป React, Vue และ Svelte หน้าเดียวที่ทันสมัยโดยใช้การกำหนดเส้นทางฝั่งเซิร์ฟเวอร์แบบคลาสสิก ใช้งานได้กับแบ็กเอนด์ใดๆ ยังสามารถใช้งานกับ Laravel ได้อย่างดีเยี่ยม
  • Bootstrap เลือกใช้เพราะความคุ้นเคย

เมื่อทราบเหตุผล เรามาเริ่มกันเลยดีกว่า

เริ่มติดตั้งเฟรมเวิร์ค และไลบารี่ ต่าง ๆ ที่จำเป็น

เริ่มต้นให้ทำการติดตั้ง PHP สำหรับใช้ในการรัน Laravel โปรเจค และอย่าลืมติดตั้ง NodeJs และ NPM ให้พร้อม

  • ติดตั้ง PHP เวอร์ชั่น 8 ขึ้นไป (mac os ก็ติดตั้งด้วย `brew install [email protected]`, window os ติดตั้งตากที่นี่ https://www.php.net/manual/en/install.windows.php)
  • ติดตั้ง NodeJS และ NPM เป็นเวอร์ชั่นล่าสุดไปเลย
  • ติดตั้ง Composer

หลังจากเตรียมพวกซอพแวร์หลัก เรียบร้อยถึงเวลาไปสร้างโปรเจคกัน

  • เริ่มต้นที่ Laravel
composer create-project laravel/laravel:^9.0 new-project-name
  • ติดตั้ง Inertia เพิ่มเติม และสร้าง Inertia middleware
composer require inertiajs/inertia-laravel

php artisan inertia:middleware

จะได้ไฟล์ HandleInertiaRequests.php อยู่ภายใต้ app/Http/Middleware ให้ทำการเพิ่มคำสั่ง

'web' => [
    // ...
    \App\Http\Middleware\HandleInertiaRequests::class,
],

เข้าไปที่ไฟล์ app/Http/Kernel.php

ติดตั้งแพ็คเกต ด้วย NPM

  • Inertia และ Vue3
npm install @inertiajs/vue3 vue-loader vue --save-dev
  • bootstrap 5
npm install @popperjs/core bootstrap --save-dev
  • laravel-mix เพื่อเอาไว้ compile minify js, css
npm install laravel-mix --save-dev
  • เกี่ยว css
npm install postcss postcss-import --save-dev
  • แก้ไขปรับแต่ง scripts ในไฟล์ package.json
"scripts": {
        "dev": "npm run development",
        "development": "mix",
        "watch": "mix watch",
        "watch-poll": "mix watch -- --watch-options-poll=1000",
        "hot": "mix watch --hot",
        "prod": "npm run production",
        "production": "mix --production"
    },
  • หน้าตาของไฟล์ package.json ทั้งหมด
{
    "private": true,
    "scripts": {
        "dev": "npm run development",
        "development": "mix",
        "watch": "mix watch",
        "watch-poll": "mix watch -- --watch-options-poll=1000",
        "hot": "mix watch --hot",
        "prod": "npm run production",
        "production": "mix --production"
    },
    "devDependencies": {
        "@popperjs/core": "^2.9.2",
        "autoprefixer": "^10.4.16",
        "axios": "^1.1.2",
        "bootstrap": "^5.3.2",
        "laravel-mix": "^6.0.11",
        "lodash": "^4.17.19",
        "postcss": "^8.4.31",
        "postcss-import": "^12.0.1",
        "vue": "^3.2.36",
        "vue-loader": "^17.3.0",
        "@inertiajs/vue3": "^1.0.13"
    },
    "dependencies": {
        "mix": "0.0.1"
    }
}

เพิ่ม และแก้ไขโค๊ด ส่วนการตั้งค่าของ webpack.mix.js

  • ให้ทำการสร้างไฟล์ /webpack.mix.js
const path = require("path");
const mix = require("laravel-mix");

// Rezolve Ziggy
mix.alias({
    ziggy: path.resolve("vendor/tightenco/ziggy/dist/vue"),
});

// Build files
mix.js("resources/js/app.js", "public/js")
    .vue({ version: 3 })
    .webpackConfig({
        resolve: {
            alias: {
                "@": path.resolve(__dirname, "resources/js"),
            },
        },
    })
    .extract()
    .postCss("resources/css/app.css", "public/css", []) //require("bootstrap")
    .version();
  • สร้างไฟล์ /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">

  @routes

  <link href="{{ asset(mix('css/app.css')) }}" rel="stylesheet">

  <script src="{{ asset(mix('js/manifest.js')) }}" defer></script>

  <script src="{{ asset(mix('js/vendor.js')) }}" defer></script>

  <script src="{{ asset(mix('js/app.js')) }}" defer></script>

  @inertiaHead

</head>

<body>

  @inertia

</body>

</html>
  • แก้ไขไฟล์ /resources/js/app.js
import { createApp, h } from "vue";
import { createInertiaApp, Link, Head } from "@inertiajs/vue3";

import { ZiggyVue } from "ziggy";
import { Ziggy } from "./ziggy";

createInertiaApp({
    resolve: async (name) => {
        return (await import(`./Pages/${name}`)).default;
    },
    setup({ el, App, props, plugin }) {
        createApp({ render: () => h(App, props) })
            .use(plugin)
            .use(ZiggyVue, Ziggy)
            // .component("Link", Link)
            // .component("Head", Head)
            .mixin({ methods: { route } })
            .mount(el);
    },
    progress: {
        color: '#29d',
    },
});
  • เพิ่ม bootstrap ทั้ง css และ js
// /resources/css/app.css
@import 'bootstrap/dist/css/bootstrap.min.css';

// /resources/js/bootstrap.js
import "bootstrap";
  • สร้าง layout ด้วย inertia /resources/js/Components/Layout.vue
<script setup>
import { Link } from '@inertiajs/vue3'
</script>

<template>
  <main>
    <nav class="navbar navbar-expand-lg navbar-dark bg-primary" style="background-color:#e3f2fd;">
      <div class="container-fluid">
        <div class="collapse navbar-collapse" id="navbarNav">
          <ul class="navbar-nav">
            <li class="nav-item">
              <Link class="nav-link active" aria-current="page"  href="/">Home</Link>
            </li>
            <li class="nav-item">
              <Link class="nav-link active" aria-current="page"  href="/about">About</Link>
            </li>
            <li class="nav-item">
              <Link class="nav-link active" aria-current="page"  href="/contact">Contact</Link>
            </li>
          </ul>
        </div>
      </div>
    </nav>
    <article>
      <slot />
    </article>
  </main>
</template>
  • สร้างหน้าเว็บ 3 หน้า ด้วยโค๊ด Vue /resources/js/Pages/Home.vue, /resources/js/Pages/About.vue, /resources/js/Pages/Contact.vue,
// /resources/js/Pages/Home.vue
<script>
import Layout from '../Components/Layout.vue'

export default {
  // Using a render function...
  layout: (h, page) => h(Layout, [page]),

  // Using shorthand syntax...
  layout: Layout,
}
</script>

<template>
    <h1>Homepage</h1>
</template>

// /resources/js/Pages/Contact.vue

<script>
import Layout from '../Components/Layout.vue'

export default {
  // Using a render function...
  layout: (h, page) => h(Layout, [page]),

  // Using shorthand syntax...
  layout: Layout,
}
</script>

<template>
    <h1>Contact</h1>
</template>
/ /resources/js/Pages/About.vue

<script>
import Layout from '../Components/Layout.vue'

export default {
  // Using a render function...
  layout: (h, page) => h(Layout, [page]),

  // Using shorthand syntax...
  layout: Layout,
}
</script>


<template>
    <h1>About</h1>
</template>
  • ทำการแก้ไข /routes/web.php route ของทั้ง 3 หน้าเว็บ
<?php

use Illuminate\Support\Facades\Route;
use Inertia\Inertia;

Route::get('/',function () {
        return Inertia::render(
            'Home',['title' => 'Homepage',]
        );
    }
)->name( 'homepage' );

Route::get('/about',function () {
        return Inertia::render(
            'About',['title' => 'About',]
        );
    }
)->name( 'about' );

Route::get('/contact',function () {
        return Inertia::render(
            'Contact',['title' => 'Contact',]
        );
    }
)->name( 'contact' );

รัน และทดสอบ

เราจะทำการรันคำสั่ง 2 คำสั่งคือ

  • php artisan serve เพื่อ start server ด้วย port :8000
  • npm run watch เพื่อสั่ง laravel mix ให้ compile js และ css แบบเรียวไทม์ทันที
// start server with 8000
php artisan serve

// start compile js, css with watch behavior
php run watch

ผลลัพธ์หลังจากรันคำสั่ง

สรุปท้ายบทความ

วิธีการขั้นตอนเหล่านี้ จะมีความยุ่งยากสักนิด แต่รับรองว่าเมื่อใช้งานไปแล้วสนุกแน่นอน สำหรับคนใดที่ถนัด react, svelt เป็นต้น inertiajs. ก็ยัง support ให้ใช้งานโดยไม่ยุ่งยากเลย ครั้งหน้าจะมาลองเขียนโค๊ดทำ APIs ให้ Vue เรียกใช้งานกัน คอยติดตามนะครับผม

Leave a Reply

อีเมลของคุณจะไม่แสดงให้คนอื่นเห็น ช่องข้อมูลจำเป็นถูกทำเครื่องหมาย *