Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create a reusable alias for each forwardRef'd component #479

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

DanielRosenwasser
Copy link

@DanielRosenwasser DanielRosenwasser commented Apr 22, 2021

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:

image

@DanielRosenwasser
Copy link
Author

@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!

@afc163
Copy link
Member

afc163 commented Aug 16, 2021

/rebase

@afc163
Copy link
Member

afc163 commented Aug 16, 2021

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

@DanielRosenwasser
Copy link
Author

I've pushed the changes, but I don't seem to be getting a full CI run.

@DanielRosenwasser
Copy link
Author

@afc163 just checking in - is there an easy way to kick off the CI?

@DanielRosenwasser
Copy link
Author

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

@afc163 afc163 requested a review from vagusX June 6, 2022 04:22
Copy link
Member

@vagusX vagusX left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@vagusX
Copy link
Member

vagusX commented Jun 7, 2022

Must fix CI firstly, I'll do that asap

@vagusX
Copy link
Member

vagusX commented Jun 10, 2022

@DanielRosenwasser could you please rebase master?

@DanielRosenwasser
Copy link
Author

@vagusX thanks for following up - I was on vacation back then. I've rebased the commits.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants