Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
954e19b
feat: add chunk group graph report api
JSerFeng Apr 21, 2026
033749a
test: cover split chunk path sizing
JSerFeng Apr 27, 2026
40fb554
fix: exclude path-required modules from chunk group waste
JSerFeng Apr 27, 2026
ec5370c
fix: align chunk group reachability with rspack blocks
JSerFeng Apr 27, 2026
00950c9
fix: cap chunk group path traversal
JSerFeng Apr 28, 2026
eb0d1b6
fix: improve chunk group graph layout
JSerFeng Apr 28, 2026
46d300d
fix: improve chunk group graph navigation
JSerFeng Apr 29, 2026
5d42b9e
fix: refine chunk graph node scaling
JSerFeng Apr 29, 2026
75bee0b
fix: refine chunk graph selection labels
JSerFeng Apr 29, 2026
40a064c
fix: show path import snippets
JSerFeng Apr 29, 2026
7f1e62f
fix: allow page scroll over chunk graph
JSerFeng Apr 29, 2026
68479c3
fix: handle chunk graph wheel scrolling
JSerFeng Apr 29, 2026
3f90792
fix: restore native chunk graph scrolling
JSerFeng Apr 29, 2026
4fc2e54
fix: stop chunk graph from hijacking wheel scroll
JSerFeng Apr 29, 2026
8e3e567
fix: add chunk graph zoom controls
JSerFeng Apr 29, 2026
3fc413f
fix: support trackpad zoom for chunk graph
JSerFeng Apr 29, 2026
d5d1d88
fix: make chunk graph zoom more responsive
JSerFeng Apr 30, 2026
e0e989e
fix: load local rsdoctor profile shards
JSerFeng Apr 30, 2026
c28ef57
fix: make chunk graph layout more organic
JSerFeng Apr 30, 2026
2631447
fix: allow dragging chunk graph nodes
JSerFeng Apr 30, 2026
434a2a4
fix: adapt chunk graph around dragged nodes
JSerFeng Apr 30, 2026
aefdb63
fix: show path import snippets on parent nodes
JSerFeng Apr 30, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,284 changes: 1,284 additions & 0 deletions packages/components/src/pages/BundleSize/components/chunk-group.tsx

Large diffs are not rendered by default.

16 changes: 15 additions & 1 deletion packages/components/src/pages/BundleSize/components/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import {
} from '../../../utils';
import { AssetDetail } from './asset';
import { BundleCards } from './cards';
import { ChunkGroupGraphPanel } from './chunk-group';
import styles from './index.module.scss';
import './index.sass';
import { SearchModal } from './search-modal';
Expand Down Expand Up @@ -71,6 +72,7 @@ export const WebpackModulesOverallBase: React.FC<
const [inputModuleUnit, setModuleUnit] = useState('');
const [inputChunkUnit, setChunkUnit] = useState('');
const [assetPath, setAssetPath] = useState<string | null>(null);
const [activeTabKey, setActiveTabKey] = useState('tree');
const { showCode, codeDrawerComponent } = useCodeDrawer(
'Do not have the codes of assets. If you use the lite or brief mode, there will have codes.',
);
Expand Down Expand Up @@ -205,6 +207,8 @@ export const WebpackModulesOverallBase: React.FC<
<Card styles={{ body: { paddingTop: 0 } }}>
<Tabs
size="middle"
activeKey={activeTabKey}
onChange={setActiveTabKey}
items={[
{
key: 'tree',
Expand Down Expand Up @@ -591,8 +595,18 @@ export const WebpackModulesOverallBase: React.FC<
</ServerAPIProvider>
),
},
{
key: 'chunk-group',
label: 'Chunk Group Graph',
children: (
activeTabKey === 'chunk-group' ? (
<ServerAPIProvider api={SDK.ServerAPI.API.GetChunkGroupGraph}>
{(report) => <ChunkGroupGraphPanel report={report} />}
</ServerAPIProvider>
) : null
),
},
]}
defaultActiveKey="tree"
/>
</Card>
</div>
Expand Down
10 changes: 6 additions & 4 deletions packages/components/src/utils/data/remote.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@ export class RemoteDataLoader extends BaseDataLoader {
public async loadData(key: string): Promise<unknown> {
return this.limit(key, async () => {
const [scope, ...rest] = this.getKeys(key);
const data = this.getData(
scope as keyof Manifest.RsdoctorManifestData,
'cloudData',
);
const data =
this.getData(
scope as keyof Manifest.RsdoctorManifestData,
'cloudData',
) ??
this.getData(scope as keyof Manifest.RsdoctorManifestData, 'data');

if (!data) return;

Expand Down
47 changes: 46 additions & 1 deletion packages/components/src/utils/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,58 @@ export async function fetchJSONByUrl(url: string) {
}
}

return json as Manifest.RsdoctorManifestWithShardingFiles;
return normalizeManifestShardingUrls(
json as Manifest.RsdoctorManifestWithShardingFiles,
url,
);
}

export function fetchJSONByUrls(urls: string[]) {
return Promise.all(urls.map((url) => fetchJSONByUrl(url)));
}

function normalizeManifestShardingUrls(
manifest: Manifest.RsdoctorManifestWithShardingFiles,
manifestUrl: string,
) {
const resolvedManifestUrl = new URL(manifestUrl, window.location.href);
const isShardingPathList = (value: unknown): value is string[] =>
Array.isArray(value) &&
value.length > 0 &&
value.every((item) => typeof item === 'string');

const normalizeData = (
data: Manifest.RsdoctorManifestWithShardingFiles['data'],
) => {
return Object.fromEntries(
Object.entries(data).map(([key, value]) => {
Comment on lines +66 to +67
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Handle missing manifest data before URL normalization

The new normalization path assumes manifest.data exists and immediately calls Object.entries(data). fetchJSONByUrl still intentionally maps HTML responses to {} (SPA fallback/error page case), so this now throws a TypeError during normalization instead of allowing later fallback handling, turning a recoverable manifest fetch error into an immediate runtime failure.

Useful? React with 👍 / 👎.

if (!isShardingPathList(value)) {
return [key, value];
}

return [
key,
value.map((item) => {
if (Url.isUrl(item)) {
return item;
}

return new URL(item, resolvedManifestUrl).toString();
}),
];
}),
) as Manifest.RsdoctorManifestWithShardingFiles['data'];
};

return {
...manifest,
data: normalizeData(manifest.data),
cloudData: manifest.cloudData
? normalizeData(manifest.cloudData)
: undefined,
};
}

export async function parseManifest(
json: Manifest.RsdoctorManifestWithShardingFiles,
) {
Expand Down
Loading
Loading