Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion examples/modern-minimal/modern.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export default defineConfig({
},
},
disableClientServer: !process.env.ENABLE_CLIENT_SERVER,
features: ['bundle', 'plugins', 'loader'],
features: ['bundle', 'plugins', 'loader', 'resolver'],
},
]);
},
Expand Down
1 change: 1 addition & 0 deletions examples/rsbuild-minimal/rsbuild.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export default defineConfig({
chain.plugin('Rsdoctor').use(RsdoctorRspackPlugin, [
{
disableClientServer: !process.env.ENABLE_CLIENT_SERVER,
features: ['resolver', 'bundle', 'plugins', 'loader'],
output: {
mode: 'brief',
options: {
Expand Down
177 changes: 86 additions & 91 deletions packages/components/src/components/Resolver/analysis.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
/* eslint-disable react/no-unescaped-entities */
import {
CloseCircleOutlined,
FileSearchOutlined,
MenuFoldOutlined,
MenuUnfoldOutlined,
} from '@ant-design/icons';
import { CloseCircleOutlined, FileSearchOutlined } from '@ant-design/icons';
import { SDK } from '@rsdoctor/types';
import { Resolver } from '@rsdoctor/utils/common';
import { Button, Card, Col, Row, Space, Table, Typography } from 'antd';
import { Card, Col, Row, Space, Table, Tabs, Typography } from 'antd';
import { get } from 'es-toolkit/compat';
import React, { useMemo, useState } from 'react';
import { Size } from '../../constants';
Expand All @@ -22,91 +17,91 @@ const height = 735;
const ResolverDetailsPanel: React.FC<
SDK.ServerAPI.InferResponseType<SDK.ServerAPI.API.GetResolverFileDetails>
> = ({ filepath, before, after, resolvers }) => {
const [collapsed, setCollapsed] = useState(false);

return (
<React.Fragment>
<Col flex={1}>
<Card
title="Resolve Diff Viewer"
styles={{ body: { padding: 0, overflow: 'hidden' } }}
>
<DiffViewer
style={{
height: height + 50,
}}
isEmbed
originalFilePath={filepath}
modifiedFilePath={filepath}
original={before}
modified={after}
/>
</Card>
</Col>
<Col span={collapsed ? 2 : 7}>
<Card
title={collapsed ? '...' : 'Resolve Details'}
extra={
<Button
onClick={() => setCollapsed(!collapsed)}
size="small"
icon={collapsed ? <MenuFoldOutlined /> : <MenuUnfoldOutlined />}
></Button>
}
style={collapsed ? { width: 80 } : undefined}
>
{collapsed ? null : (
<Table
style={{
width: '100%',
height,
overflowY: 'scroll',
wordBreak: 'break-all',
}}
size="small"
pagination={false}
bordered
rowKey={(e) => e.request}
columns={[
{
title: 'Source Code',
width: 200,
render: (_v, r) => (
<Typography.Text copyable>
<Typography.Text code strong>
{r.request}
</Typography.Text>
</Typography.Text>
),
},
{
title: 'Duration',
width: 80,
render: (_v, r) => (
<Typography.Text strong>
{formatCosts(r.costs)}
</Typography.Text>
),
sorter: (a, b) => a.costs - b.costs,
sortDirections: ['descend', 'ascend'],
},
{
title: 'Resolve Result',
render: (_v, r) => {
if (Resolver.isResolveSuccessData(r))
return (
<Typography.Text copyable>{r.result}</Typography.Text>
);
return <CloseCircleOutlined style={{ color: '#f50' }} />;
},
},
]}
dataSource={resolvers}
/>
)}
</Card>
</Col>
</React.Fragment>
<Col flex={1}>
<Tabs
defaultActiveKey="diff"
items={[
{
key: 'diff',
label: 'Resolve Diff Viewer',
children: (
<Card styles={{ body: { padding: 0, overflow: 'hidden' } }}>
<DiffViewer
style={{
height: height + 50,
}}
isEmbed
originalFilePath={filepath}
modifiedFilePath={filepath}
original={before}
modified={after}
/>
</Card>
),
},
{
key: 'details',
label: 'Resolve Details',
children: (
<Card>
<Table
style={{
width: '100%',
height,
overflowY: 'scroll',
wordBreak: 'break-all',
}}
size="small"
pagination={false}
bordered
rowKey={(e) => e.request}
columns={[
{
title: 'Source Code',
width: 200,
render: (_v, r) => (
<Typography.Text copyable>
<Typography.Text code strong>
{r.request}
</Typography.Text>
</Typography.Text>
),
},
{
title: 'Duration',
width: 80,
render: (_v, r) => (
<Typography.Text strong>
{formatCosts(r.costs)}
</Typography.Text>
),
sorter: (a, b) => a.costs - b.costs,
sortDirections: ['descend', 'ascend'],
},
{
title: 'Resolve Result',
render: (_v, r) => {
if (Resolver.isResolveSuccessData(r))
return (
<Typography.Text copyable>
{r.result}
</Typography.Text>
);
return (
<CloseCircleOutlined style={{ color: '#f50' }} />
);
},
},
]}
dataSource={resolvers}
/>
</Card>
),
},
]}
/>
</Col>
);
};

Expand Down
1 change: 1 addition & 0 deletions packages/core/src/inner-plugins/plugins/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ export * from './bundle';
export * from './ensureModulesChunkGraph';
export * from './rules';
export * from './bundleTagPlugin';
export * from './resolver';
95 changes: 95 additions & 0 deletions packages/core/src/inner-plugins/plugins/resolver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { Manifest, Plugin, SDK } from '@rsdoctor/types';
import { Time } from '@rsdoctor/utils/common';
import { InternalBasePlugin } from './base';
import type { Compiler as WebpackCompiler } from 'webpack';

export class InternalResolverPlugin<
T extends Plugin.BaseCompiler,
> extends InternalBasePlugin<T> {
public readonly name = 'resolver';

protected resolveDataMap = new Map<
string,
{ startAt: number; startHRTime: [number, number]; request: string }
>();

public apply(compiler: T) {
// resolver depends on module graph
this.scheduler.ensureModulesChunksGraphApplied(compiler);
compiler.hooks.normalModuleFactory.tap(
this.tapPostOptions,
this.handleNormalModuleFactory,
);

// add resolver page to client
this.sdk.addClientRoutes([
Manifest.RsdoctorManifestClientRoutes.ModuleResolve,
]);
}

protected handleNormalModuleFactory = (
normalModuleFactory:
| Plugin.RspackNormalModuleFactory
| ReturnType<WebpackCompiler['createNormalModuleFactory']>,
) => {
// Hook into beforeResolve to capture the start time
normalModuleFactory.hooks.beforeResolve.tap(
this.tapPostOptions,
(resolveData: any) => {
if (!resolveData) return;

const issuer =
resolveData.contextInfo?.issuer || resolveData.context || '';
const request = resolveData.request;

if (issuer && request) {
const key = `${issuer}::${request}`;
this.resolveDataMap.set(key, {
startAt: Date.now(),
startHRTime: process.hrtime(),
request,
});
}
},
);

// Hook into afterResolve to capture the result and report
normalModuleFactory.hooks.afterResolve.tap(
this.tapPostOptions,
(resolveData: any) => {
if (!resolveData) return;

const issuer =
resolveData.contextInfo?.issuer || resolveData.context || '';
const request = resolveData.request;
const result =
resolveData.createData?.resource ||
resolveData.resourceResolveData?.path;

if (issuer && request) {
const key = `${issuer}::${request}`;
const startData = this.resolveDataMap.get(key);

if (startData) {
const data: SDK.PathResolverSuccessData = {
isEntry: Boolean(issuer),
issuerPath: issuer,
request: startData.request,
startAt: startData.startAt,
endAt: Time.getCurrentTimestamp(
startData.startAt,
startData.startHRTime,
),
result: result || '',
pid: process.pid,
ppid: process.ppid,
};

this.sdk.reportResolver([data]);
this.resolveDataMap.delete(key);
}
}
},
);
};
}
7 changes: 7 additions & 0 deletions packages/rspack-plugin/src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
InternalErrorReporterPlugin,
InternalLoaderPlugin,
InternalPluginsPlugin,
InternalResolverPlugin,
InternalRulesPlugin,
InternalSummaryPlugin,
normalizeRspackUserOptions,
Expand Down Expand Up @@ -154,6 +155,12 @@ export class RsdoctorRspackPlugin<Rules extends Linter.ExtendRuleData[]>
).apply(compiler);
}

if (this.options.features.resolver) {
new InternalResolverPlugin<Plugin.BaseCompilerType<'rspack'>>(
this,
).apply(compiler);
}

if (this.options.features.resolver) {
logger.info(
chalk.yellow(
Expand Down
28 changes: 27 additions & 1 deletion packages/types/src/plugin/rspack.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
import type { RsdoctorPluginData } from '@rspack/core';
// biome-ignore assist/source/organizeImports: <explanation>
import type {
RsdoctorPluginData,
NormalModuleFactory,
LoaderDefinitionFunction,
ModuleGraph,
Dependency,
} from '@rspack/core';
export type RspackNormalModuleFactory = NormalModuleFactory;

export type RspackNativeAsset = RsdoctorPluginData.RsdoctorAsset;
export type RspackNativeChunkGraph = RsdoctorPluginData.RsdoctorChunkGraph;
Expand Down Expand Up @@ -28,3 +36,21 @@ export type RspackNativeModuleSourcePatch =
import rspack from '@rspack/core';

export type RspackExportsExperiments = typeof rspack.experiments;

export type RspackSourceMapInput = Parameters<LoaderDefinitionFunction>[1];
// export type SourceMap = Exclude<SourceMapInput, string | undefined>;
export type RspackEntryPoint = boolean | 'auto';
export interface RspackExportInfo {
used: boolean;
provideInfo: boolean | null | undefined;
useInfo: boolean | null | undefined;
canMangle: boolean;
}

export type RspackExportsInfo = ReturnType<ModuleGraph['getExportsInfo']>;

export interface RspackHarmonyImportSpecifierDependency extends Dependency {
getIds(graph: ModuleGraph): string[];
name: string;
userRequest: string;
}
6 changes: 3 additions & 3 deletions packages/types/src/sdk/instance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ import { RuntimeContext, RuntimeContextOptions } from './context';
import { Hooks } from './hooks';
import { ChunkGraphInstance } from './chunk';
import { RsdoctorServerInstance } from './server';
import { PlainObject } from '@/common';
import { BriefModeOptions } from '@/config';
import { EmoCheckData } from '@/emo';
import { PlainObject } from '../common';
import { BriefModeOptions } from '../config';
import { EmoCheckData } from '../emo';
import { SummaryData } from './summary';
import { ConfigData } from './config';

Expand Down
Loading