torann/device-view
Laravel package that detects the visitor's device type and serves different views for mobile, tablet, and desktop. Register device-specific view paths and fall back cleanly when no matching view exists. Small and config-driven.
Architecture fit
torann/device-view is a thin capability, not a framework: it decorates Laravel's view finder so view('pages.home') resolves to a device-suffixed variant, wrapping a UA classifier to sort clients into mobile/tablet/desktop. Architecturally that is the right shape for a TPM's purposes — it enables dynamic serving (one URL, one route, one controller, divergent Blade markup) without touching controller code. The fit is only strong if the product has genuinely divergent template sets. If the mobile delta is a handful of CSS classes, responsive CSS is cheaper, better for caching, better for SEO, and simpler to test — and this package is net-negative. Treat the responsive-vs-device-specific call as the decision this evaluation is for; everything else here is downstream of it.
Integration feasibility
Feasible and small: install with an exact pin (0.0.4, not a caret — on a 0.0.x line a caret is effectively a pin that never floats), register DeviceViewServiceProvider manually in config/app.php (Laravel 5.4 predates auto-discovery), publish and read the config, then prove the resolution works before adopting it anywhere. The proof is concrete: hit app('view')->getFinder()->find('welcome'), read the absolute path, spoof an iPhone UA, confirm the path changes, then repeat under php artisan config:cache. That last step matters — packages of this vintage routinely call env() outside config/*.php and only break in a cached production deploy.
Technical risk The risk is lifecycle and failure-mode visibility, not complexity.
^0.0.4 will never float onto a modern framework. This is a legacy-estate artifact.view.finder (theming, multi-tenant template overrides) interacts with this in an order you did not choose.Key questions
DeviceViewResolver interface instead of depending? (This is the honest default answer; BSD-2-Clause permits vendoring with the license notice retained.)Vary: User-Agent and device-aware cache keys?Stack fit Laravel 5.4 / PHP 5.x–7.x era. No auto-discovery, no modern constraint resolution. If the app is on 5.5+, remove the manual provider entry in the same commit as the upgrade or you get double registration. If the app is on 6+, do not adopt — vendor the pattern instead.
Migration path
Build or vendor; do not depend. The capability is a view-finder hook plus a suffix and a view()->exists() check. One engineer replicates it in a day or two behind an internal interface:
interface DeviceViewResolver {
public function device(): string; // 'mobile' | 'tablet' | 'desktop'
public function view(string $base): string;
}
Bind it in AppServiceProvider and delegate to the package initially. Replacement then becomes a one-file change rather than an archaeology project. If you adopt the package first, record the exact version and a replacement date in the dependency register on day one — a caret constraint on 0.0.x guarantees nothing will tell you when it has become dead weight.
Compatibility
Verify explicitly, because these fail only on mobile and only in production: namespaced views (view('vendor::home') with a suffix inserted in the wrong place), view()->first([...]), view composers registered against layouts.app not firing for layouts.app.mobile, and @include routing through the same finder (useful — you get partials/nav.mobile free — and dangerous, since a stray file named like a variant changes behaviour globally). Also confirm the dot-notation convention: view('home.mobile') maps to home/mobile.blade.php, making a variant file and a nested directory indistinguishable. Establish which the finder resolves before structuring directories around it.
Sequencing
config:cache.Torann\....layouts.app.mobile; every page inherits the device shell. One file per device class, tiny QA surface. Escalate to per-page variants only for the two or three pages whose module lists genuinely diverge (mobile-lite checkout, reduced nav).Vary: User-Agent middleware, a desktop escape hatch (cookie/query param that pins resolution — a product requirement the package does not provide), cache-key verification at the CDN, and the variant audit command in CI.Maintenance The package itself is near-zero maintenance because it is frozen — which is also the problem. There is no upgrade cadence to track and no upstream to escalate to; the maintenance burden is entirely yours the moment a framework upgrade or a PHP version bump forces a change. The real ongoing cost is template multiplicity: every affected page now has up to three variants to maintain and translate. Budget that explicitly — it is a 2–3x QA-surface decision for those pages, not a package-installation decision.
Support
Single maintainer, dormant since January 2017, zero dependents. There is no support channel with any expectation of response. Plan on self-support: read src/ end to end (it is small; do not skim it), because the changelog is one line and the README will not tell you the resolution order. Keep the two debugging one-liners — app('view')->getFinder()->find('pages.home') and app('view')->exists('pages.home.mobile') — exposed behind if (app()->environment('local')) on a single route rather than sprinkling dd().
Scaling
Scaling risk is concentrated in caching, not compute. Same URL serving different HTML means the CDN must key on User-Agent (or the device cookie) and the origin must emit Vary: User-Agent. If the product depends on aggressive full-page caching and the CDN keys on URL alone, the value proposition shrinks and may go net-negative — stop there. Template count scales the QA and localization surface roughly linearly with pages touched; the layout-swap strategy keeps that multiplier around 2x instead of 3x. Tablet classification will not scale reliably at all — modern iPads will generally resolve to desktop.
Failure modes (ranked by cost to detect)
device !== 'desktop' && ! view()->exists($variant) at warning level and running an artisan audit command in CI with an explicit allow-list of intentionally desktop-only pages. The allow-list matters: fail on unexpected gaps only.env() outside config breaking only under config:cache. Caught by testing cached config on day one.php artisan view:clear; watch for stale finder hints and opcache on the views path producing "it worked in staging" reports.if ($mobile) in a controller, you have paid the dependency cost and received nothing — that is a scope-discipline failure, and worth reviewing for.Ramp-up
Low technical ramp-up, moderate process ramp-up. One engineer can understand the whole surface in an afternoon; the interface wrapper should be the first artifact written. The process ramp-up is where the time goes: an SEO owner must sign off on dynamic serving (content parity on revenue and indexable pages, correct Vary header, mobile-first-indexing implications), and the QA matrix needs at least one feature test per device class per critical page with an explicit UA — the test client's default UA silently resolves to desktop, so unexercised mobile tests will pass green without ever touching the path. Three template trees drift; drift on a money page is expensive. Frame adoption as a tactical scoping lever with an expiry date on the roadmap — "ship the three revenue-critical modules on mobile now, decide on redesign later" — not as a platform decision, and sequence nothing else around it.
How can I help you explore Laravel packages today?