Skip to content

Commit

Permalink
feat(devtools): built-in doctor tab for rsdoctor (#5368)
Browse files Browse the repository at this point in the history
  • Loading branch information
Asuka109 authored Feb 21, 2024
1 parent 9925d6a commit 8c9956a
Show file tree
Hide file tree
Showing 48 changed files with 1,315 additions and 366 deletions.
9 changes: 9 additions & 0 deletions .changeset/wicked-toes-beg.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
'@integration-test/devtools': minor
'@modern-js/devtools-client': minor
'@modern-js/plugin-devtools': minor
'@modern-js/devtools-kit': minor
---

feat(devtools): add new doctor tab to show overview of rsdoctor
feat(devtools): 新增 doctor 页面展示 Rsdoctor 概览信息
16 changes: 16 additions & 0 deletions packages/devtools/client/modern.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,22 @@ export default defineConfig<'rspack'>({
disableInlineRuntimeChunk: true,
disableSourceMap: process.env.NODE_ENV === 'production',
},
performance: {
chunkSplit: {
strategy: 'split-by-experience',
override: {
cacheGroups: {
components: {
test: /\/src\/components\/.*\.(scss|css)$/,
chunks: 'all',
name: 'components',
enforce: true,
priority: 9999,
},
},
},
},
},
tools: {
postcss: (config, { addPlugins }) => {
addPlugins(require('postcss-custom-media'));
Expand Down
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.indicate-card {
border-radius: var(--radius-5);
box-shadow: var(--shadow-4);
padding: var(--space-5);
:global(.dark) & {
background-color: var(--gray-1);
}
}
35 changes: 35 additions & 0 deletions packages/devtools/client/src/components/Card/Indicate.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { FC } from 'react';
import clsx from 'clsx';
import { Box, Flex } from '@radix-ui/themes';
import type { BoxProps } from '@radix-ui/themes/dist/cjs/components/box';
import type { FlexProps } from '@radix-ui/themes/dist/cjs/components/flex';
import styles from './Indicate.module.scss';

export type IndicateCardProps = BoxProps & React.RefAttributes<HTMLDivElement>;

const Card: FC<IndicateCardProps> = ({ children, className, ...props }) => {
return (
<Box {...props} className={clsx(styles.indicateCard, className)}>
{children}
</Box>
);
};

Card.displayName = 'IndicateCard';

const Column: FC<FlexProps> = props => (
<Flex
gap="2"
height="100%"
justify="center"
direction="column"
align="start"
{...props}
/>
);

Column.displayName = 'IndicateCard.Column';

export const IndicateCard = Object.assign(Card, {
Column,
});
1 change: 1 addition & 0 deletions packages/devtools/client/src/components/Card/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './Indicate';
24 changes: 21 additions & 3 deletions packages/devtools/client/src/components/Devtools/Capsule.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { SetupClientParams } from '@modern-js/devtools-kit/runtime';
import { Flex, Theme } from '@radix-ui/themes';
import React, { useEffect, useState } from 'react';
import { useEvent, useToggle } from 'react-use';
import { useAsync, useEvent, useToggle } from 'react-use';
import { HiMiniCursorArrowRipple } from 'react-icons/hi2';
import { withQuery } from 'ufo';
import Visible from '../Visible';
Expand All @@ -13,9 +13,21 @@ import { $client, wallAgent } from '@/entries/mount/state';
import { pTimeout } from '@/utils/promise';
import { ReactDevtoolsWallListener } from '@/utils/react-devtools';

const parseDeepLink = (url = window.location) => {
// Expected: #/__devtools/doctor
const { hash } = url;
// Parse pathname from hash.
const pathname = hash.match(/^#\/__devtools(.*)/)?.[1];
// Check if match the expected pattern.
if (typeof pathname !== 'string') return null;
if (pathname === '') return '/';
return pathname;
};

export const DevtoolsCapsule: React.FC<SetupClientParams> = props => {
const logoSrc = props.def.assets.logo;
const [showDevtools, toggleDevtools] = useToggle(false);
const deepLink = parseDeepLink();
const [showDevtools, toggleDevtools] = useToggle(Boolean(deepLink));
const [loadDevtools, setLoadDevtools] = useState(false);

const src = withQuery(props.endpoint, { src: props.dataSource });
Expand Down Expand Up @@ -64,13 +76,19 @@ export const DevtoolsCapsule: React.FC<SetupClientParams> = props => {
setLoadDevtools(true);
try {
const client = await pTimeout($client, 10_000);
client.remote.pullUpReactInspector();
client.remote.pullUp('/react/components#inspecting');
} catch (e) {
console.error(e);
document.documentElement.style.removeProperty('cursor');
}
};

useAsync(async () => {
if (!deepLink) return;
const client = await pTimeout($client, 10_000);
client.remote.pullUp(deepLink);
}, []);

return (
<Theme appearance={appearance} className={appearance}>
<Visible when={showDevtools} keepAlive={true} load={loadDevtools}>
Expand Down
25 changes: 8 additions & 17 deletions packages/devtools/client/src/components/Devtools/Puller.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,23 @@ import React, { useEffect } from 'react';
import { useNavigate } from '@modern-js/runtime/router';
import { useThrowable } from '@/utils';
import { $mountPoint } from '@/entries/client/routes/state';
import { wallAgent } from '@/entries/client/routes/react/state';

let _intendPullUp = false;
let _intendPullUp = '';

$mountPoint.then(({ hooks }) => {
hooks.hookOnce('pullUpReactInspector', async () => {
_intendPullUp = true;
hooks.hookOnce('pullUp', async target => {
_intendPullUp = target;
});
});

export const DevtoolsPuller: React.FC = () => {
export const Puller: React.FC = () => {
const navigate = useNavigate();
const mountPoint = useThrowable($mountPoint);
const handlePullUp = async () => {
navigate('/react');
if (wallAgent.status === 'active') {
wallAgent.send('startInspectingNative', null);
} else {
wallAgent.hookOnce('active', () => {
wallAgent.send('startInspectingNative', null);
});
}
};
useEffect(() => {
_intendPullUp && handlePullUp();
mountPoint.hooks.hook('pullUpReactInspector', handlePullUp);
_intendPullUp && navigate(_intendPullUp);
mountPoint.hooks.hook('pullUp', async target => {
navigate(target);
});
}, []);
return null;
};
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,12 @@ export const ErrorFallback: React.FC<ErrorFallbackProps> = props => {
<Heading as="h4" mb="4">
<Text as="span">{title}</Text>
</Heading>
<TextArea disabled style={{ height: '50vh' }}>
{description}
</TextArea>
<TextArea disabled style={{ height: '50vh' }} value={description} />
</Box>
);
};

export const ErrorRouteHandler: React.FC<ErrorFallbackProps> = props => {
export const ErrorRouteHandler: React.FC = () => {
const error = useRouteError();
return <ErrorFallback {...props} error={error} />;
return <ErrorFallback resetErrorBoundary={() => null} error={error} />;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.container {
width: max-content;
min-width: var(--space-9);
color: var(--gray-11);
}

.children {
color: var(--gray-9);
}
25 changes: 25 additions & 0 deletions packages/devtools/client/src/components/Error/FeatureDisabled.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React, { PropsWithChildren } from 'react';
import { Box, Flex, Heading } from '@radix-ui/themes';
import { HiExclamationCircle } from 'react-icons/hi2';
import styles from './FeatureDisabled.module.scss';

export interface FeatureDisabledProps extends PropsWithChildren {
title: string;
}

export const FeatureDisabled: React.FC<FeatureDisabledProps> = props => {
const { title, children } = props;
return (
<Flex className={styles.container} mt="9" mx="auto" gap="2">
<Flex height="9" align="center">
<HiExclamationCircle size="36" />
</Flex>
<Box>
<Flex height="9" align="center">
<Heading>{title}</Heading>
</Flex>
<Box className={styles.children}>{children}</Box>
</Box>
</Flex>
);
};
Empty file.
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import { ErrorRouteHandler } from '@/components/ErrorFallback/ErrorFallback';
import { ErrorRouteHandler } from '@/components/Error/Fallback';

export default ErrorRouteHandler;
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import { ErrorRouteHandler } from '@/components/ErrorFallback/ErrorFallback';
import { ErrorRouteHandler } from '@/components/Error/Fallback';

export default ErrorRouteHandler;
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { FC } from 'react';
import { useRouteError } from '@modern-js/runtime/router';
import { Box, Link } from '@radix-ui/themes';
import { useSnapshot } from 'valtio';
import { parseURL } from 'ufo';
import { $definition } from '../state';
import {
ErrorFallbackProps,
ErrorRouteHandler,
} from '@/components/Error/Fallback';
import { FeatureDisabled } from '@/components/Error/FeatureDisabled';

const Handler: FC<ErrorFallbackProps> = () => {
const error = useRouteError();
const def = useSnapshot($definition);
const isStateError =
error && typeof error === 'object' && Object.keys(error).length === 0;
if (isStateError) {
const websiteDisplay = parseURL(def.doctor.quickStart).host;
const websiteLink = (
<Link
href={def.doctor.quickStart}
target="_blank"
rel="noopener noreferrer"
>
🔗{websiteDisplay}
</Link>
);
return (
<Box width="100%">
<FeatureDisabled title="Doctor is not working">
Visit the website of {websiteLink} to learn more.
</FeatureDisabled>
</Box>
);
} else {
return <ErrorRouteHandler />;
}
};

export default Handler;
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export const handle = {
breadcrumb: {
title: 'Doctor',
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
.container {
max-width: 40rem;
width: 100%;
}

.primary-card {
flex: 4;
min-width: max-content;
background-color: var(--amber-9);
:global(.dark) & {
background-color: var(--amber-9);
}
button {
border: none;
border-radius: var(--radius-thumb);
color: var(--black-a8);
font-size: var(--font-size-1);
font-weight: var(--font-weight-regular);
padding: var(--space-1) var(--space-2);
overflow: hidden;
background-color: var(--black-a2);
&:hover,
&:active {
background-color: var(--black-a1);
}
}
}

.info-card {
flex: 2;
min-width: max-content;
}

.count-card {
flex: 1;
min-width: max-content;
}

.compile-cost-card {
flex: 4;
}

.logo {
width: var(--space-8);
opacity: 0.5;
}

.count-text {
display: flex;
align-items: center;
gap: var(--space-1);
}

.error-item {
display: flex;
align-items: center;
width: 100%;
gap: var(--space-1);
color: var(--gray-11);
}

.text-truncation {
width: 100%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}

.cost-box {
min-width: var(--space-2);

.cost-bar {
height: var(--space-1);
width: 100%;
border-radius: var(--radius-thumb);
}

&:nth-child(odd) {
.cost-bar {
background-color: var(--red-9);
}
}

&:nth-child(even) {
.cost-bar {
background-color: var(--orange-9);
}
}

.cost-label {
word-break: keep-all;
display: block;
margin-bottom: var(--space-2);
}
}

.heading {
font-family: 'NotoSans';
font-weight: 900;
font-size: var(--font-size-7);
}
Loading

0 comments on commit 8c9956a

Please sign in to comment.