pxlrbt/laravel-docs
pxlrbt/laravel-docs is a lightweight Laravel package that makes Laravel documentation easily accessible from your app, so you can reference framework guides and API details without leaving your development environment.
Install, publish, then stop and read the published config before writing any integration code. The config file plus the published Blade views are the API surface — there is no service class worth studying until you know what the config resolves.
composer require pxlrbt/laravel-docs
php artisan vendor:publish # select the laravel-docs config and view tags
php artisan route:list | grep docs # confirm the route actually exists and what middleware it carries
Then, in order:
vendor/pxlrbt/laravel-docs/src and write down which one your config produces. Treat this as a prerequisite, not a detail.docs/), and add a single index.md so you have a working vertical slice before touching layout or nav.# Illustrative shape — confirm key names against your published config/docs.php
DOCS_ENABLED=true
DOCS_PATH=docs
DOCS_PREFIX=docs
DOCS_MIDDLEWARE=web,auth
First use case: an internal engineering handbook or in-app help section behind auth, rendered through your existing layout and linked from the main nav. Read-only, low blast radius, gives you a full vertical slice on day one. Do not start with public, SEO-indexed, customer-facing docs — that's the highest-risk configuration and the one this package is least suited to (no sitemap, no structured data, no CDN story, no search).
Where to look first when something is wrong: the published config, then the published views (they show exactly what variables the renderer passes down), then the cache store.
Docs-as-code with PR review as the editorial workflow. Keep Markdown in the same repo as the app, next to the code it documents. A docs change then rides the same PR, CI, and release train as the feature — which is the entire reason to prefer this over a wiki. Day to day that means: write or edit .md, preview locally with php artisan serve against the docs route, open a PR, merge, deploy. Add the doc page and its navigation entry in the same PR; a page nobody can reach is worse than no page.
Gate the route with a named middleware group rather than inline config. Point the config at a group you already control so tenancy and entitlement logic lives in one place:
Route::middleware(['web', 'auth', 'can:view-docs'])->group(function () {
// package route resolves under the configured prefix
});
Then make the route's existence environment-dependent — disabled in local while you iterate, always disabled in staging if staging is publicly reachable. Verify with php artisan route:list in each environment that the middleware is actually attached.
Wrap the renderer in a one-method interface of your own. This isn't test elegance — it's an exit hatch. With a single maintainer and near-zero adoption, you want the option to swap the package out in an afternoon:
interface DocsRenderer
{
public function page(string $slug): ?string;
public function navigation(): array;
}
Bind it to the package in a service provider and have every controller, nav component, and view ask for DocsRenderer — never for the package's classes directly. Thirty lines that convert a fork decision from a sprint into an afternoon.
Publish and commit the Blade views, then extend your own layout. The point of the package is that docs look like the rest of the product. Once the views are in version control, make the docs layout @extends your application layout so navigation, auth state, and design tokens come for free instead of being reimplemented.
Pin the docs version to the running app version. Because the source directory is config, serving "docs for v3" to a v3 customer is an env/config decision, not a code branch. Decide that early — retrofitting version-aware paths after customers are on the URL is painful.
Cache persistently and warm at deploy. If you're on the remote-fetch mode, array cache is dev-only. Use Redis or the database and add a deploy step that hits the docs index so the first real user never pays the fetch cost:
curl -sf https://your-app.test/docs > /dev/null # or an artisan warm command if provided
Smoke-test the route in CI. One feature test asserting the docs index returns 200 and contains a known heading catches config drift, missing source files, cache misconfiguration, and upstream dependency bumps in one shot. This is the single highest-value test you can add for this package.
Sequence the Symfony 8 upgrade deliberately. v1.2.0 exists purely to widen symfony/yaml to include 8.x. When you start a Symfony 8 upgrade, bump this package first so it stops appearing as a confusing transitive conflict in composer why-not.
Resolve the local-vs-remote ambiguity before anything else. The package description mentions local Markdown with no external dependencies; other usage notes describe fetching from an upstream source with caching. Read the resolver in vendor/ and write down which one you're actually running. Don't assume.
If you do fetch remotely: 60 requests/hour/IP, unauthenticated. A team behind one NAT with a cache cleared on every deploy will exhaust that and serve blank pages. Check whether a GitHub token is supported and configure one; otherwise vendor the Markdown into the repo on a schedule and treat the network path as never taken at runtime.
The route is probably registered unconditionally by the service provider. That means it exists in every environment the moment the package is installed — including production, before you've added auth. Gate it from the first commit.
Confirm v1.2.0 widened rather than replaced the constraint. ^7|^8 is a safe maintenance bump; ^8 alone would block anyone pinned below Symfony 8. Run composer why-not pxlrbt/laravel-docs before scheduling the upgrade, and diff the rendered HTML afterward — a YAML parser bump can change front-matter edge-case handling.
Pin to a minor version and commit the published config and views. "pxlrbt/laravel-docs": "~1.2.0" plus committed artifacts means upgrades show up as a visible diff rather than silent key changes. New config keys are otherwise either adopted unnoticed or missed entirely. Budget a couple of hours a quarter to read the changelog — the ongoing cost here is governance, not code.
Watch the docs route prefix for collisions. It's a popular slug. Run php artisan route:list | grep docs after install, before you tell anyone the URL.
Don't oversell the capability. No full-text search, no i18n workflow, no versioned hosting, no editorial approval pipeline, no content API. If stakeholders need search, add a client-side library over the rendered pages as a stopgap and be explicit that this is a renderer, not a platform.
Debugging order for a blank or broken page: (1) does the source path resolve and contain .md files? (2) is the cache store reachable and is the entry actually cached? (3) if remote, did you hit a rate limit or egress block? (4) did a dependency bump change front-matter parsing? Log at each step — the failure is almost always configuration, not code.
Keep it off the critical path. Put it behind a feature flag with graceful degradation that shows a static fallback link instead of a 500 on your shared layout. Docs failing should be an inconvenience, never an outage — that constraint is what makes the weak ecosystem signals (4 stars, one maintainer, zero dependents) an acceptable risk rather than a disqualifying one.
How can I help you explore Laravel packages today?