Browse Source

feat: storybook mock @umijx/max

pull/170/head
cp3hnu 11 months ago
parent
commit
9c45343c37
27 changed files with 268 additions and 124 deletions
  1. +0
    -7
      react-ui/.gitignore
  2. +16
    -0
      react-ui/.storybook/babel-plugin-auto-css-modules.js
  3. +71
    -38
      react-ui/.storybook/main.ts
  4. +12
    -0
      react-ui/.storybook/mock/umijs.tsx
  5. +55
    -62
      react-ui/.storybook/preview.tsx
  6. +26
    -0
      react-ui/.storybook/tsconfig.json
  7. +20
    -0
      react-ui/.storybook/typings.d.ts
  8. +2
    -0
      react-ui/package.json
  9. +1
    -1
      react-ui/src/components/BasicInfo/BasicInfoItemValue.tsx
  10. +0
    -0
      react-ui/src/components/CodeConfigItem/index.less
  11. +0
    -0
      react-ui/src/components/CodeConfigItem/index.tsx
  12. +1
    -1
      react-ui/src/components/CodeSelect/index.tsx
  13. +0
    -0
      react-ui/src/components/CodeSelectorModal/index.less
  14. +0
    -0
      react-ui/src/components/CodeSelectorModal/index.tsx
  15. +3
    -0
      react-ui/src/components/FullScreenFrame/index.tsx
  16. +9
    -5
      react-ui/src/components/IFramePage/index.tsx
  17. +0
    -0
      react-ui/src/components/InfoGroup/InfoGroupTitle.less
  18. +1
    -1
      react-ui/src/components/InfoGroup/InfoGroupTitle.tsx
  19. +1
    -1
      react-ui/src/components/InfoGroup/index.tsx
  20. +1
    -0
      react-ui/src/components/KFModal/index.tsx
  21. +1
    -1
      react-ui/src/pages/ModelDeployment/components/VersionBasicInfo/index.tsx
  22. +1
    -1
      react-ui/src/pages/Pipeline/components/PipelineNodeDrawer/index.tsx
  23. +31
    -0
      react-ui/src/stories/IFramePage.stories.tsx
  24. +6
    -0
      react-ui/src/stories/KFModal.stories.tsx
  25. +6
    -4
      react-ui/src/stories/ParameterSelect.stories.tsx
  26. +3
    -1
      react-ui/src/styles/theme.less
  27. +1
    -1
      react-ui/tsconfig.json

+ 0
- 7
react-ui/.gitignore View File

@@ -41,12 +41,5 @@ screenshot
build

pnpm-lock.yaml
/src/services/codeConfig/index.js
/src/pages/CodeConfig/components/AddCodeConfigModal/index.less
/src/pages/CodeConfig/List/index.less
/src/pages/Dataset/components/ResourceItem/index.less
/src/pages/CodeConfig/components/AddCodeConfigModal/index.tsx
/src/pages/CodeConfig/components/CodeConfigItem/index.tsx
/src/pages/Dataset/components/ResourceItem/index.tsx

*storybook.log

+ 16
- 0
react-ui/.storybook/babel-plugin-auto-css-modules.js View File

@@ -0,0 +1,16 @@
export default function(babel) {
const { types: t } = babel;
return {
visitor: {
ImportDeclaration(path) {
const source = path.node.source.value;
// console.log("zzzz", source);
if (source.endsWith('.less')) {
if (path.node.specifiers.length > 0) {
path.node.source.value += "?modules";
}
}
},
},
};
};

+ 71
- 38
react-ui/.storybook/main.ts View File

