Skip to content

Commit 5c06544

Browse files
committed
[Rsbuild][Docs] Read rspack off the compiler, condense comments
1 parent 681dac5 commit 5c06544

6 files changed

Lines changed: 60 additions & 164 deletions

File tree

assets/src/collectors/vite.ts

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,8 @@ type ViteOutputChunk = Rollup.OutputChunk & { viteMetadata?: ViteChunkMetadata }
1010
export function bundleToGraph(bundle: Rollup.OutputBundle, root: string): NormalizedGraph {
1111
const entryPoints: Record<string, EntryFiles> = {};
1212
const assets: AssetEntry[] = [];
13-
// Entry CSS stays in the manifest, keyed by its logical name (e.g. `app.css`, matching Rsbuild's
14-
// chunk-name keying). Async (non-entry) chunk CSS does not: it loads at runtime with its lazily
15-
// imported chunk, never via `asset()`, so a manifest entry would only be a byproduct that diverges
16-
// from Rsbuild and collides when two chunks share a name. Both kinds report `originalFileNames` as
17-
// the importing JS, so neither must reach the source-path branch (that is for imported images/fonts).
13+
// Entry CSS is kept in the manifest (keyed by logical name like `app.css`); async chunk CSS isn't
14+
// (it loads with its chunk, never via `asset()`, and would collide across same-named chunks).
1815
const entryCss = new Set<string>();
1916
const asyncCss = new Set<string>();
2017

@@ -47,9 +44,8 @@ export function bundleToGraph(bundle: Rollup.OutputBundle, root: string): Normal
4744
}
4845

