Skip to content

Ban export * in @fluentui/utilities for better tree-shakeability#22046

Merged
Hotell merged 1 commit intomicrosoft:masterfrom
tido64:tido/enable-no-export-all-utilities
Mar 14, 2022
Merged

Ban export * in @fluentui/utilities for better tree-shakeability#22046
Hotell merged 1 commit intomicrosoft:masterfrom
tido64:tido/enable-no-export-all-utilities

Conversation

@tido64
Copy link
Member

@tido64 tido64 commented Mar 10, 2022

Some bundlers, such as esbuild, are not able to tree-shake nested export * statements. Fixed them using the no-export-all ESLint rule.

Current Behavior

@fluentui/utilities (and the repo in general) currently makes heavy use of index.ts and export *. This breaks tree-shaking in some bundlers because they are not able to do deep analysis.

New Behavior

Converting to explicit exports helped me shave off 42 KB from this package alone.

@tido64
Copy link
Member Author

tido64 commented Mar 10, 2022

cc @dzearing

@codesandbox-ci
Copy link

codesandbox-ci bot commented Mar 10, 2022

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit 4270bdc:

Sandbox Source
@fluentui/react 8 starter Configuration
@fluentui/react-components 9 starter Configuration

@fabricteam
Copy link
Collaborator

fabricteam commented Mar 10, 2022

📊 Bundle size report

🤖 This report was generated against e6fa9864d66e5cdf4e965b6069f28c4455dd35dc

@size-auditor
Copy link

size-auditor bot commented Mar 10, 2022

Asset size changes

Size Auditor did not detect a change in bundle size for any component!

Baseline commit: e6fa9864d66e5cdf4e965b6069f28c4455dd35dc (build)

@fabricteam
Copy link
Collaborator

fabricteam commented Mar 10, 2022

Perf Analysis (@fluentui/react)

No significant results to display.

All results

Scenario Render type Master Ticks PR Ticks Iterations Status
BaseButton mount 931 957 5000
Breadcrumb mount 2720 2685 1000
Checkbox mount 1545 1505 5000
CheckboxBase mount 1314 1299 5000
ChoiceGroup mount 4772 4858 5000
ComboBox mount 1015 1017 1000
CommandBar mount 10572 10684 1000
ContextualMenu mount 12134 12144 1000
DefaultButton mount 1160 1177 5000
DetailsRow mount 3891 3937 5000
DetailsRowFast mount 3952 3915 5000
DetailsRowNoStyles mount 3716 3784 5000
Dialog mount 2325 2267 1000
DocumentCardTitle mount 161 170 1000
Dropdown mount 3456 3497 5000
FocusTrapZone mount 1839 1821 5000
FocusZone mount 1848 1809 5000
IconButton mount 1834 1810 5000
Label mount 356 366 5000
Layer mount 3063 3060 5000
Link mount 480 489 5000
MenuButton mount 1562 1537 5000
MessageBar mount 2213 2160 5000
Nav mount 3400 3426 1000
OverflowSet mount 1139 1100 5000
Panel mount 2223 2199 1000
Persona mount 862 852 1000
Pivot mount 1552 1479 1000
PrimaryButton mount 1399 1315 5000
Rating mount 7823 7774 5000
SearchBox mount 1371 1343 5000
Shimmer mount 2537 2561 5000
Slider mount 2029 1975 5000
SpinButton mount 5639 5284 5000
Spinner mount 444 460 5000
SplitButton mount 3334 3552 5000
Stack mount 544 519 5000
StackWithIntrinsicChildren mount 2386 2362 5000
StackWithTextChildren mount 5439 5404 5000
SwatchColorPicker mount 11828 11899 5000
TagPicker mount 2943 2781 5000
TeachingBubble mount 106155 99786 5000
Text mount 436 431 5000
TextField mount 1443 1480 5000
ThemeProvider mount 1220 1238 5000
ThemeProvider virtual-rerender 665 675 5000
ThemeProvider virtual-rerender-with-unmount 1893 1980 5000
Toggle mount 796 828 5000
buttonNative mount 141 137 5000

