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

Js Bundle Laravel Package

ite/js-bundle

A Laravel/PHP bundle for integrating and managing JavaScript assets in your application, simplifying script bundling and frontend asset delivery with minimal configuration.

View on GitHub
Deep Wiki
Context7

Getting Started

First, confirm the mismatch. ite/js-bundle is a Symfony 2 bundle — it registers through Bundle::boot(), a DependencyInjection\Extension, and Resources/config/services.yml. Laravel never invokes any of that. There is no service provider, no facade, no Blade integration, and composer require ite/js-bundle will fail to resolve against Laravel 10/11's symfony/* pins. So "getting started" means one of two things, and you should pick deliberately:

  1. You are on Symfony 2.x. Read DependencyInjection/*Extension.php to see which parameters get serialized into the global object, then wire the Twig helper into your base template. Confirm the license file exists before shipping it internally.
  2. You are on Laravel (the overwhelmingly likely case). Do not install it. Read the source for the contract — what keys go into the global, how PHP values are serialized, where escaping happens — and reimplement that contract in ~1 day. This is the recommended path.

Where to look first (when reading the bundle as a spec):

  • The DI extension / services.yml — reveals the shape of the global object and whether it dumps container parameters wholesale (a red flag if so).
  • The Twig extension — shows the injection mechanism (inline <script> vs. data attribute) and the escaping strategy.
  • Any JS-side helper in Resources/public/js/ — shows how the frontend consumes the payload.

Minimal first use case — a working window.App in Laravel:

// app/Providers/JsBridgeServiceProvider.php
public function boot(): void
{
    View::composer('layouts.app', function ($view) {
        $view->with('jsBridge', [
            'env'   => app()->environment(),
            'user'  => auth()->user()?->only(['id', 'name']),
            'flags' => config('js-bridge.flags'),
            'i18n'  => config('js-bridge.translations'),
        ]);
    });
}
{{-- layouts/app.blade.php --}}
<script type="application/json" id="app-data">{!! json_encode($jsBridge, JSON_HEX_TAG|JSON_HEX_AMP|JSON_HEX_APOS|JSON_HEX_QUOT) !!}</script>

That's the whole package's value proposition in ~20 lines, with escaping you can test and a payload you can budget.

Implementation Patterns

Allowlist, never denylist. The single most important pattern the bundle teaches: define an explicit config/js-bridge.php of keys you are willing to expose, and populate it from that, never from config('app') or the container. The bundle's biggest operational risk (per its own eval notes) is dumping arbitrary container services into JS — secrets like APP_KEY, DB_PASSWORD, and API keys leak through helpers that serialize "everything."

// config/js-bridge.php
return [
    'flags' => ['new_checkout' => env('FLAG_NEW_CHECKOUT', false)],
    'translations' => [
        'cart.empty' => 'Your cart is empty',
    ],
    // never: 'dump_container' => true
];

Prefer a JSON script island over an inline global. The bundle emits an inline <script>; for Laravel, emit <script type="application/json" id="app-data"> and parse it once in your JS entry (Vite). This is CSP-friendly, cacheable, and diffable in tests.

// resources/js/bridge.js
const el = document.getElementById('app-data');
export const App = el ? JSON.parse(el.textContent) : {};

Centralize via a service provider, not per-view View::share calls. This mirrors the bundle's "one place to register scripts" goal. A single JsBridgeServiceProvider owns the payload shape; individual controllers stay clean. This is the Laravel analogue of the bundle's Twig extension.

Load order = Vite, not script-tag ordering. The bundle solves load order by declaring scripts in config. In Laravel, Vite's dependency graph and @vite([...]) already guarantee order. Do not replicate the bundle's "declare scripts and concatenate tags" pattern — you'll fight Vite and lose cache-busting and code-splitting.

Environment awareness via app()->environment(). The bundle adapts assets for dev/prod; in Laravel this is handled by Vite's dev server vs. manifest. Keep a single env key in the payload so frontend code can branch (e.g., enable dev-only logging) without leaking APP_DEBUG internals.

Per-role/locale caching of the encoded string. If the payload is large (translations, route tables), don't json_encode the whole tree on every request. Cache the encoded string keyed on (role, locale) and inline the cached value. The bundle runs per-request with no caching — this is a known scaling lever.

Named routes: don't hand-roll route injection. Use Ziggy (@routes directive) — it's the maintained Laravel answer to the bundle's route-exposure concept, and it's the one piece of this pattern where a dependency is justified.

Feature-flag the migration. If you're replacing ad-hoc window.__DATA__ blobs already in the codebase, ship the new app-data island behind a config flag, migrate call sites one at a time, then delete the flag after one release cycle.

Gotchas and Tips

Escaping is the whole ballgame. json_encode without JSON_HEX_TAG|JSON_HEX_AMP|JSON_HEX_APOS|JSON_HEX_QUOT will happily emit a </script> inside a translation string and terminate the inline block — classic XSS. Always pass the flags, and add a regression test with a translation containing </script><img src=x onerror=alert(1)>.

Check json_encode's return value. Non-UTF-8 data (e.g., latin-1 from a legacy DB column) makes it return false, and an unguarded {!! json_encode(...) !!} ships the literal string false. Wrap it:

$json = json_encode($payload, JSON_THROW_ON_ERROR | JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT);

JSON_THROW_ON_ERROR turns silent corruption into a loud 500 — the correct failure mode.

Allowlist, not deny. The bundle's design doesn't enforce this; if you port it naively and iterate config() into the global, you will leak APP_KEY the first time someone runs config:cache. Enforce the allowlist at the config file level and add a test asserting DB_PASSWORD, APP_KEY, and any *_SECRET can never appear in the rendered HTML.

CSP will break on an inline global. If you're moving to a strict Content-Security-Policy without unsafe-inline, the bundle's inline <script> pattern is a non-starter. Use a nonce (<script nonce="{{ csp_nonce() }}">) or the JSON-island pattern above.

Cache partitioning is non-obvious and bites in production. The moment per-user data (auth()->user()) enters the payload, the response becomes user-specific. Any full-page cache, CDN, or Cache-Control: public must be partitioned by user or disabled. This is the most common way this pattern causes incidents — the bundle offers zero guidance here.

Don't vendor the Symfony source "to reuse helpers." The ~200 lines you'd borrow are trivial (escaping + array assembly); the coupling (Symfony 2 DI, EOL PHP-8-incompatible code, no license guarantee) is not. Rewrite in a service provider.

No upstream: you're on your own. 4 stars, 0 dependents, score 0.02 — no security advisories, no issue triage, no PHP 8 compatibility guarantee (Symfony 2.8 EOL'd January 2019). Treat it strictly as a reference implementation. If the license file is absent, default copyright applies and internal redistribution is a legal blocker anyway.

Debugging tip: view-source the rendered page. The payload is plain text in the response — you can curl the page and inspect the app-data JSON directly, which is what makes the JSON-island pattern far easier to debug than a minified inline global.

Extension point that actually matters: a JsBridge facade or helper with a push(string $key, mixed $value) method, so controllers can add per-page values (App.push('order', $order)) while the provider owns escaping and serialization. This is the one ergonomic win worth keeping from the bundle's design — a single choke point for all server→client injection.

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.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core