1413 字
7 分鐘
Laravel 11 起手架 - 一站式開發整合
Laravel 一站式開發整合
Laravel 在 PHP 中廣為熟知的框架,目前市佔應該佔了不小的面額, 本篇的目的如同該標題提及,整合成全家桶的樣子,需要經歷一些些改造。 在此紀錄上一些操作,避免日後可能有些忘記要全部重新查起。
此外,可能一些人認為整合在一起的優劣有所爭議,這邊不探討該問題。
期望導入的相關技術(許願池):
以下列導入的技術有順序性(只有前端),請若是不需要什麼,請由對應的步驟往回看,然後反著操作試試看。
- Laravel ! … [1]
- Frontend
- Tailwind CSS … [2]
- Vue3 … SPA [3]
- Vue Router … [4]
- Pinia … [5]
- Typescript … [6] … vue file 在 ts 無法正確解析問題
- Test … [7]
- Backend
- laravel-route-attributes … [8]
- Swagger(L5-Swagger) … [9]
- Test(Pest) … [10]
- PHP-CS-Fixer
- ⁉️ DevOps
- pre-commit
- Docker
- Ansible
BEGIN !
Unit 1. 建立 Laravel 專案 (請自行注意 PHP8.2 以上才能裝到 Laravel 11)
composer create-project laravel/laravel laravel-11-template --prefer-distUnit 2. Tailwind CSS
請到 Laravel 根目錄底下運行下列指令。
安裝依賴、並且產生 tailwind.config.js, postcss.config.js
npm install -D tailwindcss postcss autoprefixer # 安裝依賴
npx tailwindcss init -p # 產生 tailwind.config.js, postcss.config.js調整配置檔案(tailwind.config.js)
/** @type {import('tailwindcss').Config} */
export default {
content: [ // 這裏 --- begin
"./resources/**/*.blade.php",
"./resources/**/*.js",
"./resources/**/*.vue",
], // 到這裡 --- end
theme: {
extend: {},
},
plugins: [],
}調整 Laravel 框架內的 resources/css/app.css 檔案,新增 Tailwind 導向的 CSS
@tailwind base;
@tailwind components;
@tailwind utilities;啟動你的程式
npm run dev設定視圖,使 view 可以吃到最終產生出來的 CSS
@vite('resources/css/app.css')這段,會去將 vite 的 develop server 或是編譯結果放在這裡。
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
@vite('resources/css/app.css')
</head>
<body>
<h1 class="text-3xl font-bold underline text-blue-400">
Hello world!
</h1>
</body>
</html>Unit 3. Vue3
請到 Laravel 根目錄底下運行下列指令。
安裝依賴
npm install vue
npm install @vitejs/plugin-vue配置 vite.config.js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import vue from '@vitejs/plugin-vue' // 這裡也是新增的
export default defineConfig({
plugins: [
vue(), // 這裡是新增的
laravel({
input: ['resources/css/app.css', 'resources/js/app.js'],
refresh: true,
}),
],
});調整 resources/js/app.js,新增 resources/js/App.vue 檔案
// resources/js/app.js
import './bootstrap';
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount("#app")// resources/js/App.vue
<template>
<div class="text-blue-500 text-3xl">Hello App.vue</div>
</template>調整 Laravel View(welcome.blade.php) ,新增 @vite('resources/js/app.js')
<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Application</title>
@vite('resources/css/app.css')
</head>
<body>
<div id="app"></div>
@vite('resources/js/app.js')
</body>
</html>SPA Router -> 調整 routes/web.php
除去 api 前綴的路由,其他都往 welcome.blade.php 的 view 導過去。
use Illuminate\Support\Facades\Route;
Route::get('/{any}', fn () => view('welcome'))->where('any', '^(?!api).*$');Unit 4. Vue Router
npm install vue-router@4修改 Unit 3. 的 resources/js/app.js resources/js/App.vue,新建三個 resources/js/router.js, resources/js/Pages/About.vue, resources/js/Pages/Home.vue
About.vue,Home.vue自行在 template 標籤塞入字串即可,用於 Vue router 作用時辨識用是否導過去對應的 Vue 檔案。
// resources/js/router.js
import { createRouter, createWebHashHistory } from 'vue-router';
const routes = [
{ path: "/", component: () => import("./Pages/Home.vue") },
{ path: "/about", component: () => import("./Pages/About.vue") },
];
const router = createRouter({
history: createWebHashHistory(),
routes,
});
export default router;// resources/js/app.js
import './bootstrap';
import { createApp } from 'vue'
import App from './App.vue'
import router from './router';
const app = createApp(App);
app.use(router)
app.mount("#app")// resources/js/App.vue
<template>
<div class="flex gap-2 p-2">
<router-link to="/" class="bg-blue-500 text-white px-2 py-1 rounded">Home</router-link>
<router-link to="/about" class="bg-red-500 text-white px-2 py-1 rounded">About</router-link>
</div>
<router-view />
</template>Unit 5. Pinia
npm install pinia調整 resources/js/app.js,新增 resources/js/stores/counter.js
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
import router from './router';
const app = createApp(App)
.use(router)
.use(createPinia());
app.mount("#app")// resources/js/stores/counter.js
import { ref, computed } from 'vue';
import { defineStore } from 'pinia';
export const useCounterStore = defineStore('counter', () => {
const count = ref(0);
const doubleCount = computed(() => count.value * 2);
function increment() {
count.value++;
}
return { count, doubleCount, increment };
});<script setup>
// 選定你要用的頁面在引入,在 dev tool 應該就有看到 pinia 了
import { useCounterStore } from './stores/counter'
const store = useCounterStore()
</script>
<template>
<div>test pinia !</div>
</template>Unit 6. Typescript
安裝依賴
npm install -D typescript ts-loader
npm install -D @vue/tsconfig # 一些 ts 的設定檔(預設)對於自己調整 tsconfig.js 有些複雜,因此使用 @vue/tsconfig 來幫忙,先建立 tsconfig.json,內容如下
{
"extends": "@vue/tsconfig/tsconfig.json",
"include": [
"*.d.ts",
"resources/**/*.ts",
"resources/**/*.d.ts",
"resources/**/*.vue"
],
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["resources/js/*"]
},
"types": ["vite/client"],
"allowJs": false,
"strict": false
}
}將 js 改成 ts,並且進入的 view -> welcome.blade.php,更改 vite 載入的檔案, vite.config.js 也要調整
// resources/view/welcome.blade.php
// 原本: @vite('resources/js/app.js')
// 改成: @vite('resources/js/app.ts') // 將 laravel() 這裡面的 input:
// ['resources/css/app.css', 'resources/js/app.js'] 變成為下面這樣
// ['resources/css/app.css', 'resources/js/app.ts']當遇到報錯: 找不到模組 XXX.vue 或其相對應的類別宣告時:
該問題是因為 ts 認不得 vue 檔案。所以請在上述的 tsconfig.json 中的 include 這個陣列的位置中,隨意添加一個
.d.ts的檔案,然後在該檔案中加入以下內容:
// shims.d.ts
declare module "*.vue" {
import { ComponentOptions } from "vue";
const componentOptions: ComponentOptions;
export default componentOptions;
}Unit 7. Test
TODO
Unit 8. laravel-route-attribute
作用大概就是… 使用 PHP 8 的特性,使用 attribute 去定義路由,也就是說在 routes/ 資料夾看不到對應的 route, 而是透過 controller 的註解, Laravel 動態解析路由。
安裝,並且 vendor publish
composer require spatie/laravel-route-attributes
php artisan vendor:publish --provider="Spatie\RouteAttributes\RouteAttributesServiceProvider" --tag="config"調整 config/route-attributes.php
return [
/*
* Automatic registration of routes will only happen if this setting is `true`
*/
'enabled' => true,
/*
* Controllers in these directories that have routing attributes
* will automatically be registered.
*
* Optionally, you can specify group configuration by using key/values
*/
'directories' => [
// app_path('Http/Controllers'),
app_path('Modules') => [ // 這邊代表 app/Modules 的這個資料夾下面都會去做掃瞄,如果使用 #[Get()] 就會去註冊路由
'prefix' => 'api',
'middleware' => 'api',
// only register routes in files that match the patterns
'patterns' => ['*Controller.php'],
// do not register routes in files that match the patterns
'not_patterns' => [],
],
],
/**
* This middleware will be applied to all routes.
*/
'middleware' => [
\Illuminate\Routing\Middleware\SubstituteBindings::class
]
];寫一個測試用的,並且使用 php artisan route:list 觀察是否路由有正確出現
// app/Modules/List/Http/Controllers/IndexController.php
namespace App\Modules\List\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Spatie\RouteAttributes\Attributes\Get;
class IndexController extends Controller
{
#[Get('api/list', name: 'list.index')]
public function index()
{
return response()->json([
'message' => 'Hello from List Module!',
]);
}
}Unit 9. Swagger(L5-Swagger)
安裝 Swagger 來幫助我們產生 API 文件,方便前端人員查看。
composer require "darkaonline/l5-swagger"
php artisan vendor:publish --provider "L5Swagger\L5SwaggerServiceProvider"
php artisan l5-swagger:generateUnit 10. Test(Pest)
TODO
Unit 11. PHP-CS-Fixer
TODO

