Skip to content

Commit

Permalink
feat: support brief report page (#477)
Browse files Browse the repository at this point in the history
  • Loading branch information
easy1090 authored Aug 26, 2024
1 parent 3b00f6e commit 2175edc
Show file tree
Hide file tree
Showing 16 changed files with 389 additions and 98 deletions.
2 changes: 1 addition & 1 deletion examples/rsbuild-minimal/rsbuild.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export default defineConfig({
},
},
port: 9988,
mode: 'Brief',
mode: 'brief',
},
]);
},
Expand Down
42 changes: 40 additions & 2 deletions packages/client/rsbuild.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ export default defineConfig(({ env }) => {
},

output: {
externals: [
'@rsbuild/core',
'@rsbuild/plugin-node-polyfill',
'@rsbuild/plugin-react',
],
distPath: {
root: path.basename(DistPath),
js: 'resource/js',
Expand All @@ -59,8 +64,8 @@ export default defineConfig(({ env }) => {
media: 'resource/media',
},
assetPrefix: IS_PRODUCTION
? OFFICAL_PREVIEW_PUBLIC_PATH?.replace(/\/resource$/, '') || 'auto'
: 'auto',
? OFFICAL_PREVIEW_PUBLIC_PATH?.replace(/\/resource$/, '') || './'
: './',
cleanDistPath: IS_PRODUCTION,
sourceMap: {
js: false,
Expand All @@ -82,6 +87,39 @@ export default defineConfig(({ env }) => {
maxSize: 1000000,
minSize: 500000,
},
react: {
test: /node_modules\/react-*/,
name: 'react',
chunks: 'all',
},
rc: {
test: /node_modules\/rc-*/,
name: 'rc',
chunks: 'all',
maxSize: 1000000,
minSize: 500000,
},
antDesign: {
chunks: 'all',
name: 'ant-design',
test: /node_modules\/antd\//,
maxSize: 1000000,
minSize: 500000,
},
antDesignIcons: {
chunks: 'all',
name: 'ant-design-icons',
test: /node_modules\/@ant-design\/icons/,
maxSize: 1000000,
minSize: 50000,
},
vender: {
chunks: 'all',
name: 'vender',
test: /node_modules\/(acorn|lodash|i18next|socket.io-*|axios|remark-*)/,
maxSize: 1000000,
minSize: 200000,
},
},
},
},
Expand Down
66 changes: 46 additions & 20 deletions packages/components/src/components/Manifest/api.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Manifest, SDK } from '@rsdoctor/types';
import { Constants, Manifest, SDK } from '@rsdoctor/types';
import { Skeleton, Spin } from 'antd';
import React, { useCallback, useEffect, useState } from 'react';
import { includes, isEqual, isNil, values } from 'lodash-es';
Expand All @@ -7,16 +7,19 @@ import { ComponentState } from '../../constants';
import { FailedStatus } from '../Status';
import { BaseDataLoader } from '../../utils/data/base';

export type InferServerAPIBody<T> = SDK.ServerAPI.InferRequestBodyType<T> extends void
? {
// use `any` to avoid ts check when need not to define the body in this component.
body?: any;
}
: {
body: SDK.ServerAPI.InferRequestBodyType<T>;
};
export type InferServerAPIBody<T> =
SDK.ServerAPI.InferRequestBodyType<T> extends void
? {
// use `any` to avoid ts check when need not to define the body in this component.
body?: any;
}
: {
body: SDK.ServerAPI.InferRequestBodyType<T>;
};

type ServerAPIProviderProps<T extends SDK.ServerAPI.API | SDK.ServerAPI.APIExtends> = {
type ServerAPIProviderProps<
T extends SDK.ServerAPI.API | SDK.ServerAPI.APIExtends,
> = {
manifestLoader?: () => Promise<Manifest.RsdoctorManifestWithShardingFiles>;
api: T;
children: (response: SDK.ServerAPI.InferResponseType<T>) => JSX.Element;
Expand All @@ -35,7 +38,9 @@ type ServerAPIProviderProps<T extends SDK.ServerAPI.API | SDK.ServerAPI.APIExten
* }}
* </ServerAPIProvider>
*/
export const ServerAPIProvider = <T extends SDK.ServerAPI.API | SDK.ServerAPI.APIExtends>(
export const ServerAPIProvider = <
T extends SDK.ServerAPI.API | SDK.ServerAPI.APIExtends,
>(
props: ServerAPIProviderProps<T>,
): JSX.Element | null => {
const {
Expand All @@ -47,17 +52,24 @@ export const ServerAPIProvider = <T extends SDK.ServerAPI.API | SDK.ServerAPI.AP
showSkeleton = true,
fallbackComponent,
} = props;
let promise = manifestLoader();
const [manifest, setManifest] = useState<Manifest.RsdoctorManifestWithShardingFiles>();
let promise: Promise<Manifest.RsdoctorManifestWithShardingFiles>;

const [manifest, setManifest] =
useState<Manifest.RsdoctorManifestWithShardingFiles>();
const [state, setState] = useState(ComponentState.Pending);
const [res, setRes] = useState({} as SDK.ServerAPI.InferResponseType<T>);

const { loader } = useDataLoader(manifest);

function init(loader: BaseDataLoader | void) {
ensureManifest(promise).then(() => {
if (window[Constants.WINDOW_RSDOCTOR_TAG]) {
executeLoader(loader);
});
} else {
promise = manifestLoader();
ensureManifest(promise).then(() => {
executeLoader(loader);
});
}
}

const update = useCallback(
Expand Down Expand Up @@ -91,7 +103,9 @@ export const ServerAPIProvider = <T extends SDK.ServerAPI.API | SDK.ServerAPI.AP
};
}, [loader, api, body]);

function ensureManifest(pro: Promise<Manifest.RsdoctorManifestWithShardingFiles>) {
function ensureManifest(
pro: Promise<Manifest.RsdoctorManifestWithShardingFiles>,
) {
return pro
.then((manifest) => {
setManifest(manifest);
Expand Down Expand Up @@ -138,7 +152,8 @@ export const ServerAPIProvider = <T extends SDK.ServerAPI.API | SDK.ServerAPI.AP
}

if (state === ComponentState.Fail) {
if (fallbackComponent) return fallbackComponent as unknown as React.ReactElement;
if (fallbackComponent)
return fallbackComponent as unknown as React.ReactElement;

return (
<FailedStatus
Expand All @@ -158,7 +173,11 @@ export const ServerAPIProvider = <T extends SDK.ServerAPI.API | SDK.ServerAPI.AP
return children(res);
};

export function withServerAPI<T, P extends keyof T, A extends SDK.ServerAPI.API | SDK.ServerAPI.APIExtends>({
export function withServerAPI<
T,
P extends keyof T,
A extends SDK.ServerAPI.API | SDK.ServerAPI.APIExtends,
>({
Component,
api,
responsePropName,
Expand All @@ -171,13 +190,20 @@ export function withServerAPI<T, P extends keyof T, A extends SDK.ServerAPI.API
responsePropName: P;
fallbackComponent?: React.FC;
showSkeleton?: boolean;
} & Partial<Partial<InferServerAPIBody<A>>>): React.FC<Omit<T, P> & Partial<InferServerAPIBody<A>>> {
} & Partial<Partial<InferServerAPIBody<A>>>): React.FC<
Omit<T, P> & Partial<InferServerAPIBody<A>>
> {
return function _(props) {
const { body = bodyInRoot, ...rest } = props;

return (
// @ts-ignore
<ServerAPIProvider api={api} body={body} showSkeleton={showSkeleton} fallbackComponent={fallbackComponent}>
<ServerAPIProvider
api={api}
body={body}
showSkeleton={showSkeleton}
fallbackComponent={fallbackComponent}
>
{(res) => {
const _props = {
...rest,
Expand Down
4 changes: 4 additions & 0 deletions packages/components/src/typings/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
interface Window {
[key: string]: any;
__RSDOCTOR__: any;
}
63 changes: 63 additions & 0 deletions packages/components/src/utils/data/brief.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { Manifest, SDK } from '@rsdoctor/types';
import { Algorithm } from '@rsdoctor/utils/common';
import { BaseDataLoader } from './base';
import { Constants } from '@rsdoctor/types';

export class BriefDataLoader extends BaseDataLoader {
public isLocal() {
return false;
}

public async loadData<T extends Manifest.RsdoctorManifestMappingKeys>(
key: T,
): Promise<Manifest.InferManifestDataValue<T>>;

public async loadData(key: string): Promise<unknown> {
console.log(`[loadData]-[key]: ${key}`);
const [scope] = this.getKeys(key);

console.log(`[loadData]-[scope]: ${scope}`);
const data = this.getData(scope);
console.log(`[loadData]-[data]: ${data}`);

if (!data) return;

let res = data;

// only cache by the root key in data
if (!this.shardingDataMap.has(scope)) {
const scopeData =
typeof res === 'object'
? res
: JSON.parse(Algorithm.decompressText(res));
console.log(`[loadData]-[scopeData]: ${scopeData}`);
this.shardingDataMap.set(scope, scopeData);
}

res = await this.shardingDataMap.get(scope);
return res;
}

public getData(scope: keyof Manifest.RsdoctorManifestData) {
console.log(`[getData]-[scope]: ${scope}`);
return window[Constants.WINDOW_RSDOCTOR_TAG][scope];
}

public async loadAPI<
T extends SDK.ServerAPI.API,
B extends
SDK.ServerAPI.InferRequestBodyType<T> = SDK.ServerAPI.InferRequestBodyType<T>,
R extends
SDK.ServerAPI.InferResponseType<T> = SDK.ServerAPI.InferResponseType<T>,
>(...args: B extends void ? [api: T] : [api: T, body: B]): Promise<R> {
return this.loader.loadAPI(...args) as R;
}

public dispose() {
super.dispose();
}

public onDataUpdate() {}

public removeOnDataUpdate() {}
}
32 changes: 26 additions & 6 deletions packages/components/src/utils/data/index.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,33 @@
import { Manifest } from '@rsdoctor/types';
import { Constants, Manifest } from '@rsdoctor/types';
import { useEffect, useState } from 'react';
import { LocalServerDataLoader } from './local';
import { RemoteDataLoader } from './remote';
import { BaseDataLoader } from './base';
import { getAPILoaderModeFromStorage } from '../storage';
import { APILoaderMode4Dev } from '../../constants';
import { BriefDataLoader } from './brief';

const loaderTask = new WeakMap<Manifest.RsdoctorManifestWithShardingFiles, Promise<BaseDataLoader>>();
const loaderTask = new WeakMap<
Manifest.RsdoctorManifestWithShardingFiles,
Promise<BaseDataLoader>
>();

async function createDataLoader(manifest: Manifest.RsdoctorManifestWithShardingFiles) {
async function createDataLoader(
manifest: Manifest.RsdoctorManifestWithShardingFiles,
) {
try {
if (process.env.NODE_ENV === 'development') {
const mode = getAPILoaderModeFromStorage();
if (mode === APILoaderMode4Dev.Local) return new LocalServerDataLoader(manifest);
if (mode === APILoaderMode4Dev.Remote) return new RemoteDataLoader(manifest);
console.log(`[development]-${mode}`);
if (mode === APILoaderMode4Dev.Local)
return new LocalServerDataLoader(manifest);
if (mode === APILoaderMode4Dev.Remote)
return new RemoteDataLoader(manifest);
}

// local server exists
if (manifest.__LOCAL__SERVER__) {
console.log(`[LocalServerDataLoader]`);
return new LocalServerDataLoader(manifest);
}
} catch (error) {
Expand All @@ -27,9 +37,19 @@ async function createDataLoader(manifest: Manifest.RsdoctorManifestWithShardingF
return new RemoteDataLoader(manifest);
}

export function useDataLoader(manifest: Manifest.RsdoctorManifestWithShardingFiles | void) {
export function useDataLoader(
manifest: Manifest.RsdoctorManifestWithShardingFiles | void,
) {
const [loader, setLoader] = useState<BaseDataLoader | void>(undefined);

useEffect(() => {
if (window[Constants.WINDOW_RSDOCTOR_TAG]) {
console.log('[brief mode]');
const loader = new BriefDataLoader({ data: [] } as any);
setLoader(loader);
}
}, []);

useEffect(() => {
if (!manifest) return;

Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/inner-plugins/utils/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export function normalizeUserConfig<Rules extends Linter.ExtendRuleData[]>(
supports = { parseBundle: true, banner: false, generateTileGraph: true },
port,
printLog = { serverUrls: true },
mode = 'Normal',
mode = 'normal',
} = config;

assert(linter && typeof linter === 'object');
Expand Down Expand Up @@ -75,7 +75,7 @@ export function normalizeUserConfig<Rules extends Linter.ExtendRuleData[]>(
? loaderInterceptorOptions.skipLoaders
: [],
},
disableClientServer,
disableClientServer: mode === 'brief' ? true : disableClientServer,
sdkInstance,
/**
* Data storage is divided into three types:
Expand Down
6 changes: 3 additions & 3 deletions packages/core/src/types/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ export interface RsdoctorWebpackPluginOptions<

/**
* Rsdoctor mode option:
* - Normal: Refers to the normal mode.
* - Brief: Refers to the brief mode, which only displays the results of the duration analysis and build artifact analysis
* - normal: Refers to the normal mode.
* - brief: Refers to the brief mode, which only displays the results of the duration analysis and build artifact analysis
* and does not display any part of the code.
* - Lite: Refers to the lightweight mode,
* - lite: Refers to the lightweight mode,
* which is a lightweight analysis report in the normal mode with the source code display removed.
*/
mode?: SDK.IMode;
Expand Down
2 changes: 2 additions & 0 deletions packages/sdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,11 @@
"@rsdoctor/graph": "workspace:*",
"@rsdoctor/types": "workspace:*",
"@rsdoctor/utils": "workspace:*",
"@types/fs-extra": "^11.0.4",
"body-parser": "1.20.2",
"cors": "2.8.5",
"dayjs": "1.11.12",
"fs-extra": "^11.1.1",
"lodash": "^4.17.21",
"open": "^8.4.2",
"serve-static": "1.15.0",
Expand Down
Loading

0 comments on commit 2175edc

Please sign in to comment.