@@ -5,7 +5,8 @@ import webpack from 'webpack';
const config: StorybookConfig = {
stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
addons: [
'@storybook/addon-webpack5-compiler-swc',
// '@storybook/addon-webpack5-compiler-swc',
'@storybook/addon-webpack5-compiler-babel',
'@storybook/addon-onboarding',
'@storybook/addon-essentials',
'@chromatic-com/storybook',
@@ -20,51 +21,75 @@ const config: StorybookConfig = {
config.resolve.alias = {
...config.resolve.alias,
'@': path.resolve(__dirname, '../src'),
// '@@': path.resolve(__dirname, '../src/.umi'),
// '@umijs/max':
// '/Users/cp3hnu/Documents/company/ci4sManagement-cloud/react-ui/node_modules/umi',
'@umijs/max$': path.resolve(__dirname, './mock/umijs.tsx'),
};
}
if (config.module && config.module.rules) {
config.module.rules.push({
test: /\.less$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 1,
import: true,
esModule: true,
modules: {
auto: (resourcePath: string) => {
if (
resourcePath.endsWith('MenuIconSelector/index.less') ||
resourcePath.endsWith('theme.less')
) {
return true;
} else {
return false;
}
config.module.rules.push(
{
test: /\.less$/,
oneOf: [
{
resourceQuery: /modules/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 1,
import: true,
esModule: true,
modules: {
localIdentName: '[local]___[hash:base64:5]',
},
},
},
localIdentName: '[local]___[hash:base64:5]',
},
{
loader: 'less-loader',
options: {
lessOptions: {
javascriptEnabled: true, // 如果需要支持 Ant Design 的 Less 变量,开启此项
modifyVars: {
hack: 'true; @import "@/styles/theme.less";',
},
},
},
},
],
include: path.resolve(__dirname, '../src'), // 限制范围,避免处理 node_modules
},
},
{
loader: 'less-loader',
options: {
lessOptions: {
javascriptEnabled: true, // 如果需要支持 Ant Design 的 Less 变量,开启此项
modifyVars: {
hack: 'true; @import "@/styles/theme.less";',
{
use: [
'style-loader',
'css-loader',
{
loader: 'less-loader',
options: {
lessOptions: {
javascriptEnabled: true, // 如果需要支持 Ant Design 的 Less 变量,开启此项
modifyVars: {
hack: 'true; @import "@/styles/theme.less";',
},
},
},
},
},
],
include: path.resolve(__dirname, '../src'), // 限制范围,避免处理 node_modules
},
],
},
{
test: /\.(tsx?|jsx?)$/,
loader: 'ts-loader',
options: {
transpileOnly: true,
},
],
include: path.resolve(__dirname, '../src'), // 限制范围,避免处理 node_modules
});
include: [
path.resolve(__dirname, '../src'), // 限制范围,避免处理 node_modules
path.resolve(__dirname, './'),
],
},
);
}
if (config.plugins) {
config.plugins.push(
@@ -76,5 +101,13 @@ const config: StorybookConfig = {

return config;
},
babel: async (config: any) => {
if (!config.plugins) {
config.plugins = [];
}

config.plugins.push(path.resolve(__dirname, './babel-plugin-auto-css-modules.js'));
return config;
},
};
export default config;

+ 12
- 0
react-ui/.storybook/mock/umijs.tsx View File

@@ -0,0 +1,12 @@
export const Link = ({ to, children, ...props }: any) => (
<a href={typeof to === 'string' ? to : '#'} {...props}>
{children}
</a>
);

export const request = () => {
return Promise.resolve({
success: true,
data: { message: 'Mocked response' },
});
};

+ 55
- 62
react-ui/.storybook/preview.tsx View File

@@ -4,8 +4,6 @@ import themes from '@/styles/theme.less';
import type { Preview } from '@storybook/react';
import { App, ConfigProvider } from 'antd';
import zhCN from 'antd/locale/zh_CN';
import React from 'react';
import { BrowserRouter as Router } from 'react-router-dom';
import './storybook.css';

const preview: Preview = {
@@ -16,71 +14,66 @@ const preview: Preview = {
date: /Date$/i,
},
},
actions: { argTypesRegex: '^on.*' },
},
decorators: [
(Story) => (
<React.Fragment>
<ConfigProvider
locale={zhCN}
theme={{
token: {
colorPrimary: themes['primaryColor'],
colorSuccess: themes['successColor'],
colorError: themes['errorColor'],
colorWarning: themes['warningColor'],
colorLink: themes['primaryColor'],
colorText: themes['textColor'],
controlHeightLG: 46,
<ConfigProvider
locale={zhCN}
theme={{
token: {
colorPrimary: themes['primaryColor'],
colorSuccess: themes['successColor'],
colorError: themes['errorColor'],
colorWarning: themes['warningColor'],
colorLink: themes['primaryColor'],
colorText: themes['textColor'],
controlHeightLG: 46,
},
components: {
Button: {
defaultBg: 'rgba(22, 100, 255, 0.06)',
defaultBorderColor: 'rgba(22, 100, 255, 0.11)',
defaultColor: themes['textColor'],
defaultHoverBg: 'rgba(22, 100, 255, 0.06)',
defaultHoverBorderColor: 'rgba(22, 100, 255, 0.5)',
defaultHoverColor: '#3F7FFF ',
defaultActiveBg: 'rgba(22, 100, 255, 0.12)',
defaultActiveBorderColor: 'rgba(22, 100, 255, 0.75)',
defaultActiveColor: themes['primaryColor'],
contentFontSize: parseInt(themes['fontSize']),
},
components: {
Button: {
defaultBg: 'rgba(22, 100, 255, 0.06)',
defaultBorderColor: 'rgba(22, 100, 255, 0.11)',
defaultColor: themes['textColor'],
defaultHoverBg: 'rgba(22, 100, 255, 0.06)',
defaultHoverBorderColor: 'rgba(22, 100, 255, 0.5)',
defaultHoverColor: '#3F7FFF ',
defaultActiveBg: 'rgba(22, 100, 255, 0.12)',
defaultActiveBorderColor: 'rgba(22, 100, 255, 0.75)',
defaultActiveColor: themes['primaryColor'],
contentFontSize: parseInt(themes['fontSize']),
},
Input: {
inputFontSize: parseInt(themes['fontSizeInput']),
inputFontSizeLG: parseInt(themes['fontSizeInputLg']),
paddingBlockLG: 10,
},
Select: {
singleItemHeightLG: 46,
optionSelectedColor: themes['primaryColor'],
},
Table: {
headerBg: 'rgba(242, 244, 247, 0.36)',
headerBorderRadius: 4,
rowSelectedBg: 'rgba(22, 100, 255, 0.05)',
},
Tabs: {
titleFontSize: 16,
},
Form: {
labelColor: 'rgba(29, 29, 32, 0.8);',
},
Breadcrumb: {
iconFontSize: parseInt(themes['fontSize']),
linkColor: 'rgba(29, 29, 32, 0.7)',
separatorColor: 'rgba(29, 29, 32, 0.7)',
},
Input: {
inputFontSize: parseInt(themes['fontSizeInput']),
inputFontSizeLG: parseInt(themes['fontSizeInputLg']),
paddingBlockLG: 10,
},
}}
>
<App message={{ maxCount: 3 }}>
<Router>
<Story />
</Router>
</App>
</ConfigProvider>
</React.Fragment>
Select: {
singleItemHeightLG: 46,
optionSelectedColor: themes['primaryColor'],
},
Table: {
headerBg: 'rgba(242, 244, 247, 0.36)',
headerBorderRadius: 4,
rowSelectedBg: 'rgba(22, 100, 255, 0.05)',
},
Tabs: {
titleFontSize: 16,
},
Form: {
labelColor: 'rgba(29, 29, 32, 0.8);',
},
Breadcrumb: {
iconFontSize: parseInt(themes['fontSize']),
linkColor: 'rgba(29, 29, 32, 0.7)',
separatorColor: 'rgba(29, 29, 32, 0.7)',
},
},
}}
>
<App message={{ maxCount: 3 }}>
<Story />
</App>
</ConfigProvider>
),
],
};


+ 26
- 0
react-ui/.storybook/tsconfig.json View File

@@ -0,0 +1,26 @@
{
"compilerOptions": {
"target": "esnext", // 指定ECMAScript目标版本
"lib": ["dom", "dom.iterable", "esnext"], // 要包含在编译中的库文件列表
"allowJs": true, // 允许编译JavaScript文件
"skipLibCheck": true, // 跳过所有声明文件的类型检查
"esModuleInterop": true, // 禁用命名空间导入(import * as fs from "fs"),并启用CJS/AMD/UMD样式的导入(import fs from "fs")
"allowSyntheticDefaultImports": true, // 允许从没有默认导出的模块进行默认导入
"strict": true, // 启用所有严格类型检查选项
"forceConsistentCasingInFileNames": false, // 允许对同一文件的引用使用不一致的大小写
"module": "esnext", // 指定模块代码生成
"moduleResolution": "bundler", // 使用bundlers样式解析模块
"isolatedModules": true, // 无条件地为未解析的文件发出导入
"resolveJsonModule": true, // 包含.json扩展名的模块
"noEmit": true, // 不发出输出(即不编译代码,只进行类型检查)
"jsx": "react-jsx", // 在.tsx文件中支持JSX
"sourceMap": true, // 生成相应的.map文件
"declaration": true, // 生成相应的.d.ts文件
"noUnusedLocals": true, // 报告未使用的局部变量错误
"noUnusedParameters": true, // 报告未使用的参数错误
"incremental": true, // 通过读写磁盘上的文件来启用增量编译
"noFallthroughCasesInSwitch": true, // 报告switch语句中的fallthrough案例错误
"strictNullChecks": true, // 启用严格的null检查
"baseUrl": "./"
}
}

+ 20
- 0
react-ui/.storybook/typings.d.ts View File

@@ -0,0 +1,20 @@
declare module 'slash2';
declare module '*.css';
declare module '*.less';
declare module '*.scss';
declare module '*.sass';
declare module '*.svg';
declare module '*.png';
declare module '*.jpg';
declare module '*.jpeg';
declare module '*.gif';
declare module '*.bmp';
declare module '*.tiff';
declare module 'omit.js';
declare module 'numeral';
declare module '@antv/data-set';
declare module 'mockjs';
declare module 'react-fittext';
declare module 'bizcharts-plugin-slider';

declare const REACT_APP_ENV: 'test' | 'dev' | 'pre' | false;

+ 2
- 0
react-ui/package.json View File

@@ -90,6 +90,7 @@
"@storybook/addon-interactions": "~8.5.3",
"@storybook/addon-onboarding": "~8.5.3",
"@storybook/addon-styling-webpack": "~1.0.1",
"@storybook/addon-webpack5-compiler-babel": "~3.0.5",
"@storybook/addon-webpack5-compiler-swc": "~2.0.0",
"@storybook/blocks": "~8.5.3",
"@storybook/react": "~8.5.3",
@@ -121,6 +122,7 @@
"prettier": "^2.8.1",
"storybook": "~8.5.3",
"swagger-ui-dist": "^4.18.2",
"ts-loader": "~9.5.2",
"ts-node": "^10.9.1",
"typescript": "^5.0.4",
"umi-presets-pro": "^2.0.0"


+ 1
- 1
react-ui/src/components/BasicInfo/BasicInfoItemValue.tsx View File

@@ -5,8 +5,8 @@
*/

import { isEmpty } from '@/utils';
import { Link } from '@umijs/max';
import { Typography } from 'antd';
import { Link } from 'react-router-dom';

type BasicInfoItemValueProps = {
/** 值是否显示省略号 */


react-ui/src/pages/Pipeline/components/CodeConfigItem/index.less → react-ui/src/components/CodeConfigItem/index.less View File


react-ui/src/pages/Pipeline/components/CodeConfigItem/index.tsx → react-ui/src/components/CodeConfigItem/index.tsx View File


+ 1
- 1
react-ui/src/components/CodeSelect/index.tsx View File

@@ -4,8 +4,8 @@
* @Description: 流水线选择代码配置表单
*/

import CodeSelectorModal from '@/components/CodeSelectorModal';
import KFIcon from '@/components/KFIcon';
import CodeSelectorModal from '@/pages/Pipeline/components/CodeSelectorModal';
import { openAntdModal } from '@/utils/modal';
import { Button } from 'antd';
import ParameterInput, { type ParameterInputProps } from '../ParameterInput';


react-ui/src/pages/Pipeline/components/CodeSelectorModal/index.less → react-ui/src/components/CodeSelectorModal/index.less View File


react-ui/src/pages/Pipeline/components/CodeSelectorModal/index.tsx → react-ui/src/components/CodeSelectorModal/index.tsx View File


+ 3
- 0
react-ui/src/components/FullScreenFrame/index.tsx View File

@@ -14,6 +14,9 @@ type FullScreenFrameProps = {
onError?: (e?: React.SyntheticEvent<HTMLIFrameElement, Event>) => void;
};

/**
* 全屏 iframe,IFramePage 组件的子组件,开发中应该使用 IFramePage
*/
function FullScreenFrame({ url, className, style, onLoad, onError }: FullScreenFrameProps) {
return (
<div className={classNames('kf-full-screen-frame', className ?? '')} style={style}>


+ 9
- 5
react-ui/src/components/IFramePage/index.tsx View File

@@ -12,32 +12,36 @@ export enum IframePageType {
DatasetAnnotation = 'DatasetAnnotation', // 数据标注
AppDevelopment = 'AppDevelopment', // 应用开发
DevEnv = 'DevEnv', // 开发环境
GitLink = 'GitLink',
GitLink = 'GitLink', // git link
}

const getRequestAPI = (type: IframePageType): (() => Promise<any>) => {
switch (type) {
case IframePageType.DatasetAnnotation:
case IframePageType.DatasetAnnotation: // 数据标注
return () => Promise.resolve({ code: 200, data: 'http://172.20.32.181:18888/oauth/login' }); //getLabelStudioUrl;
case IframePageType.AppDevelopment:
case IframePageType.AppDevelopment: // 应用开发
return () => Promise.resolve({ code: 200, data: 'http://172.20.32.185:30080/' });
case IframePageType.DevEnv:
case IframePageType.DevEnv: // 开发环境
return () =>
Promise.resolve({
code: 200,
data: SessionStorage.getItem(SessionStorage.editorUrlKey) || '',
});
case IframePageType.GitLink:
case IframePageType.GitLink: // git link
return () => Promise.resolve({ code: 200, data: 'http://172.20.32.201:4000' });
}
};

type IframePageProps = {
/** 子系统 */
type: IframePageType;
/** 自定义样式类名 */
className?: string;
/** 自定义样式 */
style?: React.CSSProperties;
};

/** 系统内嵌 iframe,目前系统有数据标注、应用开发、开发环境、GitLink 四个子系统,使用时可以添加其他子系统 */
function IframePage({ type, className, style }: IframePageProps) {
const [iframeUrl, setIframeUrl] = useState('');
const [loading, setLoading] = useState(false);


react-ui/src/components/InfoGroupTitle/index.less → react-ui/src/components/InfoGroup/InfoGroupTitle.less View File


react-ui/src/components/InfoGroupTitle/index.tsx → react-ui/src/components/InfoGroup/InfoGroupTitle.tsx View File

@@ -1,6 +1,6 @@
import { Flex } from 'antd';
import classNames from 'classnames';
import './index.less';
import './InfoGroupTitle.less';

type InfoGroupTitleProps = {
/** 标题 */

+ 1
- 1
react-ui/src/components/InfoGroup/index.tsx View File

@@ -1,5 +1,5 @@
import classNames from 'classnames';
import InfoGroupTitle from '../InfoGroupTitle';
import InfoGroupTitle from './InfoGroupTitle';
import './index.less';

type InfoGroupProps = {


+ 1
- 0
react-ui/src/components/KFModal/index.tsx View File

@@ -10,6 +10,7 @@ import KFModalTitle from './KFModalTitle';
import './index.less';

export interface KFModalProps extends ModalProps {
/** 标题图片 */
image?: string;
}



+ 1
- 1
react-ui/src/pages/ModelDeployment/components/VersionBasicInfo/index.tsx View File

@@ -18,7 +18,7 @@ const formatStatus = (status?: ServiceRunStatus) => {
}

return (
<Flex align="center" style={{ marginLeft: '16px', fontSize: '16px', lineHeight: 1.6 }}>
<Flex align="center" style={{ fontSize: '16px', lineHeight: 1.6 }}>
{ModelDeployStatusCell(status)}
</Flex>
);


+ 1
- 1
react-ui/src/pages/Pipeline/components/PipelineNodeDrawer/index.tsx View File

@@ -1,3 +1,4 @@
import CodeSelectorModal from '@/components/CodeSelectorModal';
import KFIcon from '@/components/KFIcon';
import ParameterInput, { requiredValidator } from '@/components/ParameterInput';
import ParameterSelect from '@/components/ParameterSelect';
@@ -21,7 +22,6 @@ import { INode } from '@antv/g6';
import { Button, Drawer, Form, Input, MenuProps, Select } from 'antd';
import { NamePath } from 'antd/es/form/interface';
import { forwardRef, useImperativeHandle, useState } from 'react';
import CodeSelectorModal from '../CodeSelectorModal';
import PropsLabel from '../PropsLabel';
import styles from './index.less';
const { TextArea } = Input;


+ 31
- 0
react-ui/src/stories/IFramePage.stories.tsx View File

@@ -0,0 +1,31 @@
import IFramePage, { IframePageType } from '@/components/IFramePage';
import type { Meta, StoryObj } from '@storybook/react';

// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export
const meta = {
title: 'Components/IFramePage',
component: IFramePage,
parameters: {
// Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout
// layout: 'centered',
},
// This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs
tags: ['autodocs'],
// More on argTypes: https://storybook.js.org/docs/api/argtypes
argTypes: {
type: { control: 'select', options: Object.values(IframePageType) },
},
// Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args
// args: { onClick: fn() },
} satisfies Meta<typeof IFramePage>;

export default meta;
type Story = StoryObj<typeof meta>;

// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args
export const Primary: Story = {
args: {
type: IframePageType.GitLink,
style: { height: '500px' },
},
};

+ 6
- 0
react-ui/src/stories/KFModal.stories.tsx View File

@@ -18,6 +18,12 @@ const meta = {
// More on argTypes: https://storybook.js.org/docs/api/argtypes
argTypes: {
// backgroundColor: { control: 'color' },
title: {
description: '标题',
},
open: {
description: '对话框是否可见',
},
},
// Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args
args: { onCancel: fn(), onOk: fn() },


react-ui/src/stories/InfoGroupTitle.stories.tsx → react-ui/src/stories/ParameterSelect.stories.tsx View File

@@ -1,10 +1,11 @@
import InfoGroupTitle from '@/components/InfoGroupTitle';
import MirrorBasic from '@/assets/img/mirror-basic.png';
import ParameterSelect from '@/components/ParameterSelect';
import type { Meta, StoryObj } from '@storybook/react';

// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export
const meta = {
title: 'Components/InfoGroupTitle',
component: InfoGroupTitle,
title: 'Components/ParameterSelect',
component: ParameterSelect,
parameters: {
// Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout
// layout: 'centered',
@@ -17,7 +18,7 @@ const meta = {
},
// Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args
// args: { onClick: fn() },
} satisfies Meta<typeof InfoGroupTitle>;
} satisfies Meta<typeof ParameterSelect>;

export default meta;
type Story = StoryObj<typeof meta>;
@@ -26,5 +27,6 @@ type Story = StoryObj<typeof meta>;
export const Primary: Story = {
args: {
title: '基本信息',
image: MirrorBasic,
},
};

+ 3
- 1
react-ui/src/styles/theme.less View File

@@ -49,7 +49,7 @@
// padding
@content-padding: 25px;

// 函数
// 函数,hex 添加 alpha 值
.addAlpha(@color, @alpha) {
@red: red(@color);
@green: green(@color);
@@ -58,6 +58,7 @@
}

// 混合
// 单行
.singleLine() {
overflow: hidden;
white-space: nowrap;
@@ -65,6 +66,7 @@
word-break: break-all;
}

// 多行
.multiLine(@line) {
display: -webkit-box;
overflow: hidden;


+ 1
- 1
react-ui/tsconfig.json View File

@@ -9,7 +9,7 @@
"strict": true, // 启用所有严格类型检查选项
"forceConsistentCasingInFileNames": false, // 允许对同一文件的引用使用不一致的大小写
"module": "esnext", // 指定模块代码生成
"moduleResolution": "node", // 使用Node.js样式解析模块
"moduleResolution": "bundler", // 使用bundlers样式解析模块
"isolatedModules": true, // 无条件地为未解析的文件发出导入
"resolveJsonModule": true, // 包含.json扩展名的模块
"noEmit": true, // 不发出输出(即不编译代码,只进行类型检查)


Loading…
Cancel
Save