Files
wehub-resource-sync a6e8bcde90
Check asset sync / cli/assets must match src/ui-ux-pro-max (push) Failing after 4s
Release / Semantic release (push) Has been skipped
Smoke test data / smoke (push) Failing after 0s
chore: import upstream snapshot with attribution
2026-07-13 11:58:17 +08:00

18 KiB

1NoCategoryGuidelineDescriptionDoDon'tCode GoodCode BadSeverityDocs URL
21Blade TemplatesUse Blade components for reusable UIExtract repeated markup into named Blade componentsUse x-* components with @props for all reusable UIDuplicate HTML blocks across views<x-card :title="$title">{{ $slot }}</x-card>@include('card' ['title' => $title])Highhttps://laravel.com/docs/blade#components
32Blade TemplatesUse layouts with @extends and @sectionDefine one master layout and extend it per page@extends layout with named @section blocksDuplicate header/footer HTML in every view@extends('layouts.app') @section('content')Full HTML in every view fileHighhttps://laravel.com/docs/blade#layouts-using-template-inheritance
43Blade TemplatesUse @props for component type-safetyDeclare accepted props inside components with @props@props with defaults to document component APIPass arbitrary variables without declaration@props(['title' => '' 'variant' => 'primary'])No @props declaration in componentMediumhttps://laravel.com/docs/blade#component-data-and-attributes
54Blade TemplatesUse conditional CSS classes with @classBuild class strings conditionally without ternary noise@class directive for conditional class bindingString concatenation or nested ternaries@class(['btn' 'btn-primary' => $primary 'btn-disabled' => $disabled])class="btn {{ $primary ? 'btn-primary' : '' }}"Mediumhttps://laravel.com/docs/blade#conditional-classes-and-styles
65Blade TemplatesUse named slots for flexible layoutsNamed slots let callers inject content into specific regions@slot('header') and $slot for flexible component APIsHard-code all sub-sections inside components<x-modal><x-slot:header>Title</x-slot>Body</x-modal><x-modal title="Title">Body with no slot control</x-modal>Mediumhttps://laravel.com/docs/blade#slots
76Blade TemplatesUse Blade directives instead of raw PHPBlade directives are readable and IDE-supported@if @foreach @forelse @empty instead of <?php ?>Raw PHP tags inside Blade templates@forelse($items as $item) ... @empty <p>None</p> @endforelse<?php foreach($items as $item): ?>Highhttps://laravel.com/docs/blade#blade-directives
87Blade TemplatesEscape output with {{ }}Use double curly braces for XSS-safe output{{ }} for all user-supplied or dynamic text{!! !!} for untrusted data{{ $user->name }}{!! $user->name !!}Highhttps://laravel.com/docs/blade#displaying-data
98Blade TemplatesUse @vite for asset loadingVite integration handles cache busting and HMR automatically@vite(['resources/css/app.css' 'resources/js/app.js'])Manual script/link tags with hardcoded paths@vite(['resources/css/app.css' 'resources/js/app.js'])<link href="/css/app.css?v=123">Highhttps://laravel.com/docs/vite
109LivewireBind inputs with wire:modelTwo-way data binding keeps component state in syncwire:model for all form inputs managed by LivewireManual JavaScript listeners syncing to component<input wire:model="email"><input @change="$wire.email = $event.target.value">Highhttps://livewire.laravel.com/docs/properties
1110LivewireUse wire:model.live for real-time validationValidate on input rather than only on submitwire:model.live + #[Validate] for instant feedbackOnly validate on form submit<input wire:model.live="email"> with #[Validate('email')]<input wire:model="email"> with validate() on submit onlyMediumhttps://livewire.laravel.com/docs/validation
1211LivewireUse wire:click for actionsBind UI events to component methods cleanlywire:click for buttons and interactive elementsJavaScript fetch calls replicating Livewire actions<button wire:click="save">Save</button><button onclick="fetch('/save')">Save</button>Highhttps://livewire.laravel.com/docs/actions
1312LivewireUse lifecycle hooks appropriatelymount() for init; updated() for reactive side effectsmount() for initialization updatedFoo() for property changesHeavy logic in render() or __construct()public function mount(): void { $this->items = Item::all(); }public function render(): View { $this->items = Item::all(); }Mediumhttps://livewire.laravel.com/docs/lifecycle-hooks
1413LivewireUse lazy loading for heavy componentsDefer render of expensive components until visiblewire:init or lazy attribute on componentsLoad all Livewire components on page load<livewire:analytics-chart lazy /><livewire:analytics-chart /> with heavy DB queries on mountMediumhttps://livewire.laravel.com/docs/lazy
1514LivewireIntegrate Alpine.js for local UI stateUse Alpine.js for UI-only state that doesn't need server round-tripsx-data / x-show / x-transition for tooltips dropdownsLivewire server calls for purely visual toggle state<div x-data="{ open: false }"><button @click="open = !open"><button wire:click="toggleDropdown"> for a local dropdownMediumhttps://livewire.laravel.com/docs/alpine
1615LivewireUse wire:loading for feedbackAlways indicate to users when a server action is in progresswire:loading.attr="disabled" and wire:loading elementsProvide no feedback while Livewire request is in flight<button wire:click="save" wire:loading.attr="disabled">Save</button><button wire:click="save">Save</button> with no loading stateHighhttps://livewire.laravel.com/docs/wire-loading
1716LivewireHandle file uploads with WithFileUploadsLivewire's trait manages chunked upload and temp storageWithFileUploads trait + wire:model for file inputsManual multipart form submissions for Livewire pagesuse WithFileUploads; public $photo; <input wire:model="photo" type="file"><form action="/upload" method="POST" enctype="multipart/form-data">Mediumhttps://livewire.laravel.com/docs/uploads
1817Inertia.jsUse Inertia page components as route endpointsEach page is a Vue/React component rendered server-side via Inertia::render()Inertia::render('Dashboard' ['data' => $data]) in controllersReturn JSON and fetch from JavaScriptreturn Inertia::render('Users/Index' ['users' => $users]);return response()->json($users); with client-side fetchHighhttps://inertiajs.com/responses
1918Inertia.jsShare global data via HandleInertiaRequestsMiddleware share() provides auth user and flash to every pageShare auth/flash in HandleInertiaRequests middlewarePass auth to every Inertia::render() callpublic function share(Request $r): array { return ['auth' => ['user' => $r->user()]]; }Inertia::render('Page' ['auth' => auth()->user()]) every controllerHighhttps://inertiajs.com/shared-data
2019Inertia.jsUse <Link> for client-side navigationInertia Link intercepts clicks for SPA-like transitions<Link href="/dashboard"> instead of <a href>Regular <a> tags for internal navigation<Link href={route('dashboard')}>Dashboard</Link><a href="/dashboard">Dashboard</a>Highhttps://inertiajs.com/links
2120Inertia.jsUse useForm for form state and submissionInertia's useForm manages progress errors and transformsuseForm for all page-level forms, form.post() for submitAxios/fetch for form submissions on Inertia pagesconst form = useForm({ name: '' }); form.post('/users');axios.post('/users', { name });Highhttps://inertiajs.com/forms
2221Inertia.jsUse persistent layouts to preserve stateWrap pages in a persistent layout so header/sidebar don't remountlayout property on page component for persistent UIRe-render full layout on every page visitMyPage.layout = (page) => <AppLayout>{page}</AppLayout>No layout — full page reload feel on navigationMediumhttps://inertiajs.com/pages#persistent-layouts
2322Inertia.jsEnable SSR for public pagesServer-side rendering improves SEO and first paintEnable Inertia SSR for marketing and public pagesClient-only rendering for all pages including publicphp artisan inertia:start-ssr with @inertiaHeadNo SSR on pages requiring good SEOMediumhttps://inertiajs.com/server-side-rendering
2423StylingSet up Tailwind CSS via ViteUse Vite + tailwindcss plugin for fast HMR and optimized buildsInstall tailwindcss @tailwindcss/vite and configure vite.config.jsLaravel Mix or manual PostCSS pipeline for new projectsplugins: [tailwindcss()] in vite.config.js + @import 'tailwindcss' in app.cssLaravel Mix with require('tailwindcss') in webpackHighhttps://tailwindcss.com/docs/installation/framework-guides
2524StylingPurge unused styles via content configTailwind scans Blade and JS files to tree-shake unused classescontent: ['./resources/views/**/*.blade.php', './resources/js/**/*.{js,vue}']No content config — ship all 3MB of CSScontent: ['./resources/**/*.blade.php', './resources/**/*.js']content: []Highhttps://tailwindcss.com/docs/content-configuration
2625StylingUse dark mode class strategyclass-based dark mode integrates with server-rendered preferencedarkMode: 'class' with a toggle that sets class on <html>Media query only — no user override possibledarkMode: 'class'; document.documentElement.classList.toggle('dark')darkMode: 'media' — no programmatic controlMediumhttps://tailwindcss.com/docs/dark-mode
2726StylingUse @apply sparingly in component CSSExtract only truly repeated multi-class patterns@apply for BEM base classes shared across many components@apply for every single element — defeats Tailwind's purpose@apply flex items-center gap-2 (shared button base)@apply text-sm for a single useLowhttps://tailwindcss.com/docs/functions-and-directives#apply
2827StylingConfigure custom design tokens in CSSDefine brand colors spacing fonts as CSS variables consumed by TailwindCustom @theme tokens matched to brand guidelinesMagic color hex codes scattered across Blade templates@theme { --color-brand: oklch(0.6 0.2 250); }bg-[#1a2b3c] inline throughout templatesMediumhttps://tailwindcss.com/docs/theme
2928ComponentsUse anonymous Blade components for UI primitivesBlade files in resources/views/components/ auto-register as x-* componentsAnonymous components for buttons alerts badges cardsBlade @includes for anything reusable<x-badge variant="success">Active</x-badge>@include('partials.badge' ['variant' => 'success'])Mediumhttps://laravel.com/docs/blade#anonymous-components
3029ComponentsUse class-based components for complex logicPHP class components can inject services and pre-process dataapp/View/Components/ class when component needs PHP logicBlade @php blocks for business logic inside templatesclass AlertComponent { public function __construct(public string $type) {} }@php $color = $type === 'error' ? 'red' : 'green'; @endphpMediumhttps://laravel.com/docs/blade#components
3130ComponentsForward extra attributes with $attributesPass through HTML attributes like class id aria to root element$attributes->merge() on root element of componentsIgnore caller-provided HTML attributes silently<div {{ $attributes->merge(['class' => 'btn']) }}><div class="btn"> — drops extra class/id from callerHighhttps://laravel.com/docs/blade#component-attributes
3231ComponentsSeparate variant logic from templatesKeep variant/size/color logic in a PHP class or helper not in BladeVariant class or match() expression in component classLong @if chains for variants inside Blade templatespublic function classes(): string { return match($this->variant) { 'primary' => 'bg-blue-600', } }@if($variant === 'primary') bg-blue-600 @elseif($variant === 'secondary')...Mediumhttps://laravel.com/docs/blade#components
3332ComponentsProvide default slot contentUse {{ $slot ?? '' }} or named slot defaults so components are usable emptyDefault content in slots for optional regionsRequire every slot to be filled — throws errors on empty usage{{ $icon ?? '' }} in component Blade file{{ $icon }} — fatal if caller omits slotLowhttps://laravel.com/docs/blade#slots
3433ComponentsUse component namespacing for packagesPrefix third-party or module components to avoid collisionsRegister custom prefix via Blade::componentNamespace()Mix first-party and package component names with no prefixBlade::componentNamespace('Modules\\Shop\\Views' 'shop'); <x-shop::product-card /><x-product-card /> colliding with first-party cardLowhttps://laravel.com/docs/blade#manually-registering-components
3534FormsValidate with Form Request classesMove validation rules out of controllers into dedicated FormRequest classesphp artisan make:request and define rules() + authorize()Inline validate() in controller actionsclass StorePostRequest extends FormRequest { public function rules() { return ['title' => 'required|max:255']; } }public function store(Request $r) { $r->validate(['title' => 'required']); }Highhttps://laravel.com/docs/validation#form-request-validation
3635FormsPreserve old input on validation failureUse old() to repopulate form fields after server-side error redirectold('field') as default value on all form inputsEmpty form fields when validation fails<input name="email" value="{{ old('email') }}"><input name="email">Highhttps://laravel.com/docs/validation#repopulating-forms
3736FormsDisplay validation errors with @errorUse the @error directive for inline field-level error messages@error('field') to show per-field messagesDump $errors->all() in one block at top of form@error('email') <p class="text-red-500">{{ $message }}</p> @enderror@foreach($errors->all() as $e) {{ $e }} @endforeachMediumhttps://laravel.com/docs/validation#quick-displaying-the-validation-errors
3837FormsUse CSRF token on all formsCSRF protection is enabled by default — include @csrf in every form@csrf in every POST/PUT/PATCH/DELETE formDisable VerifyCsrfToken middleware for convenience<form method="POST">@csrf ...<form method="POST"> without @csrfHighhttps://laravel.com/docs/csrf
3938FormsUse method spoofing for PUT/PATCH/DELETEHTML forms only support GET/POST — use @method for REST actions@method('PUT') inside form for update/delete routesRoute::post for all mutations including updates<form method="POST">@csrf @method('PUT')<form method="POST" action="/users/update">Mediumhttps://laravel.com/docs/routing#form-method-spoofing
4039FormsDisplay flash messages consistentlyFlash success/error in controller; read in layout with session()session('status') in layout for global flash displayRe-query DB or pass flash from every controller individually@if(session('success')) <div class="alert">{{ session('success') }}</div> @endifif($user) return back()->with(['user' => $user]);Mediumhttps://laravel.com/docs/session#flash-data
4140PerformanceEager load relationships to prevent N+1Always eager load related models used in views with with()with() in queries before passing collections to viewsLazy-load relations inside Blade loopsUser::with('posts' 'avatar')->get()User::all() then @foreach $user->posts in BladeHighhttps://laravel.com/docs/eloquent-relationships#eager-loading
4241PerformanceCache rendered Blade fragmentsUse cache() helper to wrap expensive rendered partialscache() around slow partials that change infrequentlyRe-render identical content on every request@php echo cache()->remember('sidebar' 3600 fn() => view('sidebar')->render()); @endphp{{ view('sidebar')->render() }} on every page loadMediumhttps://laravel.com/docs/cache
4342PerformancePaginate large data setsAlways paginate collections in list views->paginate() or ->simplePaginate() with {{ $items->links() }}->get() for large tables in viewsUser::paginate(20) with <x-pagination :links="$users" />User::all() passed to BladeHighhttps://laravel.com/docs/pagination
4443PerformanceQueue slow background tasksOffload emails notifications and heavy processing to queuesDispatch jobs for anything taking >200msBlock HTTP request with slow operationsProcessImage::dispatch($file); return back();Storage::put(); Mail::send(); Image::resize(); in controllerHighhttps://laravel.com/docs/queues
4544PerformanceUse route model bindingLaravel resolves models automatically — avoids manual find()Type-hint model in controller methodManual User::findOrFail($id) in every methodpublic function show(User $user): View { return view('users.show' compact('user')); }public function show($id) { $user = User::findOrFail($id); }Mediumhttps://laravel.com/docs/routing#route-model-binding
4645PerformanceEnable HTTP response caching for static contentCache control headers for pages that rarely changeCache-Control headers via middleware for public pagesNo caching — serve every response freshresponse()->view('home')->header('Cache-Control', 'public, max-age=3600')No cache headers on marketing pagesMediumhttps://laravel.com/docs/responses#response-headers
4746SecurityEscape all output in Blade{{ }} auto-escapes HTML — never use {!! !!} on user data{{ }} for all untrusted or dynamic content{!! !!} for user-controlled strings{{ $comment->body }}{!! $comment->body !!}Highhttps://laravel.com/docs/blade#displaying-data
4847SecurityProtect routes with Gate and PolicyUse policies for authorization — never inline permission checks in views@can / Gate::allows() for UI visibility; policy()->authorize() for actionsHardcode role checks inline across templates@can('update' $post) <a href="{{ route('posts.edit' $post) }}">Edit</a> @endcan@if(auth()->user()->role === 'admin') <a href="/edit">Highhttps://laravel.com/docs/authorization#policies
4948SecurityValidate and authorize file uploadsCheck MIME type size and store outside public rootStore in storage/app/private + validate mimes and maxStore raw upload in public/ without validation'avatar' => ['required' 'image' 'mimes:jpg,png' 'max:2048']'avatar' => 'required' with no MIME or size checkHighhttps://laravel.com/docs/filesystem#file-uploads
5049SecurityUse signed URLs for temporary linksGenerate expiring URLs for private downloads or email confirmationsURL::signedRoute() or temporarySignedRoute()Expose sequential IDs in download URLs without authURL::temporarySignedRoute('file.download' now()->addMinutes(30) ['file' => $id])route('file.download' $id) with no expiry or signatureHighhttps://laravel.com/docs/urls#signed-urls
5150SecuritySet a strict Content Security PolicyCSP headers prevent XSS injection of external scriptsspatie/laravel-csp or custom middleware to emit CSP headerNo CSP — browser runs any injected scriptHeader: Content-Security-Policy: default-src 'self'; script-src 'self'No Content-Security-Policy header on responsesMediumhttps://laravel.com/docs/middleware