@Hotell
Copy link
Contributor

Hotell commented Mar 10, 2022

thanks for your contribution !

To provide some additional context:

  • we have this rule setup but only for external re-exports @rnx-kit/no-export-all, as that's the only issue we identified to mitigate duplicates and tree shake-ability during bundling. Can you pls provide repro that showcases/proves your statement ?
    • also you're referring to import starts (import *) but you're changing re-exports
  • not sure you are allowed to use type in v8 packages because old TS support ( cc @ecraig12345 )

Some bundlers, such as esbuild, are not able to tree-shake nested
`export *` statements. Fixed them using the `no-export-all` ESLint rule.
@tido64 tido64 force-pushed the tido/enable-no-export-all-utilities branch from 544bbed to 4270bdc Compare March 10, 2022 13:26
@tido64
Copy link
Member Author

tido64 commented Mar 10, 2022

  • we have this rule setup but only for external re-exports @rnx-kit/no-export-all, as that's the only issue we identified to mitigate duplicates and tree shake-ability during bundling. Can you pls provide repro that showcases/proves your statement ?

Sorry, I have a repro in an internal repository. If you hit me up on Teams, I can provide you more context.

  • also you're referring to import starts (import *) but you're changing re-exports

Sorry, that's a typo. It should be fixed now.

  • not sure you are allowed to use type in v8 packages because old TS support ( cc @ecraig12345 )

There are currently 2045 instances of import type in the repo. 😄

@dzearing
Copy link
Member

@Hotell The type comment - I added them a while ago as they've been in typescript since 3.8. Inline type imports though are new, but I don't see them here.

@dzearing
Copy link
Member

dzearing commented Mar 10, 2022

Pending @Hotell approval here. :)

@Hotell: I regret not figuring out a way to remove all export stars tbh. Even though it's more work to maintain, it would also help in resolving even more edge cases. I found this one:

a.js:

export { createTheme } from 'libA';

b.js:

export { createTheme } from 'libB';

index.js:

export * from './a';
export * from './b';

In this case, createTheme is still coming from 2 separate libraries (even though we banned export * from external libraries, it's transitively exported here.) I don't believe typescript will ever complain about this scenario, even if they resolve to separate impls. But let's say both versions map to the same impl within the repo. Then outside of the repo due to node module resolution, you can STILL resolve to different versions, leading to an ambiguous or breaking situation.

Banning all export * would remove this edge case because the index.js file would need to explicitly choose which createTheme to take as the source of truth.

Tommy suggested having a mode in the lint rule to enforce them in just index files. That would help this scenario as well.

@ecraig12345
Copy link
Member

  • not sure you are allowed to use type in v8 packages because old TS support

import type is fine now since our minbar for v8 is 3.9 (it was only a problem in v7 where our minbar was 3.5).

@ecraig12345
Copy link
Member

One random interesting thing about this PR: having the API report file made it really easy to verify that the actual exports stayed the same.

@Hotell
Copy link
Contributor

Hotell commented Mar 11, 2022

thanks for additional context @dzearing !

based on your new findings, IMO this should be only needed for barrel files that are part of public API -> thus src/index.ts, correct ?

Q: not sure if that lint rule supports such a feature or we need to add additional churn via overrides.
A: it doesn't support. we'll need to use overrides. Created PR for all v9 https://github.com/microsoft/fluentui/pull/22073/files

Last but not least this should be applied across whole monorepo. I'll follow up after we resolve that PR I linked

@Hotell
Copy link
Contributor

Hotell commented Mar 11, 2022

@tido64

Sorry, I have a repro in an internal repository. If you hit me up on Teams, I can provide you more context.

for future I'd suggest to leverage stackblitz for any kind of isolated repros so anyone is able to troubleshoot.

@Hotell
Copy link
Contributor

Hotell commented Mar 14, 2022

merged, thx for your contribution @tido64 !

@tido64 tido64 deleted the tido/enable-no-export-all-utilities branch March 17, 2022 12:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants