Styling — Dark Theme

Website Rebuild with Laravel

Chapter 5 · Styling — Dark Theme

Django Rebuild 5 had no bundler at all — staticfiles just serves plain files, exactly as written. Next.js bundles CSS as an inseparable part of the framework's own build system. Laravel lands on neither extreme: composer create-project already installed and pre-configured a real, independent tool — Vite — without folding bundling into Laravel itself. A genuine third position, not a compromise between the other two.

The @vite Directive

{{-- resources/views/layouts/base.blade.php --}} <head> @vite(['resources/css/app.css']) </head>

Django's own {% static %} tag points at a plain, unprocessed file — served exactly as it sits on disk. @vite points at a source file that genuinely gets processed — Sass, PostCSS, autoprefixing, and (in development) live hot-reloading are all real, available capabilities the moment they're needed, not something bolted on afterward.

vite.config.js: Already Generated, Nothing to Set Up

// vite.config.js — generated automatically by composer create-project import { defineConfig } from 'vite'; import laravel from 'laravel-vite-plugin'; export default defineConfig({ plugins: [ laravel({ input: ['resources/css/app.css', 'resources/js/app.js'], refresh: true, }), ], });
The central fact this chapter is built on
Next.js's own bundler is invisible — baked into the framework's build system, no separate config file most projects ever touch. Django ships nothing at all — staticfiles genuinely has no bundling concept. Laravel does neither: it hands you a real, independently-maintained tool, already wired up and ready, but never claims to be that tool itself. vite.config.js existing as its own real, separate file — not hidden inside Laravel's own internals — is the visible proof of that distinction.

A Real Gotcha: Two Processes Running at Once, in Development

# Terminal 1 — the PHP application itself php artisan serve # Terminal 2 — the Vite dev server, genuinely required for @vite to resolve anything npm run dev
Forgetting npm run dev breaks the page, not just the styling
In development, @vite doesn't read a static file at all — it connects to a running Vite dev server on its own port, expecting a live process to actually answer. Forget to start npm run dev, and there's nothing there to connect to: the page can show a connection error, or fail to load any asset at all, not just a missing stylesheet. This is a genuinely different failure shape from Django Rebuild 5's own DEBUG=False gotcha — Django's problem only appears in production, once a specific setting flips; Laravel's version can happen on literally the very first day of local development, the moment one of two required processes isn't running.

Production: npm run build and the Manifest

npm run build # Generates public/build/manifest.json plus versioned, hashed asset files # @vite now reads that manifest directly — no dev server involved, or expected, at all

This is Laravel's own direct parallel to Django Rebuild 11's forward-referenced collectstatic step — a real, necessary build action that has to happen as part of deployment, not something to discover was missing after the site is already live.

The Stylesheet: The Same Palette, a Third Time

/* resources/css/app.css */ :root { --bg: #0f1117; --surface: #161b22; --border: #30363d; --text: #c9d1d9; --accent: #FF6B57; } body.dark-theme { background: var(--bg); color: var(--text); font-family: system-ui, sans-serif; }

The same background, surface, border, and text colors from Chapter 5 of both sibling courses, reused here for the third and final time in this "same site, three frameworks" trilogy — deliberate continuity, not repetition for its own sake. A visitor moving between any of the three shouldn't be able to tell which one they're looking at.

Hands-On Exercises

Exercise 1

Explain the genuine three-way difference in asset bundling between Next.js, Django, and Laravel. Is Laravel "a bundler" the same way Next.js is? Why or why not?

📄 View solution
Exercise 2

Explain why forgetting to run npm run dev alongside php artisan serve breaks the page's assets, and how this failure differs in timing from Django's own DEBUG=False static-file gotcha.

📄 View solution
Exercise 3

Explain what changes about how @vite resolves its assets between development (with npm run dev running) and production (after npm run build has already executed).

📄 View solution

Chapter 5 Quick Reference

  • A genuine third position — Next.js bundles by framework design, Django has no bundler at all, Laravel ships a real separate tool (Vite) pre-wired, without being one itself
  • @vite([...]) — points at real source files, genuinely processed, unlike Django's {% static %} serving plain files as-is
  • vite.config.js — already generated by composer create-project, nothing to set up manually
  • Two processes in developmentphp artisan serve and npm run dev both required; forgetting the second breaks the page immediately, not just in production
  • npm run build — generates the production manifest @vite reads instead of a dev server; Laravel's own parallel to Django's collectstatic
  • The same palette, a third time — deliberate visual continuity across all three rebuild courses and the live site itself
  • Next chapter: The Database: Eloquent ORM