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

Biome Js Bundle Laravel Package

kocal/biome-js-bundle

Symfony bundle that integrates Biome, the fast JavaScript, TypeScript, and JSON formatter and linter, into your project. Configure Biome from Symfony and run checks or formatting through convenient console commands.

View on GitHub
Deep Wiki
Context7

Getting Started

Read this first: it is a Symfony bundle, not a Laravel package. There is no service provider, no config/biome.php, and no php artisan biome:* command. A Laravel developer has exactly two realistic entry points:

  1. Reference implementation — read the bundle's source (src/) to lift the two pieces that matter: platform/arch detection for the Biome Rust binary (linux-x64, darwin-arm64, win32-x64, …) and a symfony/process wrapper that shells out with a proper exit code. That is roughly 150–250 lines and ports to an Artisan command in an afternoon.
  2. Monorepo coexistence — if your Laravel app lives beside a Symfony service, install the bundle there with composer require --dev kocal/biome-js-bundle, register it in config/bundles.php, and run its console command from that side of the repo against the Laravel resources/js directory.

Minimal Laravel-side port:

composer require --dev symfony/http-client   # symfony/process ships with Laravel already

Then a single command app/Console/Commands/BiomeCommand.php that:

  • resolves the pinned Biome version (from composer.json extra or an env var),
  • downloads the correct binary into storage/app/biome/<version>/ on first run (idempotent, skip if present),
  • chmod +x, then proxies $this->argument('args') through Symfony\Component\Process\Process with cwd set to base_path().

First use case: run it against resources/js and resources/css in CI as a node-free lint gate, while Vite keeps handling the actual build.

Where to look first in the upstream repo: the Command/ directory (exact command names are version-dependent — check the classes rather than trusting docs), and the service that computes the download URL.

Implementation Patterns

Composer script hook, guarded. Wire the installer into post-install-cmd/post-update-cmd so a fresh clone works, but make the command a no-op when the binary already exists or BIOME_SKIP_DOWNLOAD=1 is set. Air-gapped and locked-down corporate CI will thank you.

Artisan passthrough, not a wrapper API. Keep the command dumb: php artisan biome check --write resources/js. Every Biome flag, config key, and future feature stays available without you re-releasing. Resist the urge to invent --fix/--all sugar.

Split responsibilities with Pint. Pint owns *.php; Biome owns *.js, *.ts, *.jsx, *.tsx, *.json, *.jsonc, *.css, and (in 2.x) GraphQL. One composer script composes both:

"scripts": {
  "lint": ["@php artisan biome check --write", "pint"],
  "lint:ci": ["@php artisan biome ci", "pint --test"]
}

Note the ordering — format JS/CSS first, then PHP, so a single git diff review covers everything.

CI caching keyed on OS + pinned version. Cache storage/app/biome. Key: ${{ runner.os }}-biome-${{ hashFiles('composer.lock') }}. Run biome ci in the same job as php artisan test; it adds a few seconds, not a job.

Docker: download in the build stage. Biome is a self-contained Rust binary, so COPY --from=builder /app/storage/app/biome /app/storage/app/biome works cleanly. Do not run the download at container start — you have just moved a network call into your critical path.

Editor parity. Point the VS Code Biome extension at the downloaded binary path so contributors who never ran npm install still get diagnostics. This is the highest day-to-day payoff of the whole exercise.

Pre-commit with staged files only. Pass explicit file paths from git diff --cached --name-only --diff-filter=ACM rather than running a full-tree check; the full check belongs in CI.

Graceful degradation. If the download fails, log a warning and exit 0 from the installer (not from the check). A missing linter must never block a deploy build.

Gotchas and Tips

  • The Symfony DI coupling is the real blocker. The bundle's commands extend Symfony\Component\Console\Command\Command, so they will run inside Laravel's console kernel if you instantiate them manually — but the bundle's container config never loads. Unless the command has zero constructor dependencies (unlikely; it needs a binary path and version config), manual instantiation is more work than writing your own. Fork the pattern, not the code.
  • Alpine/musl is the classic breakage. Biome publishes separate builds for glibc and musl Linux. A php:8.x-fpm-alpine base image will fail with a confusing ENOEXEC/not-found error if your detection logic assumes glibc. Detect musl (ldd --version output, or just key off the base image) or add an override env var.
  • Exit codes are not boolean. Biome returns 1 for lint diagnostics and 2 for tool/config errors. In CI, treat 2 as a hard failure and 1 as "fix the code" — collapsing them into one message wastes real debugging time.
  • Pin the Biome version, and verify it's actually pinned. The bundle version transitively determines the binary version. Check what composer.lock resolves to before assuming you're on the same Biome as your editor extension. Version drift between CLI and editor produces phantom diagnostics.
  • --write vs --apply semantics changed across Biome 1.x → 2.x. Pin, then read the docs for that version. Copy-pasted blog snippets are the single biggest source of "why did it reformat my JSON keys" complaints.
  • Run from the project root, not with absolute paths. biome.json files.includes globs resolve relative to cwd; passing absolute paths from your command silently skips the config. Set Process cwd to base_path() explicitly.
  • .exe suffix and the executable bit. Windows needs biome.exe; POSIX needs chmod 0755. Both are easy to forget and both fail with unhelpful "binary not found" messages when wrong.
  • Gitignore storage/app/biome, commit biome.json. The binary is large and platform-specific; the config is the only thing that should be reviewed in PRs.
  • Maturity risk is priced in. 32 stars, 0 dependents, published Dec 2025. Treat this as a reference implementation with a documented exit plan: at any moment you can npm i -D @biomejs/biome (if a Node toolchain reappears) or curl the release tarball directly. Keep the version and URL construction in one small class so the swap is a one-file change.
  • Ask whether you need this at all. Every Laravel app already has Node for Vite. The node-free property only pays off for PHP-only CI runners, restricted build environments, or a team policy against node_modules. If none of those apply, npm i -D @biomejs/biome and a "lint" script is one line and zero maintenance.
  • Debug with verbosity. Run your command with -v and print the resolved binary path, version, and argv before execution. Every failure mode here is "wrong binary" or "wrong path," and both are invisible at default verbosity.
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.
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core