|
1 | 1 | import type { RsbuildPlugin } from '@rsbuild/core'; |
2 | 2 | import type { RspackStats } from './collectors/rspack'; |
3 | | -import type { BuildContext, Options } from './types'; |
| 3 | +import type { BuildContext, ManifestJson, Options } from './types'; |
4 | 4 | import * as path from 'node:path'; |
5 | 5 | import * as process from 'node:process'; |
6 | 6 | import { rspack } from '@rsbuild/core'; |
7 | 7 | import { statsToGraph } from './collectors/rspack'; |
| 8 | +import { copyManifest, resolveCopyFiles, writeCopyFiles } from './core/copy'; |
8 | 9 | import { writeSymfonyFiles } from './core/emit'; |
9 | 10 | import { integrityFromDisk, referencedFileNames } from './core/integrity'; |
10 | 11 | import { buildEntrypoints, buildManifest } from './core/format'; |
@@ -103,6 +104,32 @@ export default function symfony(options?: Options): RsbuildPlugin { |
103 | 104 | api.onAfterCreateCompiler(({ compiler }) => { |
104 | 105 | const compilers = 'compilers' in compiler ? compiler.compilers : [compiler]; |
105 | 106 | for (const c of compilers) { |
| 107 | + // Build: emit the copied files into the compilation, so Rspack writes them, lists |
| 108 | + // them in the build output, and cleans them like any other asset. `sourceFilename` |
| 109 | + // lets the existing statsToGraph collector key them in manifest.json (no manual |
| 110 | + // merge — see the `done` tap). Dev instead writes them to disk in `done`: there they |
| 111 | + // are served by the Symfony web server from `public/build`, not by the dev server, |
| 112 | + // so they must not become in-memory compilation assets. |
| 113 | + if (!isDev) { |
| 114 | + c.hooks.thisCompilation.tap('@symfony/reprise:copy', (compilation) => { |
| 115 | + compilation.hooks.processAssets.tap( |
| 116 | + { |
| 117 | + name: '@symfony/reprise:copy', |
| 118 | + stage: rspack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL, |
| 119 | + }, |
| 120 | + () => { |
| 121 | + for (const file of resolveCopyFiles(resolved.copy, true)) { |
| 122 | + compilation.emitAsset( |
| 123 | + file.physicalName, |
| 124 | + new rspack.sources.RawSource(file.source), |
| 125 | + { sourceFilename: file.logicalName } |
| 126 | + ); |
| 127 | + } |
| 128 | + } |
| 129 | + ); |
| 130 | + }); |
| 131 | + } |
| 132 | + |
106 | 133 | c.hooks.done.tap('@symfony/reprise', (stats) => { |
107 | 134 | const isDev = c.watchMode; |
108 | 135 | // The dev URLs we advertise must be the dev-server origin joined with our `publicPath` |
@@ -141,10 +168,22 @@ export default function symfony(options?: Options): RsbuildPlugin { |
141 | 168 | resolved.integrity.algorithms |
142 | 169 | ); |
143 | 170 | } |
144 | | - // In dev the manifest is empty: assets are served from the dev server, never looked |
145 | | - // up on disk by hash, so cache-busting is moot. entrypoints.json alone drives loading. |
146 | | - // Matches the Vite dev path (see `configureServer` in index.ts), which also writes `{}`. |
147 | | - const manifest = isDev ? {} : buildManifest(graph, ctx); |
| 171 | + // Copied static files: in build they were emitted into the compilation (see the |
| 172 | + // processAssets tap above), so statsToGraph already carries them in `graph.assets` |
| 173 | + // and `buildManifest` keys them. In dev they are not emitted (served by the Symfony |
| 174 | + // web server from disk, not the dev server), so write them out here and key them by |
| 175 | + // their relative publicPath URL. |
| 176 | + let manifest: ManifestJson; |
| 177 | + if (isDev) { |
| 178 | + const copyFiles = resolveCopyFiles(resolved.copy, false); |
| 179 | + writeCopyFiles(copyFiles, resolved.outputPath); |
| 180 | + manifest = copyManifest(copyFiles, { |
| 181 | + publicPath: resolved.publicPath, |
| 182 | + manifestKeyPrefix: resolved.manifestKeyPrefix, |
| 183 | + }); |
| 184 | + } else { |
| 185 | + manifest = buildManifest(graph, ctx); |
| 186 | + } |
148 | 187 | try { |
149 | 188 | writeSymfonyFiles(resolved.outputPath, buildEntrypoints(graph, ctx), manifest); |
150 | 189 | } catch (err) { |
|
0 commit comments