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

Reprise Laravel Package

symfony/reprise

View on GitHub
Deep Wiki
Context7

Getting Started

Reprise is a Symfony bundle (it ships no Laravel service provider or facade), so "getting started" for a Laravel developer means one of two things: you're adding it to a Symfony app in a mixed estate, or you're evaluating it as the reference implementation for what laravel-vite-plugin + Vite facade do on the Laravel side.

Minimal path in a Symfony app:

  1. composer require symfony/reprise and accept the Flex recipe — config lands in config/packages/reprise.yaml, assets are emitted to public/build.
  2. Pick a bundler (Vite or Rsbuild) and point it at the package's emit contract: the build must produce manifest.json (prod) and entrypoints.json (dev), which is the same artifact pair laravel-vite-plugin produces.
  3. Add at least one entry, then render it with the entry tag helpers in Twig (the *_entry_script_tags / *_entry_link_tags equivalents — check the bundle's Twig extension for exact names in your installed version).
  4. Run the dev and build console commands (php bin/console list reprise to see them; they are the analogue of npm run dev / npm run build with the manifest handled for you).

First real use case: replace hand-maintained <script> tags with a single entry per page and let the package resolve hashed filenames, preloads and the dev-server URL. If you only ever need that, you're done in an afternoon.

Implementation Patterns

Entry-per-page, config-driven. Define entries once in reprise.yaml (or the bundle's config tree) and render per template. This is the same mental model as @vite(['resources/js/app.js']) in Blade — one call site, no hashed filenames in templates.

Dev/prod parity without branching. entrypoints.json is served in dev (with the dev-server origin), manifest.json in prod. Keep one template path for both; do not {% if app.environment == 'dev' %} around your tags. In 1.3.0 the dev-server origin is now advertised correctly for wildcard and IPv6 hosts, and Rsbuild honours devServerOrigin, so containerised/reverse-proxied setups can set one externally reachable origin and stop hand-editing host strings.

Preload headers as a response concern. The TagRenderer can emit Link: rel=modulepreload headers alongside the tags. The 1.3.0 fix makes the header follow the final rendered tag (and lets CSP nonces reach both), so the pattern is: let the bundle generate tags, then attach headers from the same render pass via a kernel response listener — never construct preload headers independently of the tag output, or they drift.

CSP nonce plumbing. If you run a strict CSP (or NelmioSecurityBundle's CSP layer), inject the nonce once per request and let TagRenderer thread it onto modulepreload links and their headers. This is the single biggest reason to adopt the bundle over hand-rolled tags — a manual modulepreload list is the classic thing that silently breaks under strict-dynamic.

Stimulus/UX controller discovery. Controllers are auto-registered; 1.3.0 adds .jsx/.tsx local controllers and picks up controller changes in dev without a restart. Pattern: keep controllers in one directory, name them *_controller.js|jsx|tsx, and let discovery do the wiring — same shape as Laravel's import.meta.glob convention.

Atomic emit for deploys. entrypoints.json and manifest.json are now written atomically (single pipeline). That means a request that lands mid-build never sees a truncated manifest — useful if you build in-place on a shared host rather than in a release directory. It does not mean the manifest is consistent with the emitted hashed files; still deploy assets and manifest together.

Cross-stack tip. The manifest is plain Vite format, so if you have a Symfony admin app and a Laravel app sharing one asset build, Laravel's Vite facade can read the same manifest.json — set Vite::useManifestFilename()/build path to the shared directory. Don't bother for a single app; it's only worth it for genuinely shared builds.

Gotchas and Tips

  • Trailing slashes are now normalised on publicPath and manifestKeyPrefix. Existing configs keep working, but if you concatenate your own URLs from these values you may now get // or an unexpected leading segment. Also check manifest keys: with manifestKeyPrefix: 'build' the keys become build/… with a guaranteed trailing slash — code doing exact string matches on manifest keys will need updating.
  • joinUrl was removed from the Format helpers. Any extension or template that imported it must inline the join logic. Unused in most apps, breaking if you wrote a custom tag renderer.
  • ViteOutputChunk TS type removed from the Vite integration. If you typed a custom plugin against it, switch to the bundler's own types. Purely a build-time typing change.
  • Bundler hooks moved into per-bundler modules (Vite hooks, Rsbuild hooks each in their own module). If you extended or imported internal hook classes, update your imports — this is the most likely real-world break in an app that customises emit behaviour.
  • rsbuild build --watch is now treated as a build, not a dev session: you get manifest.json rather than dev-server output. If CI or a local watch loop was relying on the old behaviour to get a dev-ish asset graph, it will now emit production assets.
  • A missing entrypoints.json is no longer cached. Previously a failed/missing build could poison the cache and survive a successful rebuild; now the first request after the file appears will resolve correctly. If you were compensating with a manual cache:clear step in deploy, drop it — but keep it if you cache the rendered HTML.
  • Rebuild loops are stopped when another tool watches the output directory. If you have a custom watcher on public/build, expect it to no longer trigger the package's own rebuild. Don't run two watchers on the same output dir.
  • Debugging a 404 in prod: check in this order — APP_ENV (dev manifest vs prod manifest), publicPath, manifestKeyPrefix (both now trailing-slashed), then whether the entry name in config matches the key in manifest.json. The generated JSON is the source of truth; read it before reading the template.
  • Atomic writes emit via rename. Tools tailing or inotify-watching manifest.json for writes may miss the event; watch the directory, not the file, if you have such a tool.
  • Extension points: the TagRenderer (tag + header generation) and the emit pipeline are the two seams worth learning; both gained fixes in 1.3.0 (final-tag headers, single emit pipeline). Everything else in this release is behaviour you get for free — no config migration is required to adopt 1.3.0 beyond the joinUrl/type removals if you had custom code.
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
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
cgv/localized-resource