material-ui [SelectField]引入新组件

sq1bmfud  于 2022-10-29  发布在  其他
关注(0)|答案(5)|浏览(239)

React Material-UI的最小示例(仅导入了TextField组件)-结果包大小为250 Kb!
https://github.com/pqr/react-mui-treeshake-does-not-work的最大值
webpack-bundle-analyzer显示所有内容都已导入,没有任何内容发生树摇动。
根据文档https://material-ui.com/guides/minimizing-bundle-size/,树摇动应该工作,引用:
Material-UI的树抖动在现代框架中是开箱即用的。Material-UI在顶层material-ui导入中公开了其完整的API。如果您使用的是ES6模块和支持树抖动的捆绑器(webpack〉= 2.x,带有一个标志的包),您可以安全地使用命名的导入,并且仍然可以自动获得优化的捆绑包大小:

import { Button, TextField } from '@material-ui/core';

但正如这个最小的例子所示,它并不是开箱即用的。
我做了几个实验,通读了问题和StackOverflow,都没能找到解决方案。

  • [+]最新版本中存在该问题。
  • [+]我已经搜索了此存储库的issues,相信这不是重复的。

当前行为😯

仅导入TextField的最小应用程序包大小约为250 Kb,所有内容均包含在包中(使用webpack-bundle-analyzer分析

预期行为🤔

Bundle不应包含任何与唯一导入的TextField无关的代码,树摇才能正常工作

重现步骤🕹

git clone git@github.com:pqr/react-mui-treeshake-does-not-work.git
cd react-mui-treeshake-does-not-work
npm install
npm run build
npm run analyze

您的环境🌎

| 技术人员|版本号|
| - -|- -|
| 材料-UI| v4.11 |
| React|16.13.1节|
| 浏览器|任何|
| 类型脚本|没有|
| 网络包|四点四十三分|

z9smfwbn

z9smfwbn1#

在我看来,这很好。这是一个TextField过载的问题。它目前包括Select组件,该组件需要PopoverModalList等。
树抖动正在工作,否则你会看到更多的组件。你可以通过导入Button来验证这一点。

vnjpjtjt

vnjpjtjt2#

这更像是一个TextField重载程度的问题。
@eps1lon我们讨论的时候(或者甚至同意)将select用例移到TextField之外,使用新的SelectField组件。我不知道我们有专门的问题。我们使用这个问题怎么样?它似乎完全匹配(不同的是,作者没有意识到TextField的整个依赖链相当大)如果我们这样做,我们可以重新打开,直到修复:)。

mwkjh3gx

mwkjh3gx3#

这一期是关于树摇的。为什么重新定位它如此重要?这是什么解决了一个新问题不能?

avwztpqn

avwztpqn4#

@pqr希望他的应用程序只包含他需要的代码。

他注意到很多组件与显示输入没有明确的关系。他继续假设这是因为树的震动被破坏了。错了。
因此,据我所知,我们使用SelectField组件建议来覆盖相同的根本痛点。只是作者对痛点来源的解释是错误的,根本问题仍然存在:文本字段不应捆绑选择。
建议的解决方案是:

-<TextField select />
+<SelectField />
ilmyapht

ilmyapht5#

我们的团队对此也是措手不及。我们注意到表单页面的捆绑包大小非常庞大,尽管我们只使用了material-ui中的文本字段和按钮。我们花了很长时间试图找出捆绑包在哪里出错,并导入了Select和Modal,结果发现TextField默认包含Select、Modal和它们的许多依赖项。
对于遇到这个问题的其他开发人员,这里有一个权宜之计,可以在material-ui进行正式修复的同时大大减少TextFields的大小。(这样,只有您使用的变体类型才会包含在套件中,而不是预设包含所有3个标准、轮廓和填充变体元件):
ComposableTextField.tsx

import React from "react";
import { InputProps } from "@material-ui/core/Input";
import { TextFieldProps } from "@material-ui/core/TextField";
import FormControl from "@material-ui/core/FormControl";
import InputLabel from "@material-ui/core/InputLabel";
import FormHelperText from "@material-ui/core/FormHelperText";

interface ComposableTextFieldProps
  extends Omit<TextFieldProps, "select" | "SelectProps" | "children"> {
  InputComponent: React.ComponentType<InputProps>;
}

const ComposableTextField = React.forwardRef(
  (props: ComposableTextFieldProps, ref: React.Ref<HTMLDivElement>): JSX.Element => {
    const { InputComponent, ...textFieldProps } = props;
    const {
      autoComplete,
      autoFocus = false,
      className,
      color = "primary",
      defaultValue,
      disabled = false,
      error = false,
      FormHelperTextProps,
      fullWidth = false,
      helperText,
      id,
      InputLabelProps,
      inputProps,
      InputProps,
      inputRef,
      label,
      maxRows,
      minRows,
      multiline = false,
      name,
      onBlur,
      onChange,
      onFocus,
      placeholder,
      required = false,
      rows,
      type,
      value,
      variant = "outlined",
      ...other
    } = textFieldProps;

    if (!InputComponent) {
      return null;
    }

    const InputMore: Record<string, unknown> = {};

    if (variant === "outlined") {
      if (InputLabelProps && typeof InputLabelProps.shrink !== "undefined") {
        InputMore.notched = InputLabelProps.shrink;
      }
      if (label) {
        const displayRequired = InputLabelProps?.required ?? required;
        InputMore.label = (
          <>
            {label}
            {displayRequired && "\u00a0*"}
          </>
        );
      }
    }

    const helperTextId = helperText && id ? `${id}-helper-text` : undefined;
    const inputLabelId = label && id ? `${id}-label` : undefined;

    return (
      <FormControl
        className={["MuiTextField-root", className].filter(Boolean).join(" ")}
        disabled={disabled}
        error={error}
        fullWidth={fullWidth}
        ref={ref}
        required={required}
        color={color}
        variant={variant}
        {...other}
      >
        {label && (
          <InputLabel htmlFor={id} id={inputLabelId} {...InputLabelProps}>
            {label}
          </InputLabel>
        )}
        <InputComponent
          aria-describedby={helperTextId}
          autoComplete={autoComplete}
          autoFocus={autoFocus}
          defaultValue={defaultValue}
          fullWidth={fullWidth}
          multiline={multiline}
          name={name}
          rows={rows}
          maxRows={maxRows}
          minRows={minRows}
          type={type}
          value={value}
          id={id}
          inputRef={inputRef}
          onBlur={onBlur}
          onChange={onChange}
          onFocus={onFocus}
          placeholder={placeholder}
          inputProps={inputProps}
          {...InputMore}
          {...InputProps}
        />
        {helperText && (
          <FormHelperText id={helperTextId} {...FormHelperTextProps}>
            {helperText}
          </FormHelperText>
)}
</FormControl>
    );
  }
);

export default ComposableTextField;

只需将任何对TextField的引用替换为ComposableTextField组件即可。并确保传入您要使用的InputComponent变量:
替换为:

<TextField label="Outlined" variant="outlined" />

有了这个:

<ComposableTextField label="Outlined" variant="outlined" InputComponent={OutlinedInput} />

顺便提一下,material-ui文本字段文档确实提到了可以使用较低级别的组件来更好地定制TextFields,但也许还值得一提的是,可以使用这些较低级别的组件来减少Minimizing Your Bundle Size documentation中的包大小。

相关问题