ant-design-icons
ant-design-icons copied to clipboard
Create a reusable alias for each forwardRef'd component
This is a slightly experimental PR since I'm not that familiar with the codebase; however, an investigation on compiling ant-design uncovered that a lot of string literal type syntax nodes were being created during parsing. We found that many of them came directly from the .d.ts
files of @ant-design/icons
.
This is because React.forwardRef
creates several anonymous intermediate types and TypeScript's declaration emit ends up having to write those types inline. Those types each contain over 360 string literals which are all the same!
declare const _default: React.ForwardRefExoticComponent<Pick<AntdIconProps, "max" | "required" | "default" | "high" | "low" | "disabled" | "start" | "open" | "media" | "hidden" | "cite" | "data" | "dir" | "form" | "label" | "slot" | "span" | "style" | "summary" | "title" | "pattern" | "async" | "defer" | "manifest" | "color" | "content" | "size" | "wrap" | "multiple" | "height" | "rotate" | "translate" | "width" | "prefix" | "src" | "children" | "key" | "list" | "step" | "value" | "aria-label" | "spin" | "accept" | "acceptCharset" | "action" | "allowFullScreen" | "allowTransparency" | "alt" | "as" | "autoComplete" | "autoFocus" | "autoPlay" | "capture" | "cellPadding" | "cellSpacing" | "charSet" | "challenge" | "checked" | "classID" | "cols" | "colSpan" | "controls" | "coords" | "crossOrigin" | "dateTime" | "download" | "encType" | "formAction" | "formEncType" | "formMethod" | "formNoValidate" | "formTarget" | "frameBorder" | "headers" | "href" | "hrefLang" | "htmlFor" | "httpEquiv" | "integrity" | "keyParams" | "keyType" | "kind" | "loop" | "marginHeight" | "marginWidth" | "maxLength" | "mediaGroup" | "method" | "min" | "minLength" | "muted" | "name" | "nonce" | "noValidate" | "optimum" | "placeholder" | "playsInline" | "poster" | "preload" | "readOnly" | "rel" | "reversed" | "rows" | "rowSpan" | "sandbox" | "scope" | "scoped" | "scrolling" | "seamless" | "selected" | "shape" | "sizes" | "srcDoc" | "srcLang" | "srcSet" | "target" | "type" | "useMap" | "wmode" | "defaultChecked" | "defaultValue" | "suppressContentEditableWarning" | "suppressHydrationWarning" | "accessKey" | "className" | "contentEditable" | "contextMenu" | "draggable" | "id" | "lang" | "spellCheck" | "tabIndex" | "radioGroup" | "role" | "about" | "datatype" | "inlist" | "property" | "resource" | "typeof" | "vocab" | "autoCapitalize" | "autoCorrect" | "autoSave" | "itemProp" | "itemScope" | "itemType" | "itemID" | "itemRef" | "results" | "security" | "unselectable" | "inputMode" | "is" | "aria-activedescendant" | "aria-atomic" | "aria-autocomplete" | "aria-busy" | "aria-checked" | "aria-colcount" | "aria-colindex" | "aria-colspan" | "aria-controls" | "aria-current" | "aria-describedby" | "aria-details" | "aria-disabled" | "aria-dropeffect" | "aria-errormessage" | "aria-expanded" | "aria-flowto" | "aria-grabbed" | "aria-haspopup" | "aria-hidden" | "aria-invalid" | "aria-keyshortcuts" | "aria-labelledby" | "aria-level" | "aria-live" | "aria-modal" | "aria-multiline" | "aria-multiselectable" | "aria-orientation" | "aria-owns" | "aria-placeholder" | "aria-posinset" | "aria-pressed" | "aria-readonly" | "aria-relevant" | "aria-required" | "aria-roledescription" | "aria-rowcount" | "aria-rowindex" | "aria-rowspan" | "aria-selected" | "aria-setsize" | "aria-sort" | "aria-valuemax" | "aria-valuemin" | "aria-valuenow" | "aria-valuetext" | "dangerouslySetInnerHTML" | "onCopy" | "onCopyCapture" | "onCut" | "onCutCapture" | "onPaste" | "onPasteCapture" | "onCompositionEnd" | "onCompositionEndCapture" | "onCompositionStart" | "onCompositionStartCapture" | "onCompositionUpdate" | "onCompositionUpdateCapture" | "onFocus" | "onFocusCapture" | "onBlur" | "onBlurCapture" | "onChange" | "onChangeCapture" | "onBeforeInput" | "onBeforeInputCapture" | "onInput" | "onInputCapture" | "onReset" | "onResetCapture" | "onSubmit" | "onSubmitCapture" | "onInvalid" | "onInvalidCapture" | "onLoad" | "onLoadCapture" | "onError" | "onErrorCapture" | "onKeyDown" | "onKeyDownCapture" | "onKeyPress" | "onKeyPressCapture" | "onKeyUp" | "onKeyUpCapture" | "onAbort" | "onAbortCapture" | "onCanPlay" | "onCanPlayCapture" | "onCanPlayThrough" | "onCanPlayThroughCapture" | "onDurationChange" | "onDurationChangeCapture" | "onEmptied" | "onEmptiedCapture" | "onEncrypted" | "onEncryptedCapture" | "onEnded" | "onEndedCapture" | "onLoadedData" | "onLoadedDataCapture" | "onLoadedMetadata" | "onLoadedMetadataCapture" | "onLoadStart" | "onLoadStartCapture" | "onPause" | "onPauseCapture" | "onPlay" | "onPlayCapture" | "onPlaying" | "onPlayingCapture" | "onProgress" | "onProgressCapture" | "onRateChange" | "onRateChangeCapture" | "onSeeked" | "onSeekedCapture" | "onSeeking" | "onSeekingCapture" | "onStalled" | "onStalledCapture" | "onSuspend" | "onSuspendCapture" | "onTimeUpdate" | "onTimeUpdateCapture" | "onVolumeChange" | "onVolumeChangeCapture" | "onWaiting" | "onWaitingCapture" | "onAuxClick" | "onAuxClickCapture" | "onClick" | "onClickCapture" | "onContextMenu" | "onContextMenuCapture" | "onDoubleClick" | "onDoubleClickCapture" | "onDrag" | "onDragCapture" | "onDragEnd" | "onDragEndCapture" | "onDragEnter" | "onDragEnterCapture" | "onDragExit" | "onDragExitCapture" | "onDragLeave" | "onDragLeaveCapture" | "onDragOver" | "onDragOverCapture" | "onDragStart" | "onDragStartCapture" | "onDrop" | "onDropCapture" | "onMouseDown" | "onMouseDownCapture" | "onMouseEnter" | "onMouseLeave" | "onMouseMove" | "onMouseMoveCapture" | "onMouseOut" | "onMouseOutCapture" | "onMouseOver" | "onMouseOverCapture" | "onMouseUp" | "onMouseUpCapture" | "onSelect" | "onSelectCapture" | "onTouchCancel" | "onTouchCancelCapture" | "onTouchEnd" | "onTouchEndCapture" | "onTouchMove" | "onTouchMoveCapture" | "onTouchStart" | "onTouchStartCapture" | "onPointerDown" | "onPointerDownCapture" | "onPointerMove" | "onPointerMoveCapture" | "onPointerUp" | "onPointerUpCapture" | "onPointerCancel" | "onPointerCancelCapture" | "onPointerEnter" | "onPointerEnterCapture" | "onPointerLeave" | "onPointerLeaveCapture" | "onPointerOver" | "onPointerOverCapture" | "onPointerOut" | "onPointerOutCapture" | "onGotPointerCapture" | "onGotPointerCaptureCapture" | "onLostPointerCapture" | "onLostPointerCaptureCapture" | "onScroll" | "onScrollCapture" | "onWheel" | "onWheelCapture" | "onAnimationStart" | "onAnimationStartCapture" | "onAnimationEnd" | "onAnimationEndCapture" | "onAnimationIteration" | "onAnimationIterationCapture" | "onTransitionEnd" | "onTransitionEndCapture" | "twoToneColor"> & React.RefAttributes<HTMLSpanElement>>;
export default _default;
However, if we create a type alias (here called ForwardRefComponentBase
) and annotate every component with that type, the declaration emit will reuse that type instead.
declare const Comp: ForwardRefComponentBase<AntdIconProps>;
export default Comp;
This brings the size down of each component from 5.98KB to 165 byes. This cumulatively brings down the size of your declaration files from 4.66MB to 189KB.
That's a substantial reduction of the size of your published packages. It will also reduce the amount of code that TypeScript needs to parse and keep in memory for all users, meaning faster builds for all your consumers.
It's not highly scientific, but here's a before/after of just doing type-checking @ant-design/icons
:
@afc163 @zombieJ @John60676 any chance I can get a review on this PR? I expect it'll have a great downstream effect for you and your users!
/rebase
CI failed, could you fix it?
src/icons/WalletOutlined.tsx(11,7): error TS2604: JSX element type 'AntdIcon' does not have any construct or call signatures.
src/icons/WalletOutlined.tsx(15,13): error TS2304: Cannot find name 'ForwardRefComponentBase'.
src/icons/WalletOutlined.tsx(15,13): error TS4025: Exported variable 'Comp' has or is using private name 'ForwardRefComponentBase'.
src/icons/WalletTwoTone.tsx(11,7): error TS2604: JSX element type 'AntdIcon' does not have any construct or call signatures.
src/icons/WalletTwoTone.tsx(15,13): error TS2304: Cannot find name 'ForwardRefComponentBase'.
src/icons/WalletTwoTone.tsx(15,13): error TS4025: Exported variable 'Comp' has or is using private name 'ForwardRefComponentBase'.
src/icons/WarningFilled.tsx(11,7): error TS2604: JSX element type 'AntdIcon' does not have any construct or call signatures.
src/icons/WarningFilled.tsx(15,13): error TS2304: Cannot find name 'ForwardRefComponentBase'.
src/icons/WarningFilled.tsx(15,13): error TS4025: Exported variable 'Comp' has or is using private name 'ForwardRefComponentBase'.
src/icons/WarningOutlined.tsx(11,7): error TS2604: JSX element type 'AntdIcon' does not have any construct or call signatures
I've pushed the changes, but I don't seem to be getting a full CI run.
@afc163 just checking in - is there an easy way to kick off the CI?
Pinging @tangjinzhou @zombieJ @afc163 @hullis, this is an old PR but will likely speed up load time, check time, and memory usage for everyone using ant-design
Must fix CI firstly, I'll do that asap
@DanielRosenwasser could you please rebase master?
@vagusX thanks for following up - I was on vacation back then. I've rebased the commits.