Reprise 0.8.0 is out, a few weeks after the project was introduced on this blog. This release brings back an Encore behavior that some codebases depend on: copied files that keep a stable path on disk. It also fixes a manifest discrepancy between Vite and Rsbuild.

Copied Files Can Keep Their Path

Loïck Piera
Contributed by Loïck Piera in #81

Encore's copyFiles() could keep a copied file at a fixed path on disk and put the hash in the query string instead. Codebases end up relying on that: templates hardcoding asset('/build/images/logo.svg'), PHP code reading a file from a known location, CDN rules. Reprise always hashed the filename, so migrating such a project from Encore meant writing a custom plugin.

A copy entry now accepts a hash option, true by default. Set it to false and the file keeps its logical path, while the content hash moves to the manifest.json value as a query string:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// vite.config.ts
import { defineConfig } from 'vite'
import Symfony from '@symfony/reprise/vite'

export default defineConfig({
  // ...
  plugins: [
    Symfony({
      copy: [
        {
          from: 'assets/images',
          to: 'images',
          hash: false,
        },
      ],
    }),
  ],
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// rsbuild.config.ts
import { defineConfig } from '@rsbuild/core'
import Symfony from '@symfony/reprise/rsbuild'

export default defineConfig({
  // ...
  plugins: [
    Symfony({
      copy: [
        {
          from: 'assets/images',
          to: 'images',
          hash: false,
        },
      ],
    }),
  ],
})

The file lands at public/build/images/logo.svg and the manifest carries the cache-busting query, so asset() keeps returning a versioned URL:

1
{ "build/images/logo.svg": "/build/images/logo.svg?87dcc351" }

The option is per entry, so hashed and stable copies can live in the same config. Proxies or CDNs configured to ignore query strings will not pick up new versions of these files, which is why hashed filenames remain the default. The same pull request also lets an empty to place copied files at the root of outputPath, for the ones that have to sit at a fixed top-level URL like favicon.ico or site.webmanifest.

Same Manifest Keys on Vite and Rsbuild

Hugo Alliaume
Contributed by Hugo Alliaume in #82

manifest.json maps a logical asset path to its hashed URL, which is what makes asset('fonts/query.woff2') resolve to the built file in Twig. A stylesheet can reference that same file with a query string or a fragment tacked on, and both are everyday CSS:

1
2
3
4
5
6
7
8
@font-face {
    font-family: "Query";
    src: url("./fonts/query.woff2?v=1") format("woff2");
}

.icon {
    background: url("./media/icon.svg#frag");
}

Vite wrote the manifest key as build/fonts/query.woff2, with the query string already stripped. Rsbuild carried it over instead and wrote build/fonts/query.woff2?v=1, a key that asset('fonts/query.woff2') in Twig would never match. Same project, same CSS: the font resolved through Vite and failed through Rsbuild. The query string and the fragment describe how the CSS references the file, not the file itself, so both are now stripped before the manifest key is written.

Corepack Is Gone

Hugo Alliaume
Contributed by Hugo Alliaume in #84 and #85

Node.js stopped shipping Corepack in v25, after the TSC voted to stop distributing it. It was also a slow way to reach pnpm, since every command went through a Node.js shim that first had to resolve and download the package manager.

Reprise no longer relies on it. The CI workflows use pnpm/setup, which fetches the standalone pnpm binary and installs Node.js in one step, and contributors install pnpm the usual way instead of running corepack enable. Symfony UX made the same move in symfony/ux#3774.

Full Changelog

  • #81 Add a per-entry opt-out of copied filenames hashing (@pyrech)
  • #82 [Manifest] Strip url() query and fragment from Rspack keys (@Kocal)
  • #84 [CI] Replace Corepack with pnpm/setup (@Kocal)
  • #85 [CI] Use pnpm/setup in the release workflow (@Kocal)
  • #83 Update all npm devDependencies (@Kocal)
  • #79 Link the announcement blog post in the README (@Kocal)

Reprise is still experimental and still 0.x, so this is the moment where feedback shapes what comes after Encore. Try it on a real project, open an issue, or send a pull request on GitHub.

Published in #Releases