From 514f9e76e73ccc48a77b2551bfa3df809d63844d Mon Sep 17 00:00:00 2001 From: yifancong Date: Fri, 10 Jan 2025 12:52:58 +0800 Subject: [PATCH] feat(ui): optimize the bundle size page (#671) --- examples/modern-minimal/modern.config.ts | 1 - examples/rsbuild-minimal/package.json | 2 +- examples/rsbuild-minimal/rsbuild.config.ts | 2 +- .../src/components/CodeViewer/viewer.tsx | 8 - .../src/components/FileTree/css.svg | 5 + .../src/components/FileTree/html.svg | 7 + .../src/components/FileTree/image.svg | 5 + .../src/components/FileTree/index.scss | 4 +- .../components/src/components/FileTree/js.svg | 6 + .../src/components/FileTree/unkown-file.svg | 5 + .../src/components/Form/keyword.tsx | 4 +- .../src/components/Keyword/index.tsx | 12 +- .../src/components/Keyword/style.module.scss | 2 +- .../components/Layout/bundle-size-icon.svg | 4 + .../src/components/Layout/compile-icon.svg | 7 + .../src/components/Layout/overall-icon.svg | 4 + .../src/components/Loader/Analysis/index.tsx | 2 +- .../src/components/Loader/Analysis/input.svg | 5 + .../src/components/Loader/Analysis/output.svg | 6 + .../components/src/components/Loader/step.svg | 3 + .../src/components/TextDrawer/index.tsx | 8 +- .../src/pages/BundleSize/components/asset.tsx | 282 +++++++++--------- .../BundleSize/components/index.module.scss | 89 ++++++ .../src/pages/BundleSize/components/index.tsx | 267 ++++++++--------- .../ModuleAnalyze/components/fileTreeCom.scss | 39 ++- .../ModuleAnalyze/components/fileTreeCom.tsx | 121 +++----- .../src/pages/ModuleAnalyze/fileTree.tsx | 232 +++----------- .../src/pages/ModuleAnalyze/index.scss | 8 +- .../src/pages/ModuleAnalyze/index.tsx | 223 ++++++++++---- .../src/pages/WebpackPlugins/index.tsx | 7 +- packages/components/src/utils/file.tsx | 78 ++++- packages/document/package.json | 4 +- pnpm-lock.yaml | 113 ++++--- 33 files changed, 837 insertions(+), 728 deletions(-) create mode 100644 packages/components/src/components/FileTree/css.svg create mode 100644 packages/components/src/components/FileTree/html.svg create mode 100644 packages/components/src/components/FileTree/image.svg create mode 100644 packages/components/src/components/FileTree/js.svg create mode 100644 packages/components/src/components/FileTree/unkown-file.svg create mode 100644 packages/components/src/components/Layout/bundle-size-icon.svg create mode 100644 packages/components/src/components/Layout/compile-icon.svg create mode 100644 packages/components/src/components/Layout/overall-icon.svg create mode 100644 packages/components/src/components/Loader/Analysis/input.svg create mode 100644 packages/components/src/components/Loader/Analysis/output.svg create mode 100644 packages/components/src/components/Loader/step.svg create mode 100644 packages/components/src/pages/BundleSize/components/index.module.scss diff --git a/examples/modern-minimal/modern.config.ts b/examples/modern-minimal/modern.config.ts index 4d0ae3f8..86cef406 100644 --- a/examples/modern-minimal/modern.config.ts +++ b/examples/modern-minimal/modern.config.ts @@ -26,7 +26,6 @@ export default defineConfig({ { disableClientServer: !process.env.ENABLE_CLIENT_SERVER, features: ['bundle', 'plugins', 'loader'], - mode: 'brief', }, ]); }, diff --git a/examples/rsbuild-minimal/package.json b/examples/rsbuild-minimal/package.json index 2cbae2bc..2a0f339c 100644 --- a/examples/rsbuild-minimal/package.json +++ b/examples/rsbuild-minimal/package.json @@ -21,7 +21,7 @@ "semver7": "npm:semver@7.5.4" }, "devDependencies": { - "@rsbuild/core": "^1.1.1", + "@rsbuild/core": "^1.1.3", "@rsbuild/plugin-react": "^1.0.7", "@rsdoctor/core": "workspace:*", "@rsdoctor/rspack-plugin": "workspace:*", diff --git a/examples/rsbuild-minimal/rsbuild.config.ts b/examples/rsbuild-minimal/rsbuild.config.ts index f0298b58..a34470a3 100644 --- a/examples/rsbuild-minimal/rsbuild.config.ts +++ b/examples/rsbuild-minimal/rsbuild.config.ts @@ -33,7 +33,7 @@ export default defineConfig({ }, }, port: 9988, - mode: 'brief', + // mode: 'brief', }, ]); }, diff --git a/packages/components/src/components/CodeViewer/viewer.tsx b/packages/components/src/components/CodeViewer/viewer.tsx index 3e1f03fa..50005aa2 100644 --- a/packages/components/src/components/CodeViewer/viewer.tsx +++ b/packages/components/src/components/CodeViewer/viewer.tsx @@ -1,9 +1,7 @@ -/* eslint-disable financial/no-float-calculation */ import React from 'react'; import { SDK } from '@rsdoctor/types'; import Editor, { OnMount } from '@monaco-editor/react'; import { isNumber } from 'lodash-es'; -import { CodepenCircleOutlined } from '@ant-design/icons'; import type { editor } from 'monaco-editor'; import { getOriginalLanguage, getSelectionRange } from '../../utils'; import { DefaultEditorConfig } from './config'; @@ -64,12 +62,6 @@ export const CodeViewerWithDrawer: React.FC = (props) => { return ( , - type: 'default', - }} - buttonStyle={{ padding: `0 4px` }} drawerProps={{ destroyOnClose: true, title: `Code of "${props.path}"`, diff --git a/packages/components/src/components/FileTree/css.svg b/packages/components/src/components/FileTree/css.svg new file mode 100644 index 00000000..452c16a0 --- /dev/null +++ b/packages/components/src/components/FileTree/css.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/packages/components/src/components/FileTree/html.svg b/packages/components/src/components/FileTree/html.svg new file mode 100644 index 00000000..a69ac2de --- /dev/null +++ b/packages/components/src/components/FileTree/html.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/packages/components/src/components/FileTree/image.svg b/packages/components/src/components/FileTree/image.svg new file mode 100644 index 00000000..bcd8560e --- /dev/null +++ b/packages/components/src/components/FileTree/image.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/packages/components/src/components/FileTree/index.scss b/packages/components/src/components/FileTree/index.scss index d7c8726b..c92f74ea 100644 --- a/packages/components/src/components/FileTree/index.scss +++ b/packages/components/src/components/FileTree/index.scss @@ -19,7 +19,7 @@ $treeNodePrefixCls: '#{$treePrefixCls}-treenode'; height: 24px; margin: 0; padding: 0 4px; - font-size: 12px; + font-size: 14px; font-weight: 400; color: rgba(0, 0, 0, 0.85); box-sizing: border-box; @@ -76,5 +76,5 @@ $treeNodePrefixCls: '#{$treePrefixCls}-treenode'; .file-icon { display: inline-block; padding: 2px 0; - margin-left: 7px; + margin-left: 8px; } diff --git a/packages/components/src/components/FileTree/js.svg b/packages/components/src/components/FileTree/js.svg new file mode 100644 index 00000000..0e9f58fd --- /dev/null +++ b/packages/components/src/components/FileTree/js.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/packages/components/src/components/FileTree/unkown-file.svg b/packages/components/src/components/FileTree/unkown-file.svg new file mode 100644 index 00000000..bb380d45 --- /dev/null +++ b/packages/components/src/components/FileTree/unkown-file.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/packages/components/src/components/Form/keyword.tsx b/packages/components/src/components/Form/keyword.tsx index f1c36f85..fbd617ac 100644 --- a/packages/components/src/components/Form/keyword.tsx +++ b/packages/components/src/components/Form/keyword.tsx @@ -58,9 +58,9 @@ export const KeywordInput: React.FC = ({ style={{ width: width ? width - labelWidth : 250 }} placeholder={placeholder} onChange={(e) => { - clearTimeout(timer); + if (timer) clearTimeout(timer); const v = e.target.value.trim(); - setTimeout(() => { + timer = setTimeout(() => { setFilename(v); }, delay); }} diff --git a/packages/components/src/components/Keyword/index.tsx b/packages/components/src/components/Keyword/index.tsx index fd988b01..79382e6c 100644 --- a/packages/components/src/components/Keyword/index.tsx +++ b/packages/components/src/components/Keyword/index.tsx @@ -36,7 +36,11 @@ export const Keyword: React.FC< } } - return {els}; + return ( + + {els} + + ); }; const EllipsisText = ({ @@ -59,8 +63,8 @@ const EllipsisText = ({ const end = Math.ceil((MAX_LENGTH - 3) / 2); return ( - -
+ +
{text.slice(0, start)}...{text.slice(textLength - end)} @@ -71,7 +75,7 @@ const EllipsisText = ({ return ( -
+
+ + + diff --git a/packages/components/src/components/Layout/compile-icon.svg b/packages/components/src/components/Layout/compile-icon.svg new file mode 100644 index 00000000..a3a4f35e --- /dev/null +++ b/packages/components/src/components/Layout/compile-icon.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/packages/components/src/components/Layout/overall-icon.svg b/packages/components/src/components/Layout/overall-icon.svg new file mode 100644 index 00000000..14b65058 --- /dev/null +++ b/packages/components/src/components/Layout/overall-icon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/packages/components/src/components/Loader/Analysis/index.tsx b/packages/components/src/components/Loader/Analysis/index.tsx index d2a7bfc4..5b3d20de 100644 --- a/packages/components/src/components/Loader/Analysis/index.tsx +++ b/packages/components/src/components/Loader/Analysis/index.tsx @@ -25,7 +25,7 @@ export const LoaderAnalysisBase: React.FC<{ theme={{ token: { padding: 16, - fontSize: 12, + fontSize: 14, }, }} > diff --git a/packages/components/src/components/Loader/Analysis/input.svg b/packages/components/src/components/Loader/Analysis/input.svg new file mode 100644 index 00000000..8c92aaf9 --- /dev/null +++ b/packages/components/src/components/Loader/Analysis/input.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/packages/components/src/components/Loader/Analysis/output.svg b/packages/components/src/components/Loader/Analysis/output.svg new file mode 100644 index 00000000..7ba3d02a --- /dev/null +++ b/packages/components/src/components/Loader/Analysis/output.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/packages/components/src/components/Loader/step.svg b/packages/components/src/components/Loader/step.svg new file mode 100644 index 00000000..12326180 --- /dev/null +++ b/packages/components/src/components/Loader/step.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/components/src/components/TextDrawer/index.tsx b/packages/components/src/components/TextDrawer/index.tsx index 8337d3f8..6f8eadb5 100644 --- a/packages/components/src/components/TextDrawer/index.tsx +++ b/packages/components/src/components/TextDrawer/index.tsx @@ -1,3 +1,4 @@ +import { CodeOutlined } from '@ant-design/icons'; import { Button, Drawer, ButtonProps, DrawerProps } from 'antd'; import React, { CSSProperties, @@ -25,7 +26,7 @@ export const TextDrawer = (
e.stopPropagation()} {...props.containerProps}> {props.button ? (
setVisible(!visible)}>{props.button}
- ) : ( + ) : props.text ? ( + ) : ( + setVisible(!visible)} + /> )} setShow(false)} - > - - {(modules) => ( - - )} - - + + {(modules) => ( + + )} + ); }; @@ -353,7 +354,6 @@ export const AssetDetail: React.FC<{ height, root, }) => { - // const navigate = useNavigate(); const [moduleKeyword, setModuleKeyword] = useState(''); const [defaultExpandAll, setDefaultExpandAll] = useState(false); const [moduleJumpList, setModuleJumpList] = useState([] as number[]); @@ -393,131 +393,134 @@ export const AssetDetail: React.FC<{ ); return ( - - - {parsedSize !== 0 ? ( - - - {'Bundled Size:' + formatSize(parsedSize)} - - - {'Source Size:' + formatSize(sourceSize)} - - - } - color={'white'} - > - - {'Bundled: ' + formatSize(parsedSize)} - - - ) : sourceSize !== 0 ? ( - // fallback to display tag for source size - - {'Source Size:' + formatSize(sourceSize)} - - ) : null} - {isConcatenation ? ( - - - this is a concatenated module, it contains - {mod.modules?.length} modules - - - } - > - - concatenated +
+
+
+ +
+ +
+ +
+
+ + {parsedSize !== 0 ? ( + + + {'Bundled Size:' + formatSize(parsedSize)} + + + {'Source Size:' + formatSize(sourceSize)} + + + } + color={'white'} + > + + {'Bundled: ' + formatSize(parsedSize)} + + + ) : sourceSize !== 0 ? ( + // fallback to display tag for source size + + {'Source Size:' + formatSize(sourceSize)} - - ) : null} - {containedOtherModules && containedOtherModules.length ? ( - - - this is a concatenated module, it is be contained in these - modules below: - - {containedOtherModules.map(({ id, path }) => { - if (isJsDataUrl(path)) { - return ( - - {path} - - ); - } - - const p = relative(dirname(mod.path), path); + ) : null} + {isConcatenation ? ( + + + this is a concatenated module, it contains + {mod.modules?.length} modules + + + } + > + + concatenated + + + ) : null} + {containedOtherModules && containedOtherModules.length ? ( + + + this is a concatenated module, it is be contained in + these modules below: + + {containedOtherModules.map(({ id, path }) => { + if (isJsDataUrl(path)) { + return ( + + {path} + + ); + } + + const p = relative(dirname(mod.path), path); + if (p.startsWith('javascript;charset=utf-8;base64,')) { + return ( + + {p[0] === '.' ? p : `./${p}`} + + ); + } - if (p.startsWith('javascript;charset=utf-8;base64,')) { return ( {p[0] === '.' ? p : `./${p}`} ); - } - - return ( - - {p[0] === '.' ? p : `./${p}`} - - ); - })} - - } - > - concatenated - - ) : null} - -
); }, dirTitle(dir, defaultTitle) { const paths = getChildrenModule(dir); if (paths.length) { - const mods = paths.map( - (e) => includeModules.find((m) => m.path === e)!, - ); - const parsedSize = sumBy(mods, (e) => e.size?.parsedSize || 0); - const sourceSize = sumBy(mods, (e) => e.size?.sourceSize || 0); + // TODO: this counts need to fixed. + // const mods = paths.map( + // (e) => includeModules.find((m) => m.path === e)!, + // ); + // const parsedSize = sumBy(mods, (e) => e.size?.parsedSize || 0); + // const sourceSize = sumBy(mods, (e) => e.size?.sourceSize || 0); return ( - {defaultTitle} - {parsedSize > 0 ? ( + + {/* {parsedSize > 0 ? ( <> {'Bundled:' + formatSize(parsedSize)} @@ -530,13 +533,14 @@ export const AssetDetail: React.FC<{ {'Source:' + formatSize(sourceSize)} - )} + )} */} ); } return defaultTitle; }, + page: 'bundle', }); return res; }, [filteredModules]); @@ -557,6 +561,7 @@ export const AssetDetail: React.FC<{ value={{ moduleJumpList, setModuleJumpList }} > setDefaultExpandAll(true)} size="small" icon={} - > - expand all - + /> {filteredModules.length ? ( - { expandedModulesKeys = expandedKeys; }} - treeData={fileStructures} - autoExpandParent defaultExpandParent defaultExpandedKeys={ expandedModulesKeys?.length @@ -602,10 +608,12 @@ export const AssetDetail: React.FC<{ ? [fileStructures[0].key] : [] } - key={`tree_${moduleKeyword}_${defaultExpandAll}_${asset.path}`} - defaultExpandAll={ - defaultExpandAll || filteredModules.length <= 20 - } + treeData={fileStructures as AntdDataNode[]} + rootStyle={{ + minHeight: '800px', + border: '1px solid rgba(235, 237, 241)', + padding: '14px 20px', + }} /> ) : ( ; } +const tabList = [ + { + key: 'tree', + label: ( + + {'Tree Graph'} + + + + + initial + + + : Indignify whether the chunk is the initial chunk. + + + + + + concatenated + + : Indignify whether the module is the concatenated module. + +
+ Concatenated Module: + + A series module is to lift or series multiple modules into a + closure when packaging. + + +
+ + +
); }, }); @@ -176,27 +251,21 @@ export const WebpackModulesOverallBase: React.FC< }; return ( - +
- setGraphType(e.target.value)} - style={{ marginBottom: Size.BasePadding }} - buttonStyle="solid" - optionType="button" - > - Tree Graph - Bundle Analyzer Graph - setGraphType(e as 'tree' | 'tile')} hidden={graphType === 'tree'} - title={ - - - </Space> - } + tabProps={{ + size: 'middle', + }} > - {/* TODO: add loading icon. */} + <Row> + <Typography.Text code>From: webpack-bundle-analyzer</Typography.Text> + </Row> <ServerAPIProvider api={SDK.ServerAPI.API.GetTileReportHtml} body={{}}> {(data) => { if (data && graphType === 'tile') { @@ -227,98 +296,12 @@ export const WebpackModulesOverallBase: React.FC< <Card hidden={graphType === 'tile'} - title={ - <Space> - <Title text="Bundle Analysis" /> - <Tooltip - color={'white'} - title={ - <Space direction="vertical" color="white"> - <Row> - <Col> - <Tag color="cyan" style={{ margin: 0 }}> - initial - </Tag> - <Typography.Text> - : Indignify whether the chunk is the initial chunk. - </Typography.Text> - </Col> - </Row> - <Row> - <Col> - <Tag color="green">concatenated</Tag> - <Typography.Text> - : Indignify whether the module is the concatenated - module. - </Typography.Text> - <br /> - <Typography.Text strong> - Concatenated Module: - </Typography.Text> - <Typography.Text> - A series module is to lift or series multiple modules - into a closure when packaging. - </Typography.Text> - </Col> - </Row> - <Row> - <Col> - <Button size="small" icon={<CodepenCircleOutlined />} /> - <Typography.Text>: Open the code.</Typography.Text> - </Col> - </Row> - <Row> - <Col> - <Button size="small" icon={<DeploymentUnitOutlined />} /> - <Typography.Text> - : View the module dependency, that is, module reasons in - stats.json. - </Typography.Text> - </Col> - </Row> - <Row> - <Col> - <Tag color={'purple'}>{'Bundled: 15.77 KB'}</Tag> - <Typography.Text strong>Bundled Size</Typography.Text> - <Typography.Text> - The size of the code which bundled. That is, after - bundle and tree-shaking. - </Typography.Text> - </Col> - </Row> - <Row> - <Col> - <Tag color={'orange'}>{'Source: 15.77 KB'}</Tag> - <Typography.Text strong>Source Size</Typography.Text> - <Typography.Text> - The size of the code which before bundle and transform. - </Typography.Text> - </Col> - </Row> - </Space> - } - style={{ marginLeft: 3 }} - > - <InfoCircleOutlined style={{ color: 'rgba(0,0,0,.45)' }} /> - </Tooltip> - </Space> - } - extra={ - fold ? ( - <Button onClick={() => setFold(false)}> - <Typography.Text> - Expand <ColumnHeightOutlined /> - </Typography.Text> - </Button> - ) : ( - <Button onClick={() => setFold(true)}> - <Typography.Text> - Fold - <VerticalAlignMiddleOutlined /> - </Typography.Text> - </Button> - ) - } + tabList={tabList} + activeTabKey={graphType as 'tree' | 'tile'} + onTabChange={(e) => setGraphType(e as 'tree' | 'tile')} + tabProps={{ + size: 'middle', + }} > <Row align="middle" gutter={[Size.BasePadding, Size.BasePadding]}> {entryPoints && entryPoints.length ? ( @@ -413,7 +396,7 @@ export const WebpackModulesOverallBase: React.FC< <Col span={24}> {filteredAssets.length ? ( <Row gutter={Size.BasePadding}> - <Col span={8}> + <Col span={6}> <Card title={ <Space> @@ -443,19 +426,11 @@ export const WebpackModulesOverallBase: React.FC< size="small" bodyStyle={{ overflow: 'scroll', - height: fold ? cardBodyHeight : largeCardBodyHeight, + height: cardBodyHeight, }} - extra={ - <Button - size="small" - icon={<ColumnHeightOutlined />} - onClick={() => setDefaultExpandAll(true)} - > - expand all - </Button> - } > <FileTree + className={styles.assets} treeData={assetsStructures} autoExpandParent defaultExpandAll={ @@ -465,7 +440,7 @@ export const WebpackModulesOverallBase: React.FC< /> </Card> </Col> - <Col span={16}> + <Col span={18}> {assetPath ? ( <ServerAPIProvider api={SDK.ServerAPI.API.GetAssetDetails} @@ -476,7 +451,7 @@ export const WebpackModulesOverallBase: React.FC< asset={details.asset} chunks={details.chunks} modules={details.modules} - height={fold ? cardBodyHeight : largeCardBodyHeight} + height={cardBodyHeight} moduleSizeLimit={inputModule} root={cwd} /> @@ -485,9 +460,7 @@ export const WebpackModulesOverallBase: React.FC< ) : ( <Card bodyStyle={{ - height: fold - ? cardBodyHeight + 40 - : largeCardBodyHeight, + height: cardBodyHeight, }} > <Empty @@ -508,7 +481,7 @@ export const WebpackModulesOverallBase: React.FC< </Col> </Row> </Card> - </React.Fragment> + </div> ); }; diff --git a/packages/components/src/pages/ModuleAnalyze/components/fileTreeCom.scss b/packages/components/src/pages/ModuleAnalyze/components/fileTreeCom.scss index e3910970..377c89d6 100644 --- a/packages/components/src/pages/ModuleAnalyze/components/fileTreeCom.scss +++ b/packages/components/src/pages/ModuleAnalyze/components/fileTreeCom.scss @@ -33,13 +33,12 @@ $treeNodePrefixCls: '#{$treePrefixCls}-treenode'; } } - &-treenode-disabled - > span:not(.#{$treePrefixCls}-switcher), - > a, - > a span { - color: #767676; - cursor: not-allowed; - } + &-treenode-disabled > span:not(.#{$treePrefixCls}-switcher), + > a, + > a span { + color: #767676; + cursor: not-allowed; + } &-treenode-selected { background: rgba(5, 145, 255, 0.3); @@ -66,7 +65,6 @@ $treeNodePrefixCls: '#{$treePrefixCls}-treenode'; transform: rotate(0deg); transition: transform 0.3s ease; - &-expand { transform: rotate(90deg); } @@ -75,21 +73,22 @@ $treeNodePrefixCls: '#{$treePrefixCls}-treenode'; .rc-tree.rc-tree-show-line .rc-tree-treenode:not(:last-child) { border-left: 1px solid #eee; -.#{$treePrefixCls}-titles { - display: flex; - flex-direction: column; - - .#{$treePrefixCls}-node-title { + .#{$treePrefixCls}-titles { display: flex; - cursor: pointer; - img { - cursor: pointer; - &-tag { + flex-direction: column; + + .#{$treePrefixCls}-node-title { + display: flex; cursor: pointer; + line-height: 30px; + img { + cursor: pointer; + &-tag { + cursor: pointer; + } + } } } - } -} .#{$treePrefixCls}-node-title-selected { background-color: yellow; @@ -115,4 +114,4 @@ $treeNodePrefixCls: '#{$treePrefixCls}-treenode'; .rc-tree-indent-unit { display: inline-block; width: 14px; -} \ No newline at end of file +} diff --git a/packages/components/src/pages/ModuleAnalyze/components/fileTreeCom.tsx b/packages/components/src/pages/ModuleAnalyze/components/fileTreeCom.tsx index 59c387d7..672a46b9 100644 --- a/packages/components/src/pages/ModuleAnalyze/components/fileTreeCom.tsx +++ b/packages/components/src/pages/ModuleAnalyze/components/fileTreeCom.tsx @@ -1,15 +1,16 @@ -import { InfoCircleOutlined, MinusCircleOutlined, PlusCircleOutlined, RightSquareTwoTone } from '@ant-design/icons'; -import { SDK } from '@rsdoctor/types'; -import { Popover, Space, Tag, Typography } from 'antd'; +import { + InfoCircleOutlined, + MinusCircleOutlined, + PlusCircleOutlined, + RightSquareTwoTone, +} from '@ant-design/icons'; +import { Popover, Space, Typography } from 'antd'; import React, { useCallback } from 'react'; import Tree, { DefaultNodeProps, useTreeState } from 'react-hyper-tree'; -import { ServerAPIProvider } from 'src/components/Manifest'; -import { TAG_PALLETE } from 'src/constants'; - import { ModuleGraphListContext } from '../../BundleSize/config'; import { NewTreeNodeType } from '../utils/hooks'; -import './fileTreeCom.sass'; +import './fileTreeCom.scss'; const prefix = 'file-tree-com'; @@ -25,7 +26,12 @@ type FileTreeProps = { }; export const FileTree: React.FC<FileTreeProps> = (props) => { - const { treeData, needJumpto = false, defaultOpened = false, defaultOpenFather = 0 } = props; + const { + treeData, + needJumpto = false, + defaultOpened = false, + defaultOpenFather = 0, + } = props; const { required, handlers } = useTreeState({ id: `${prefix}-tree`, @@ -36,7 +42,9 @@ export const FileTree: React.FC<FileTreeProps> = (props) => { }); const renderNode = useCallback(({ node, onToggle }: DefaultNodeProps) => { - defaultOpenFather && node.data.level < defaultOpenFather && node.setOpened(true); + defaultOpenFather && + node.data.level < defaultOpenFather && + node.setOpened(true); return ( <div className={`${prefix}-titles-box`} key={node.data.name}> @@ -45,72 +53,39 @@ export const FileTree: React.FC<FileTreeProps> = (props) => { <div className={`${prefix}-node-title`}> <Space> <div onClick={onToggle}> - {!node.options.opened && node.data.children?.length ? ( - <PlusCircleOutlined style={{ color: 'lightblue' }} /> - ) : ( - <MinusCircleOutlined style={{ color: 'lightblue' }} /> - )} - <Typography.Text code> - {node.data.name} - <Popover - key={`${node.data.name}popover`} - content={ - <> - {node.data.__RESOURCEPATH__ ? ( - <Typography.Text key={`${node.data.name}-popover-path`} code> - {node.data.__RESOURCEPATH__} - </Typography.Text> - ) : ( - <></> - )} - </> - } - title="INFO" - trigger="hover" - > - <InfoCircleOutlined style={{ marginLeft: 4 }} /> - </Popover> - </Typography.Text> + <Space> + {!node.options.opened && node.data.children?.length ? ( + <PlusCircleOutlined style={{ color: 'lightblue' }} /> + ) : ( + <MinusCircleOutlined style={{ color: 'lightblue' }} /> + )} + <Typography.Text> + {node.data.name} + <Popover + key={`${node.data.name}popover`} + content={ + <> + {node.data.__RESOURCEPATH__ ? ( + <Typography.Text + key={`${node.data.name}-popover-path`} + code + > + {node.data.__RESOURCEPATH__} + </Typography.Text> + ) : ( + <></> + )} + </> + } + title="INFO" + trigger="hover" + > + <InfoCircleOutlined style={{ marginLeft: 4 }} /> + </Popover> + </Typography.Text> + </Space> </div> <Space> - {node.data.concatModules?.length ? ( - <Popover - content={ - <ServerAPIProvider - api={SDK.ServerAPI.API.GetModulesByModuleIds} - body={{ moduleIds: node.data.concatModules || [] }} - > - {(res) => { - return ( - <div> - {res.map(({ path }, index) => ( - <p key={`${path}-${index}`}>{path}</p> - ))} - </div> - ); - }} - </ServerAPIProvider> - } - title="Concatenated Module Name" - trigger="hover" - > - <Tag - key={`${node.data.name}-size-tag`} - className={`${prefix}-node-title-tag`} - color={TAG_PALLETE.DARK_BLUE} - > - {'Concatenated'} - </Tag> - </Popover> - ) : node.data.size && node.data.size !== '0 bytes' ? ( - <Tag - key={`${node.data.name}-size-tag`} - className={`${prefix}-node-title-tag`} - color={TAG_PALLETE.COLOR_B} - >{`Bundled: ${node.data.size}`}</Tag> - ) : ( - <></> - )} {needJumpto && ( <ModuleGraphListContext.Consumer> {({ moduleJumpList, setModuleJumpList }) => { diff --git a/packages/components/src/pages/ModuleAnalyze/fileTree.tsx b/packages/components/src/pages/ModuleAnalyze/fileTree.tsx index 8acdfe9b..ce9d5667 100644 --- a/packages/components/src/pages/ModuleAnalyze/fileTree.tsx +++ b/packages/components/src/pages/ModuleAnalyze/fileTree.tsx @@ -1,38 +1,13 @@ -import { - ExpandOutlined, - InfoCircleOutlined, - MenuFoldOutlined, - MenuUnfoldOutlined, - RightSquareTwoTone, -} from '@ant-design/icons'; import { SDK } from '@rsdoctor/types'; -import { - Badge, - Button, - Col, - Empty, - Popover, - Radio, - Row, - Tag, - Typography, -} from 'antd'; +import { Col, Empty } from 'antd'; import React, { useEffect, useState } from 'react'; -import { ServerAPIProvider } from 'src/components/Manifest'; -import { Title } from 'src/components/Title'; -import { Size, TAG_PALLETE } from 'src/constants'; -import { useI18n } from 'src/utils/hooks'; -import { ChunksTable } from './chunks'; +import { Size } from 'src/constants'; import { FileTree } from './components/fileTreeCom'; import { clsNamePrefix } from './constants'; import DependencyTree from './dependency'; -import { getImporteds, getModuleReasonsTree } from './utils'; +import { getImporteds } from './utils'; import { useCreateFileTreeData } from './utils/hooks'; - -enum ChartDimension { - Dependencies, - Chunks, -} +import { TabList } from './index'; export const ModuleFilesTree: React.FC<{ modules: SDK.ModuleData[]; @@ -40,185 +15,66 @@ export const ModuleFilesTree: React.FC<{ curModule: SDK.ModuleData; cwd: string; selectedChunk: string; + activeTabKey: string; }> = (props) => { - const { curModule, modules, dependencies, cwd, selectedChunk = '' } = props; - const { t } = useI18n(); + const { + curModule, + modules, + dependencies, + cwd, + activeTabKey, + selectedChunk = '', + } = props; const [importedModules, setImportedModules] = useState( [] as SDK.ModuleData[], ); - const [dimension, setDimension] = useState<ChartDimension>( - ChartDimension.Dependencies, - ); - const [fold, setFold] = useState(true); + const { data: fileStructures } = useCreateFileTreeData( modules, importedModules, curModule, ); - const [reasonsTree, setReasonsTree] = useState( - {} as Record<string, string[]>, - ); useEffect(() => { const importeds = getImporteds(curModule, modules); setImportedModules(importeds); }, [curModule, modules]); - useEffect(() => { - const _reasonsTree: Record<string, string[]> = {}; - importedModules.forEach((_curModule) => { - const treeList: string[] = []; - const visited = new Map(); - getModuleReasonsTree(_curModule, modules, treeList, visited); - _reasonsTree[_curModule.id] = treeList; - }); - setReasonsTree(_reasonsTree); - }, [importedModules]); - return ( <> - <Row> - <Popover - content={ - <div> - <div> - <Badge status="success" text=" " /> - <Typography.Text code> - <ExpandOutlined /> - {" Expand the node_modules's modules that was omitted... "} - </Typography.Text> - <Typography.Text>{`: ${t('Expand Omitted')}`}</Typography.Text> - </div> - <div> - <Badge status="success" text=" " /> - <Popover - content="*" - title="Concatenated Module Name" - trigger="hover" - > - <Tag color={TAG_PALLETE.DARK_BLUE}>{'Concatenated'}</Tag> - </Popover> - <Typography.Text>{`: ${t('Concatenated Tag')}`}</Typography.Text> - </div> - <div> - <Badge status="success" text=" " /> - <RightSquareTwoTone /> - <Typography.Text> - { - ': Jump button, click to jump to the Module dependency analysis page of this module.' - } - </Typography.Text> - </div> - </div> - } - title="Usage" - > - <Button type="primary" icon={<InfoCircleOutlined />}> - Usage - </Button> - </Popover> - </Row> - <Row gutter={4} style={{ marginTop: Size.BasePadding }}> - <Col span={fold ? 18 : 12}> - <Row className={`${clsNamePrefix}-file-tree`} justify={'center'}> - <Col span={24} style={{ padding: Size.BasePadding / 2 }}> - <Title text={'Current Module Imported Reasons Tree:'} /> - {importedModules ? ( - <FileTree - cwd={cwd} - treeData={ - selectedChunk - ? fileStructures.filter( - (_parent) => - reasonsTree[_parent.id].indexOf(selectedChunk) >= 0, - ) - : fileStructures - } - needCode={true} - needShowAllTree={true} - needJumpto={true} - selectedChunk={selectedChunk} - /> - ) : ( - <Empty className={`${clsNamePrefix}-empty`} /> - )} - </Col> - </Row> - </Col> - <Col span={fold ? 6 : 12}> - <div - className={`${clsNamePrefix}-file-tree`} - style={{ padding: Size.BasePadding / 2 }} - > - {fold ? ( - <Popover content={'Unfold [Dependencies & Chunks] Box.'}> - <MenuFoldOutlined - onClick={() => setFold(!fold)} - style={{ marginRight: 8 }} - /> - </Popover> - ) : ( - <Popover content={'Fold [Dependencies & Chunks] Box.'}> - <MenuUnfoldOutlined - onClick={() => setFold(!fold)} - style={{ marginRight: 8 }} - /> - </Popover> - )} - - <Radio.Group - options={[ - { - label: 'Dependencies', - value: ChartDimension.Dependencies, - }, - { - label: 'Chunks', - value: ChartDimension.Chunks, - }, - ]} - onChange={(e) => setDimension(e.target.value)} - value={dimension} - optionType="button" - buttonStyle="solid" - size="middle" + {activeTabKey === TabList[TabList.Reasons] ? ( + <> + {importedModules ? ( + <FileTree + cwd={cwd} + treeData={fileStructures} + needCode={true} + needShowAllTree={true} + needJumpto={true} + selectedChunk={selectedChunk} /> - {!fold ? ( - <> - {dimension === ChartDimension.Dependencies && ( - <Col span={24} style={{ marginTop: Size.BasePadding / 2 }}> - {curModule ? ( - <DependencyTree - module={curModule} - dependencies={dependencies} - cwd={cwd} - /> - ) : ( - <Empty className={`${clsNamePrefix}-empty`} /> - )} - </Col> - )} - {dimension === ChartDimension.Chunks && ( - <Col span={18} style={{ marginTop: Size.BasePadding / 2 }}> - {curModule ? ( - <ServerAPIProvider - api={SDK.ServerAPI.API.GetChunksByModuleId} - body={{ moduleId: curModule.id }} - > - {(res) => <ChunksTable chunks={res} />} - </ServerAPIProvider> - ) : ( - <Empty className={`${clsNamePrefix}-empty`} /> - )} - </Col> - )} - </> + ) : ( + <Empty className={`${clsNamePrefix}-empty`} /> + )} + </> + ) : ( + <div + className={`${clsNamePrefix}-file-tree`} + style={{ padding: Size.BasePadding / 2 }} + > + <Col span={24} style={{ marginTop: Size.BasePadding / 2 }}> + {curModule ? ( + <DependencyTree + module={curModule} + dependencies={dependencies} + cwd={cwd} + /> ) : ( - <></> + <Empty className={`${clsNamePrefix}-empty`} /> )} - </div> - </Col> - </Row> + </Col> + </div> + )} </> ); }; diff --git a/packages/components/src/pages/ModuleAnalyze/index.scss b/packages/components/src/pages/ModuleAnalyze/index.scss index 35918a76..1737fc27 100644 --- a/packages/components/src/pages/ModuleAnalyze/index.scss +++ b/packages/components/src/pages/ModuleAnalyze/index.scss @@ -2,12 +2,14 @@ $prefixCls: 'module-analyze'; .#{$prefixCls}-file-tree { width: '100%'; - border: 1px solid #eee; min-height: 50em; - margin: 4; - padding: 4; .#{$prefixCls}-empty { margin-top: 20%; } } + +.module-analyze-box { + display: flex; + flex-direction: column; +} diff --git a/packages/components/src/pages/ModuleAnalyze/index.tsx b/packages/components/src/pages/ModuleAnalyze/index.tsx index 9371a160..7199bc4b 100644 --- a/packages/components/src/pages/ModuleAnalyze/index.tsx +++ b/packages/components/src/pages/ModuleAnalyze/index.tsx @@ -1,78 +1,179 @@ -import { LeftSquareOutlined } from '@ant-design/icons'; import { SDK } from '@rsdoctor/types'; -import { Card, Col, Row, Select, Space, Typography } from 'antd'; +import { + Badge, + Card, + Col, + Drawer, + Popover, + Row, + Space, + Tag, + Typography, +} from 'antd'; import React, { useState } from 'react'; import { ServerAPIProvider } from 'src/components/Manifest'; import { getShortPath } from 'src/utils'; -import { values } from 'lodash-es'; import { ModuleGraphListContext } from '../BundleSize/config'; import { ModuleFilesTree } from './fileTree'; -import './index.sass'; +import './index.scss'; +import { drawerWidth, TAG_PALLETE } from '../../constants'; +import { + ExpandOutlined, + LeftSquareOutlined, + QuestionCircleOutlined, + RightSquareTwoTone, +} from '@ant-design/icons'; +import { t } from 'i18next'; + +export enum TabList { + Reasons, + Dependencies, +} + +const tabslist = [ + { + key: TabList[TabList.Reasons], + label: TabList[TabList.Reasons], + }, + { + key: TabList[TabList.Dependencies], + label: TabList[TabList.Dependencies], + }, +] as unknown as { key: string; label: string }[]; export const ModuleAnalyzeComponent: React.FC<{ modules: SDK.ModuleData[]; cwd: string; moduleId: string | number; -}> = ({ modules, cwd, moduleId }) => { - const [selectedChunk, setSelectedChunk] = useState('' as string); + show: boolean; + setShow: (arg: boolean) => void; +}> = ({ modules, cwd, moduleId, show, setShow }) => { + const [selectedChunk, _setSelectedChunk] = useState('' as string); + const [activeTabKey, setActiveTabKey] = useState(TabList[TabList.Reasons]); + return ( - <ServerAPIProvider api={SDK.ServerAPI.API.GetModuleDetails} body={{ moduleId: +moduleId }}> + <ServerAPIProvider + api={SDK.ServerAPI.API.GetModuleDetails} + body={{ moduleId: +moduleId }} + > {({ module, dependencies }) => { return ( - <ServerAPIProvider api={SDK.ServerAPI.API.GetAllChunkGraph} body={{}}> - {(chunks) => { - return ( - <ModuleGraphListContext.Consumer> - {({ moduleJumpList, setModuleJumpList }) => { - return ( - <Card - title={ - <Space> - <LeftSquareOutlined - onClick={() => { - const _list = [...moduleJumpList.slice(0, -1)]; - setModuleJumpList(_list); - }} - /> - - <Typography.Title code level={5} style={{ marginBottom: 'revert' }}> - {`Current Module: ${getShortPath(module.path)}`} - </Typography.Title> - </Space> - } - style={{ height: '100%' }} - > - <Row justify="start" style={{ marginBottom: 20 }}> - <Col> - <Select - allowClear - placeholder="Select Chunk To Filter Modules Links" - showSearch - style={{ width: 300 }} - options={values(chunks).map((e) => ({ label: e.name, value: e.id }))} - onChange={(e) => setSelectedChunk(e)} - /> - </Col> - </Row> - - <Row justify="start" align="middle"> - <Col span={24}> - <ModuleFilesTree - curModule={module} - modules={modules} - dependencies={dependencies} - cwd={cwd} - selectedChunk={selectedChunk} - /> - </Col> - </Row> - </Card> - ); - }} - </ModuleGraphListContext.Consumer> - ); - }} - </ServerAPIProvider> + <Drawer + title={ + <div className="module-analyze-box"> + <Typography.Text>{module.path}</Typography.Text> + <Typography.Text + style={{ fontSize: 12, color: 'rgba(0, 0, 0, 0.45)' }} + > + {`Current Module: ${getShortPath(module.path)}`} + </Typography.Text> + </div> + } + open={show} + maskClosable + width={drawerWidth} + onClose={() => setShow(false)} + > + <ServerAPIProvider + api={SDK.ServerAPI.API.GetAllChunkGraph} + body={{}} + > + {(_chunks) => { + return ( + <ModuleGraphListContext.Consumer> + {({ moduleJumpList, setModuleJumpList }) => { + return ( + <Card + style={{ minHeight: 400 }} + tabList={tabslist} + activeTabKey={activeTabKey} + tabProps={{ + size: 'small', + style: { + fontSize: 12, + }, + }} + onTabChange={(k) => setActiveTabKey(k)} + styles={{ + title: { paddingTop: 0 }, + }} + title={ + <Space style={{ padding: '10px 0px' }}> + <LeftSquareOutlined + onClick={() => { + const _list = [ + ...moduleJumpList.slice(0, -1), + ]; + setModuleJumpList(_list); + }} + /> + <Typography.Text> + Current Module Imported Reasons Tree + </Typography.Text> + <Popover + content={ + <div> + <div> + <Badge status="success" text=" " /> + <Typography.Text code> + <ExpandOutlined /> + { + " Expand the node_modules's modules that was omitted... " + } + </Typography.Text> + <Typography.Text>{`: ${t('Expand Omitted')}`}</Typography.Text> + </div> + <div> + <Badge status="success" text=" " /> + <Popover + content="*" + title="Concatenated Module Name" + trigger="hover" + > + <Tag color={TAG_PALLETE.DARK_BLUE}> + {'Concatenated'} + </Tag> + </Popover> + <Typography.Text>{`: ${t('Concatenated Tag')}`}</Typography.Text> + </div> + <div> + <Badge status="success" text=" " /> + <RightSquareTwoTone /> + <Typography.Text> + { + ': Jump button, click to jump to the Module dependency analysis page of this module.' + } + </Typography.Text> + </div> + </div> + } + title="Usage" + > + <QuestionCircleOutlined /> + </Popover> + </Space> + } + > + <Row justify="start" align="middle"> + <Col span={24}> + <ModuleFilesTree + curModule={module} + modules={modules} + dependencies={dependencies} + cwd={cwd} + selectedChunk={selectedChunk} + activeTabKey={activeTabKey} + /> + </Col> + </Row> + </Card> + ); + }} + </ModuleGraphListContext.Consumer> + ); + }} + </ServerAPIProvider> + </Drawer> ); }} </ServerAPIProvider> diff --git a/packages/components/src/pages/WebpackPlugins/index.tsx b/packages/components/src/pages/WebpackPlugins/index.tsx index 3d66eca9..54267d9c 100644 --- a/packages/components/src/pages/WebpackPlugins/index.tsx +++ b/packages/components/src/pages/WebpackPlugins/index.tsx @@ -18,7 +18,10 @@ export const Page: React.FC = () => { bodyStyle={{ paddingTop: Size.BasePadding / 3 }} extra={<WebpackConfigurationViewer defaultKeys={['plugins']} />} > - <Space direction="vertical"> + <Space + direction="vertical" + style={{ width: '100%', padding: '0 30px' }} + > <ServerAPIProvider api={SDK.ServerAPI.API.GetPluginSummary}> {({ hooks, tapNames }) => ( <Space style={{ marginBottom: Size.BasePadding / 2 }}> @@ -83,4 +86,4 @@ export const Page: React.FC = () => { ); }; -export * from './constants' +export * from './constants'; diff --git a/packages/components/src/utils/file.tsx b/packages/components/src/utils/file.tsx index 45e0bb41..0d3521e0 100644 --- a/packages/components/src/utils/file.tsx +++ b/packages/components/src/utils/file.tsx @@ -1,7 +1,14 @@ import { get, startsWith } from 'lodash-es'; import { Common } from '@rsdoctor/types'; -import { message, UploadFile } from 'antd'; +import { message, Space, TreeNodeProps, UploadFile } from 'antd'; import { FieldDataNode } from 'rc-tree'; +import { + FolderOpenTwoTone, + FolderTwoTone, + FileOutlined, + RightOutlined, +} from '@ant-design/icons'; +import { getFileCom } from 'src/components/FileTree'; export type DataNode = FieldDataNode<{ key: string | number; @@ -33,7 +40,10 @@ export function mapFileKey( res.push(e.key); } }); - parent = parent.reduce<DataNode[]>((t, e) => t.concat(e.children || []), []); + parent = parent.reduce<DataNode[]>( + (t, e) => t.concat(e.children || []), + [], + ); if (!parent.length) break; d++; } @@ -47,7 +57,8 @@ export function flattenDirectory( parent: DataNode, sep = '/', inlinedResourcePathKey: keyof DataNode, - dirTitle = (_dir: DataNode, defaultTitle: string): JSX.Element | string => defaultTitle, + dirTitle = (_dir: DataNode, defaultTitle: string): JSX.Element | string => + defaultTitle, ) { if (n.isLeaf) return; if (parent.children && parent.children.length === 1) { @@ -79,6 +90,7 @@ export function createFileStructures({ inlinedResourcePathKey = '__RESOURCEPATH__', fileTitle = (_file: string, basename: string) => basename, dirTitle = (_dir: DataNode, defaultTitle: string) => defaultTitle, + page = 'other', }: { files: string[]; cwd?: string; @@ -86,6 +98,7 @@ export function createFileStructures({ inlinedResourcePathKey?: keyof DataNode; dirTitle?(dir: DataNode, defaultTitle: string): JSX.Element | string; fileTitle?(file: string, basename: string): JSX.Element | string; + page?: 'bundle' | 'other'; }): DataNode[] { const sepRegexp = new RegExp(sep); @@ -99,9 +112,15 @@ export function createFileStructures({ // find the match directory. let exist = parent.children!.find((e) => e.title === dir) as DataNode; if (!exist) { - const p = [parent[inlinedResourcePathKey], dir].filter(Boolean).join(sep); + const p = [parent[inlinedResourcePathKey], dir] + .filter(Boolean) + .join(sep); exist = { title: dir, + icon: + page === 'bundle' + ? (props) => getFileIcon(props as TreeNodeProps, false) + : null, // key: [parent.key, parent.children!.length].join('-'), key: p, children: [], @@ -113,17 +132,23 @@ export function createFileStructures({ parent = exist; dir = rootDirname(basename); - basename = dir ? basename.slice(dir.length).replace(sepRegexp, '') : basename; + basename = dir + ? basename.slice(dir.length).replace(sepRegexp, '') + : basename; } // uniq - if (parent.children!.some((e) => get(e, inlinedResourcePathKey) === file)) return t; + if (parent.children!.some((e) => get(e, inlinedResourcePathKey) === file)) + return t; parent.children!.push({ title() { return fileTitle(file, basename); }, - // key: [parent.key, parent.children!.length].join('-'), + icon: + page === 'bundle' + ? (props) => getFileIcon(props as TreeNodeProps) + : null, key: file, isLeaf: true, [inlinedResourcePathKey]: file, @@ -137,7 +162,9 @@ export function createFileStructures({ res.forEach((e) => { e.children && - e.children.forEach((item) => flattenDirectory(item, e, sep, inlinedResourcePathKey, dirTitle)); + e.children.forEach((item) => + flattenDirectory(item, e, sep, inlinedResourcePathKey, dirTitle), + ); }); return res; @@ -151,9 +178,15 @@ export function beautifyPath(path: string, cwd: string) { return path; } -export function readJSONByFileReader<T extends Common.PlainObject>(file: UploadFile): Promise<T>; -export function readJSONByFileReader<T extends Common.PlainObject>(file: Blob): Promise<T>; -export function readJSONByFileReader<T extends Common.PlainObject>(file: unknown): Promise<T> { +export function readJSONByFileReader<T extends Common.PlainObject>( + file: UploadFile, +): Promise<T>; +export function readJSONByFileReader<T extends Common.PlainObject>( + file: Blob, +): Promise<T>; +export function readJSONByFileReader<T extends Common.PlainObject>( + file: unknown, +): Promise<T> { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onloadend = () => { @@ -198,3 +231,26 @@ export function beautifyModulePath(modulePath: string, cwd: string) { inNodeModules: false, }; } + +export function getFileIcon(props: TreeNodeProps, addRowIcon = true) { + const { data } = props; + const expanded = props.expanded; + if (data?.children) { + return ( + <Space> + {addRowIcon ? ( + <RightOutlined + className={`file-tree-switcher-arrow ${expanded ? 'file-tree-switcher-arrow-expand' : ''}`} + /> + ) : ( + <></> + )} + {expanded ? <FolderOpenTwoTone /> : <FolderTwoTone />} + </Space> + ); + } + if (props.eventKey && typeof props.eventKey === 'string') { + return getFileCom(props.eventKey); + } + return <FileOutlined />; +} diff --git a/packages/document/package.json b/packages/document/package.json index 9d8592b2..d9e2b228 100644 --- a/packages/document/package.json +++ b/packages/document/package.json @@ -25,7 +25,7 @@ }, "devDependencies": { "@rsdoctor/types": "workspace:*", - "@rspress/plugin-rss": "^1.39.3", + "@rspress/plugin-rss": "^1.39.4", "@types/node": "^16", "@types/react": "^18.3.18", "@types/react-dom": "^18.3.5", @@ -40,6 +40,6 @@ "dependencies": { "@rstack-dev/doc-ui": "1.5.4", "react-markdown": "^9.0.1", - "rspress": "^1.39.3" + "rspress": "^1.39.4" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 38851dd4..176c16d2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -236,11 +236,11 @@ importers: version: /semver@7.5.4 devDependencies: '@rsbuild/core': - specifier: ^1.1.1 - version: 1.1.1 + specifier: ^1.1.3 + version: 1.1.13 '@rsbuild/plugin-react': specifier: ^1.0.7 - version: 1.0.7(@rsbuild/core@1.1.1) + version: 1.0.7(@rsbuild/core@1.1.13) '@rsdoctor/core': specifier: workspace:* version: link:../../packages/core @@ -779,15 +779,15 @@ importers: specifier: ^9.0.1 version: 9.0.1(@types/react@18.3.18)(react@18.3.1) rspress: - specifier: ^1.39.3 - version: 1.39.3(webpack@5.95.0) + specifier: ^1.39.4 + version: 1.39.4(webpack@5.95.0) devDependencies: '@rsdoctor/types': specifier: workspace:* version: link:../types '@rspress/plugin-rss': - specifier: ^1.39.3 - version: 1.39.3(react@18.3.1)(rspress@1.39.3) + specifier: ^1.39.4 + version: 1.39.4(react@18.3.1)(rspress@1.39.4) '@types/node': specifier: ^16 version: 16.18.104 @@ -1086,6 +1086,8 @@ importers: specifier: ^5.2.2 version: 5.5.4 + packages/utils/dist/esm: {} + packages/webpack-plugin: dependencies: '@rsdoctor/core': @@ -7134,19 +7136,6 @@ packages: fsevents: 2.3.3 dev: true - /@rsbuild/core@1.1.1: - resolution: {integrity: sha512-CJoO3PIC0Cm/z1iL6nWoIuQzETEMY+D+UIrlMGmWuhdGiixDE2x0spban7jmmJRE7w3Ns8b2ccCmhp6rovEojw==} - engines: {node: '>=16.7.0'} - hasBin: true - dependencies: - '@rspack/core': 1.1.8(@swc/helpers@0.5.15) - '@rspack/lite-tapable': 1.0.1 - '@swc/helpers': 0.5.15 - core-js: 3.39.0 - optionalDependencies: - fsevents: 2.3.3 - dev: true - /@rsbuild/core@1.1.13: resolution: {integrity: sha512-XBL2hrin8731W6iTGGL+x3cv07n4vm2D7u6XHRwtQkRfySzAqGx7ThlQLdNX/dJwfsoQrYQuWl/qzaljjXtGtg==} engines: {node: '>=16.7.0'} @@ -7374,12 +7363,12 @@ packages: react-refresh: 0.14.2 dev: true - /@rsbuild/plugin-react@1.0.7(@rsbuild/core@1.1.1): + /@rsbuild/plugin-react@1.0.7(@rsbuild/core@1.1.13): resolution: {integrity: sha512-t7T/GqDwodusTAnxGpqVRnQ/G+HYh98zk71qIg19WkjVJJGv57AC1Ppx0/6zzbZAbxU60bfK8TeEEXjhXCdSxA==} peerDependencies: '@rsbuild/core': 1.x dependencies: - '@rsbuild/core': 1.1.1 + '@rsbuild/core': 1.1.13 '@rspack/plugin-react-refresh': 1.0.0(react-refresh@0.14.2) react-refresh: 0.14.2 dev: true @@ -8077,8 +8066,8 @@ packages: html-entities: 2.5.2 react-refresh: 0.16.0 - /@rspress/core@1.39.3(webpack@5.95.0): - resolution: {integrity: sha512-xY2DXYEKk6M4rZt2Yx+exUwX1MaJt6WRBirUc+5gv7uSdnxdMgFD9bL7ppR8oevmaIhzvcGLeVi7VBcdqG1Nlg==} + /@rspress/core@1.39.4(webpack@5.95.0): + resolution: {integrity: sha512-IdFWtFFk6LNVh5npwgJt3D0TkVgEV4koUQvBDmeFx4JX1KMPPJhCbyK+TsCE9DPh00XiWXa6ddjw+MJm3xdS4g==} engines: {node: '>=14.17.6'} dependencies: '@mdx-js/loader': 2.3.0(webpack@5.95.0) @@ -8089,13 +8078,13 @@ packages: '@rsbuild/plugin-react': 1.1.0(@rsbuild/core@1.1.13) '@rsbuild/plugin-sass': 1.1.2(@rsbuild/core@1.1.13) '@rspress/mdx-rs': 0.6.4 - '@rspress/plugin-auto-nav-sidebar': 1.39.3 - '@rspress/plugin-container-syntax': 1.39.3 - '@rspress/plugin-last-updated': 1.39.3 - '@rspress/plugin-medium-zoom': 1.39.3(@rspress/runtime@1.39.3) - '@rspress/runtime': 1.39.3 - '@rspress/shared': 1.39.3 - '@rspress/theme-default': 1.39.3 + '@rspress/plugin-auto-nav-sidebar': 1.39.4 + '@rspress/plugin-container-syntax': 1.39.4 + '@rspress/plugin-last-updated': 1.39.4 + '@rspress/plugin-medium-zoom': 1.39.4(@rspress/runtime@1.39.4) + '@rspress/runtime': 1.39.4 + '@rspress/shared': 1.39.4 + '@rspress/theme-default': 1.39.4 enhanced-resolve: 5.18.0 github-slugger: 2.0.0 hast-util-from-html: 2.0.3 @@ -8197,58 +8186,58 @@ packages: '@rspress/mdx-rs-win32-arm64-msvc': 0.6.4 '@rspress/mdx-rs-win32-x64-msvc': 0.6.4 - /@rspress/plugin-auto-nav-sidebar@1.39.3: - resolution: {integrity: sha512-Z64FILjUaBKNE7c6mRcSL64S11DLpS84CFVQrAEANx1GkliacWoCZO84mWGDirj5iTsuiS6augMJxIaC2RS5tA==} + /@rspress/plugin-auto-nav-sidebar@1.39.4: + resolution: {integrity: sha512-QPF+omV5caI/dy5C6U7+MUH1ryXDIvcVBGjz66LjGlq3xp8lqfx6L6lRZK8tOAXsh0gNeIkLjO7W6Tiq6ILFIA==} engines: {node: '>=14.17.6'} dependencies: - '@rspress/shared': 1.39.3 + '@rspress/shared': 1.39.4 - /@rspress/plugin-container-syntax@1.39.3: - resolution: {integrity: sha512-wO/Rk6nGesKmZ/b+HIotkMT3HAeR0Z3QdtpT5qj29CseBeY9L1NhtHiEc0nn2nR3kQKndcEIqRFumvnE01ry7Q==} + /@rspress/plugin-container-syntax@1.39.4: + resolution: {integrity: sha512-MruIyFhJ7RFm5fSRxtScjfiKxu3DcqqN4EtfbFk/JCPNbQdZS6ejSkrq2j6/tToMpW0SOHa9HjrwHWWp1w/28w==} engines: {node: '>=14.17.6'} dependencies: - '@rspress/shared': 1.39.3 + '@rspress/shared': 1.39.4 - /@rspress/plugin-last-updated@1.39.3: - resolution: {integrity: sha512-0kw9sAdOR/9ZppC0ebSSprit6SE5j0ABYtIxQBTkTc56D2WYHJMRIJgXKySImW42koiVbNkZm+OCozqm5BTFbA==} + /@rspress/plugin-last-updated@1.39.4: + resolution: {integrity: sha512-NYFnw70x19m/Tq0QTYh9Efs2KmCNFb+MZWh1Oe28XZHR1odr0f/H/+33GHTBrQZ0VddLf3v6BpVAxj7eHz3SUA==} engines: {node: '>=14.17.6'} dependencies: - '@rspress/shared': 1.39.3 + '@rspress/shared': 1.39.4 - /@rspress/plugin-medium-zoom@1.39.3(@rspress/runtime@1.39.3): - resolution: {integrity: sha512-AIIxQjC0u8wRTWBW3U5FWFG3kWJ1zkJEXbTXMvKBT7HykUhwC+vnUh6l8UCe+HQYwuFaIEasmEwI4UAho0ZhYg==} + /@rspress/plugin-medium-zoom@1.39.4(@rspress/runtime@1.39.4): + resolution: {integrity: sha512-nECUOHb3Z8aFXXRV0i5rIrj2Gsu8n2W3jUGrB9cAmHDyng68v/KFgU84ASFxnZgJsu4NJPyL7bzUy08kIPxWEw==} engines: {node: '>=14.17.6'} peerDependencies: - '@rspress/runtime': ^1.39.3 + '@rspress/runtime': ^1.39.4 dependencies: - '@rspress/runtime': 1.39.3 + '@rspress/runtime': 1.39.4 medium-zoom: 1.1.0 - /@rspress/plugin-rss@1.39.3(react@18.3.1)(rspress@1.39.3): - resolution: {integrity: sha512-GHdxCYrqrA3dJsx9M45YULf/CKZVXdGL/U3flTLbBBjJzOow8gYseNK0MEcVlVcaZ3lhbhZGh/mkeRriqGtcXQ==} + /@rspress/plugin-rss@1.39.4(react@18.3.1)(rspress@1.39.4): + resolution: {integrity: sha512-5GwpBOrZGZUZF4SVWZvjrRIIfiwrPrHZ6wfG7sCm8ltHW+oMEIhcaBiDawAziBbFMXanm7pmpC8ztGi84YdEhQ==} engines: {node: '>=14.17.6'} peerDependencies: react: '>=17.0.0' - rspress: ^1.39.3 + rspress: ^1.39.4 dependencies: - '@rspress/shared': 1.39.3 + '@rspress/shared': 1.39.4 feed: 4.2.2 react: 18.3.1 - rspress: 1.39.3(webpack@5.95.0) + rspress: 1.39.4(webpack@5.95.0) dev: true - /@rspress/runtime@1.39.3: - resolution: {integrity: sha512-iOoAKDST9bFopl+Bwpfg5+5NqKFf9SaPiuKW4EyoNjQBJpvQZh4nrauusz84sXarIg9frhOnpN/M7YTPbEa+EQ==} + /@rspress/runtime@1.39.4: + resolution: {integrity: sha512-TTcQ6uufHjdrIlS7vW523wE7m7JCGKCBRZVAOSEeQCDbDShyHeefNFMVh9/r/Bdubfz6/Q3OxmSFENwM2nJu+Q==} engines: {node: '>=14.17.6'} dependencies: - '@rspress/shared': 1.39.3 + '@rspress/shared': 1.39.4 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) react-helmet-async: 1.3.0(react-dom@18.3.1)(react@18.3.1) react-router-dom: 6.28.1(react-dom@18.3.1)(react@18.3.1) - /@rspress/shared@1.39.3: - resolution: {integrity: sha512-lzOHBJNN4POkSaIWoehXi9iWZvjclLhny+RGP53oTRuOlS6MWORKc3Q2V/ga+2uh2c99DgvPa62dRtqdfazkQQ==} + /@rspress/shared@1.39.4: + resolution: {integrity: sha512-6EYpUIyHrEfsMv2eeYnrnfSb2E4AGie0n5zEMf3ZdTyDfmocA5r1JhQYGL6hfVj7Tdep7oEMFjQHU0JioY3ruA==} dependencies: '@rsbuild/core': 1.1.13 chalk: 5.4.1 @@ -8258,13 +8247,13 @@ packages: lodash-es: 4.17.21 unified: 10.1.2 - /@rspress/theme-default@1.39.3: - resolution: {integrity: sha512-3eJc/loocaUpAbrgDJY7a9iX+Og8hLkuIkgCwf4orl57oFdldm8xbAZHtNro71tIgi/c/13kdGDZCCygwut/9A==} + /@rspress/theme-default@1.39.4: + resolution: {integrity: sha512-6bvIjkF2SKFdOsYnqTo/8sW/+v2cIY8Z3X59SrnxTaEYmdu/upa1mBVkezhqIrJxBE+k79iCUBBJ0s9LqUvXEg==} engines: {node: '>=14.17.6'} dependencies: '@mdx-js/react': 2.3.0(react@18.3.1) - '@rspress/runtime': 1.39.3 - '@rspress/shared': 1.39.3 + '@rspress/runtime': 1.39.4 + '@rspress/shared': 1.39.4 body-scroll-lock: 4.0.0-beta.0 copy-to-clipboard: 3.3.3 flexsearch: 0.7.43 @@ -18158,13 +18147,13 @@ packages: resolution: {integrity: sha512-usb6zWoi5wFFmBeA9HKR6BhsnnsItudMBarc54GYpuRL55SWkLxyWyMijv14mUI04FI7J7lEmea08uZE0bVKxg==} dev: true - /rspress@1.39.3(webpack@5.95.0): - resolution: {integrity: sha512-XNsgPIdkVenP4knrys8WSN87nuTe32in2zg4+i9UbPUduOA9n082pwMpnxL5FIraUe3ZjSI2nzwEBRlkmPY72Q==} + /rspress@1.39.4(webpack@5.95.0): + resolution: {integrity: sha512-oxk5x+4MqwXXPi5tvGqDCsnGOoSyBdMt+0nTYeV2bVJqJwpf2D6TmKf+VpGryspa6sQG1FZRgf8aoQBRcCilKg==} hasBin: true dependencies: '@rsbuild/core': 1.1.13 - '@rspress/core': 1.39.3(webpack@5.95.0) - '@rspress/shared': 1.39.3 + '@rspress/core': 1.39.4(webpack@5.95.0) + '@rspress/shared': 1.39.4 cac: 6.7.14 chalk: 5.4.1 chokidar: 3.6.0