4946
function assetLogicalName(file: Rollup.OutputAsset, root: string, entryCss: Set<string>): string {
50-
// Imported assets (images, fonts) get their source path relative to the project root, so the
51-
// manifest key matches Rsbuild's `sourceFilename` and same-basename files in different folders
52-
// stay distinct. Entry CSS and assets with no source path fall back to the basename.
47+
// Imported assets key by source path relative to root (matches Rsbuild's `sourceFilename`, keeps
48+
// same-basename files distinct); entry CSS and path-less assets fall back to the basename.
5349
const original = entryCss.has(file.fileName) ? undefined : file.originalFileNames[0];
5450
if (original) return slash(relative(root, resolve(root, original)));
5551
return file.names[0] ?? file.fileName;

assets/src/core/format.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@ export function joinUrl(prefix: string, name: string): string {
55
}
66

77
function toReference(prefix: string, name: string): string {
8-
// Docroot-relative reference (ADR 0001): a build URL like `/build/app-<hash>.js` becomes
9-
// `build/app-<hash>.js`; an absolute dev-server URL has no leading slash and is unchanged.
8+
// Docroot-relative reference (ADR 0001): strips the leading slash (dev-server URLs have none).
109
return joinUrl(prefix, name).replace(/^\//, '');
1110
}
1211

@@ -27,8 +26,7 @@ export function buildEntrypoints(graph: NormalizedGraph, ctx: BuildContext): Ent
2726
entryPoints,
2827
};
2928
if (graph.integrity) {
30-
// Re-key the per-file-name hashes by the same references that appear in the entry lists,
31-
// so the Symfony side can look each one up by asset reference.
29+
// Re-key hashes by the same references used in the entry lists, for lookup by reference.
3230
out.integrity = Object.fromEntries(
3331
Object.entries(graph.integrity).map(([fileName, sri]) => [toReference(ctx.urlPrefix, fileName), sri])
3432
);

assets/src/core/integrity.ts

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,12 @@ import { createHash } from 'node:crypto';
33
import { readFileSync } from 'node:fs';
44
import { join } from 'node:path';
55

6-
/**
7-
* Build a Subresource Integrity string for `content`: one `<algorithm>-<base64 digest>`
8-
* token per algorithm, joined by spaces (the format browsers expect in an `integrity`
9-
* attribute, and the one Webpack Encore writes into `entrypoints.json`).
10-
*/
6+
/** SRI string for `content`: space-joined `<algo>-<base64 digest>` tokens, one per algorithm. */
117
export function computeIntegrity(content: string | Uint8Array, algorithms: string[]): string {
128
return algorithms.map((algo) => `${algo}-${createHash(algo).update(content).digest('base64')}`).join(' ');
139
}
1410

15-
/**
16-
* The distinct file names referenced by every entry, across all four buckets
17-
* (js/css/preload/dynamic), in first-seen order. This is the set of emitted files
18-
* that get an integrity hash.
19-
*/
11+
/** Distinct file names across every entry's four buckets (first-seen order) — the SRI set. */
2012
export function referencedFileNames(entryPoints: Record<string, EntryFiles>): string[] {
2113
const seen = new Set<string>();
2214
for (const files of Object.values(entryPoints)) {
@@ -27,11 +19,7 @@ export function referencedFileNames(entryPoints: Record<string, EntryFiles>): st
2719
return [...seen];
2820
}
2921

30-
/**
31-
* Compute the integrity of each file read from `outputPath` on disk, keyed by file name.
32-
* Used by the Rspack path, whose `done` hook fires after the assets are emitted (like
33-
* Encore, which reads the emitted files back). Bytes are hashed raw, so binary assets work.
34-
*/
22+
/** Integrity of each file read back from disk (Rspack path; raw bytes, so binary assets work). */
3523
export function integrityFromDisk(
3624
fileNames: string[],
3725
outputPath: string,

assets/src/core/options.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,8 @@ function normalizeIntegrity(integrity: Options['integrity']): ResolvedOptions['i
77
}
88

99
function normalizeCopyTo(to: string): string {
10-
// Collapse "." segments and redundant slashes, then drop any leading "./" or "/" and trailing
11-
// "/". A leading "./" or "/" would corrupt the manifest key ("build/./to-copy/…") and, in the
12-
// Vite path, make Rollup reject the emitted asset fileName (it forbids relative-looking paths).
10+
// Drop leading `./`|`/` and trailing `/`: they corrupt the manifest key and make Rollup reject
11+
// a relative-looking emitted fileName.
1312
const normalized = path.posix.normalize(to.replace(/\\/g, '/'));
1413
return normalized
1514
.replace(/^\.?\/+/, '')

assets/src/core/stimulus.ts

Lines changed: 7 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,7 @@ interface ControllersJson {
2222
/** The virtual module the runtime helper imports; provided by each bundler adapter. */
2323
export const VIRTUAL_CONTROLLERS_ID = 'virtual:symfony/controllers';
2424

25-
/**
26-
* Shown when `virtual:symfony/controllers` is imported (typically via `startStimulusApp()`)
27-
* while the `stimulus` option is unset — instead of the bundler's cryptic
28-
* "failed to resolve" / "Unhandled scheme" error.
29-
*/
25+
/** Shown when the virtual module is imported while the `stimulus` option is unset. */
3026
export const STIMULUS_NOT_ENABLED_MESSAGE =
3127
`[@symfony/reprise] "${VIRTUAL_CONTROLLERS_ID}" was imported (this is what startStimulusApp() ` +
3228
`from "@symfony/reprise/stimulus" pulls in), but the Stimulus integration is not enabled. ` +
@@ -42,29 +38,18 @@ interface ResolvedController {
4238
autoimports: string[];
4339
}
4440

45-
// A controller opts into lazy loading with a `stimulusFetch: 'lazy'` comment placed *directly
46-
// above the class declaration* — after the imports, like a decorator:
47-
//
48-
// import { Controller } from '@hotwired/stimulus'
41+
// A controller opts into lazy loading with a `stimulusFetch: 'lazy'` comment directly above the
42+
// class (line/block comment, either quotes, `/*!...*/` survives minification) — recognised only
43+
// when the class is the very next code, so a stray marker elsewhere doesn't count:
4944
//
5045
// /* stimulusFetch: 'lazy' */
5146
// export default class extends Controller {}
52-
//
53-
// The marker is recognised only when the very next code is the class (`[export [default]] class`),
54-
// which is why a stray `stimulusFetch: 'lazy'` sitting above the imports (or anywhere else) does
55-
// NOT flip the controller to lazy. It may be a block comment or a single-line one, single or
56-
// double quotes; a block comment may sit on the class's own line, a line comment must precede it.
57-
// A preserved block comment (`/*! ... */`, the form tsc/esbuild keep so the marker survives
58-
// minification) is recognised too.
5947
const LAZY_COMMENT_RE =
6048
/(?:\/\*!?\s*stimulusFetch:\s*['"]lazy['"]\s*\*\/|\/\/\s*stimulusFetch:\s*['"]lazy['"])\s*(?:export\s+(?:default\s+)?)?(?:abstract\s+)?class\b/i;
6149
const LOCAL_CONTROLLER_RE = /[-_]controller\.[jt]s$/;
6250

6351
export function generateControllersModule(opts: ResolvedStimulusOptions, root: string, isDev: boolean): string {
64-
// Collect controllers keyed by identifier. Third-party controllers are added first, local
65-
// ones second, so a local controller sharing an identifier with a third-party one overrides
66-
// it (last write wins) and each identifier ends up in exactly one of the two maps — never
67-
// emitted twice, never registered twice.
52+
// Keyed by identifier; local added after third-party so a local override wins (last write wins).
6853
const controllers = new Map<string, ResolvedController>();
6954

7055
const require = createRequire(path.join(root, 'noop.js'));
@@ -108,8 +93,7 @@ export function generateControllersModule(opts: ResolvedStimulusOptions, root: s
10893
controllers.set(identifier, {
10994
identifier,
11095
fetch: LAZY_COMMENT_RE.test(readFileSync(abs, 'utf8')) ? 'lazy' : 'eager',
111-
// Emit a forward-slash path: a valid ESM import specifier on every OS (a Windows
112-
// backslash path would be escaped in the generated string and is not a portable specifier).
96+
// Forward slashes: a portable ESM specifier (a Windows backslash path isn't).
11397
main: abs.replace(/\\/g, '/'),
11498
autoimports: [],
11599
});
@@ -179,8 +163,7 @@ function listLocalControllers(dir: string): string[] {
179163
entries
180164
.map((e) => String(e).replace(/\\/g, '/'))
181165
.filter((e) => LOCAL_CONTROLLER_RE.test(e))
182-
// Sort so the generated module -- and therefore its content hash -- stays stable
183-
// regardless of the filesystem's iteration order. See symfony/ux#3703.
166+
// Sort so the module (and its content hash) is stable across FS order. See symfony/ux#3703.
184167
.sort()
185168
);
186169
}

0 commit comments

Comments
 (0)