Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Spotlight Laravel Package

cswni/spotlight

Spotlight is a Laravel package that adds fast, keyboard-driven search to your application. Register searchable resources, query across models, and surface results through a clean, customizable interface, with sensible defaults and full control over ranking and display.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install and pin. composer require cswni/spotlight:^1.0. This is the first stable tag, so pin the major version explicitly rather than relying on dev-main or a loose constraint — you want a predictable surface while the 1.x line settles.
  2. Publish everything, then read it. Run php artisan vendor:publish --provider="Cswni\Spotlight\SpotlightServiceProvider" without a --tag first. That lists every publishable group (config, assets, migrations, views) in one pass, so you know what the package expects to own before you start overriding things.
  3. Read config/spotlight.php end to end. In packages of this shape the config file is the API — sources, key bindings, result limits, and UI toggles usually live there rather than in a fluent builder. Read it before writing a single line of integration code.
  4. Skim the service provider. Look specifically for register() bindings and container singletons you can swap() in tests, plus any route or Blade/Livewire component registration. That tells you the extension points and whether the front end is server-rendered or asset-driven.
  5. First use case: one source, end to end. Register a single searchable source (typically a model or a closure returning a result set), open the palette, confirm results render and the click/keyboard action navigates correctly. Resist adding five sources before the first one round-trips — most early failures are front-end wiring, not source logic.
  6. Then wire the trigger. Confirm the global keyboard shortcut and/or the @stack/component include actually lands in your layout. This is the single most common "it doesn't work" report on first install.

Implementation Patterns

Source registration. Two idioms are worth checking for on day one: a config-array style ('sources' => [Model::class, ...]) and a programmatic style called from a service provider (Spotlight::register(...)). Prefer the config array for static, always-on sources and the programmatic call for anything that needs runtime context (the current tenant, the authenticated user, feature flags). Don't mix both for the same source — you'll get duplicates that are annoying to trace.

Grouped result sets. Structure output by source rather than as one flat list. Users navigate a palette by category ("Customers", "Orders", "Commands"), and grouping also gives you a natural place to cap results per source so one noisy model can't crowd out everything else.

Authorization belongs in the source, not the UI. Filter by Gate/policy or a tenant scope inside the source closure. Hiding results client-side leaks titles and URLs through the JSON payload — assume the response is fully readable by anyone who can hit the endpoint.

Action-per-result. Model the result as {title, subtitle, url} for navigation and a separate action for anything mutating. Keep mutating actions behind a confirmation and a POST route; if the package's default action handler performs a redirect from a GET, add a form-based confirm step rather than trusting the shortcut.

Front-end integration. If the UI is Livewire/Alpine, mount the component in your persistent layout (not a page-level view) so the shortcut works everywhere, and check that the package's JS is registered once — double-inclusion from both a @stack push and a published asset is a classic source of duplicate event listeners.

Testing. Bind a fake source in setUp() via the container rather than hitting real models; assert on the JSON/Inertia payload shape, not on rendered markup. Add one browser-level test for the shortcut, because the payload tests won't catch a missing asset include.

Gotchas and Tips

  • No documented 0.x → 1.0 path. The 1.0.0 notes are just a changelog link. Before adopting, read the commits since the last 0.x tag for renamed config keys and changed method signatures — nothing will tell you at runtime, since config keys silently fall back to defaults.
  • Config caching. After editing config/spotlight.php, run php artisan config:clear (or config:cache in the deploy step). A stale cached config is the number one cause of "my new source isn't showing up."
  • Publish-tag guessing. Always --provider=... first to enumerate tags. Guessing --tag=spotlight-assets when it's actually spotlight-frontend wastes more time than it saves.
  • N+1 in sources. A source that loads a model and renders $model->relation->name will fire a query per row. with() eagerly, and cap results before hydrating, not after.
  • Debounce and rate-limit. The palette fires on every keystroke. Put a client-side debounce in front of the request and a throttle middleware behind it; server-side throttling also protects you from accidental LIKE '%x%' scans on large tables.
  • Large-table LIKE search. If sources query your own tables, add the index or move to a full-text/whereFullText path early. A palette that takes 800ms feels broken even when it's correct.
  • Debugging the palette not appearing. In order: (1) is the asset/JS actually in the rendered HTML? (2) is the component mounted in the layout that's in use? (3) is the shortcut colliding with a browser or OS binding? (4) php artisan route:list | grep -i spotlight to confirm the endpoint exists — a missing route usually means the provider wasn't auto-discovered (check bootstrap/providers.php / config/app.php if discovery is disabled).
  • Extension points worth knowing. Anything bound as a singleton in register() (a resolver, a source registry, a result formatter) can be swap()ed in a service provider — that's your cleanest hook for tenant-scoped sources and for deterministic tests, without forking the package.
  • Log the generated query. When results are wrong rather than absent, log the actual SQL from the source closure; the mismatch is nearly always an un-scoped orWhere or a missing whereNull('deleted_at') leaking soft-deleted rows into a palette.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle