สร้างเว็บด้วย 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 เรียกใช้งานกัน คอยติดตามนะครับผม

ใส่ความเห็น

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