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

chore: create new tsconfig.base with path aliases #16976

Merged
merged 4 commits into from Feb 23, 2021

Conversation

Hotell
Copy link
Contributor

@Hotell Hotell commented Feb 12, 2021

Pull request checklist

Description of changes

  • creates new base tsconfig
  • switches react-menu to TS path aliases
  • adds workaround to make current build work

Focus areas to test

(optional)

"skipLibCheck": true,
"typeRoots": ["../../node_modules/@types", "../../typings"],
"types": ["jest", "webpack-env", "custom-global"]
"types": ["jest", "custom-global"]
Copy link
Contributor Author

Choose a reason for hiding this comment

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

cleanup: webpack-env is already included in custom-globals

* > - This is a temporary workaround for current way of building packages.
* > - Without setting baseUrl we would get all aliased packages build within outDir
*/
function backportTsAliasedPackages(options: TscTaskOptions) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

workaround to make existing pipeline work without changes

@@ -0,0 +1,24 @@
{
"compilerOptions": {
"target": "ES2015",
Copy link
Contributor Author

Choose a reason for hiding this comment

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

we gonna use this also for node packages etc, particular packages should explicitly state their target (in future babel/esbuild will handle that automatically)

"compilerOptions": {
"baseUrl": ".",
"target": "ES5",
Copy link
Contributor Author

@Hotell Hotell Feb 12, 2021

Choose a reason for hiding this comment

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

TODO (create issue Martin): while we restrict to ES5 ECMA language features, because of global leaking types, we can use almost all ECMA lang features
-> it starts with conformance lib , which imports enzyme -> enzyme refs whole node types -> node types add ES2017 etc to the type check tree

#17101

This comment was marked as off-topic.

@Hotell Hotell changed the title Hotell/16889/ts aliases chore: create new tsconfig.base with path aliases Feb 12, 2021
@codesandbox-ci
Copy link

codesandbox-ci bot commented Feb 12, 2021

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 5ff03c4:

Sandbox Source
Fluent UI Button Configuration
codesandbox-react-template Configuration
codesandbox-react-northstar-template Configuration

@size-auditor
Copy link

size-auditor bot commented Feb 12, 2021

Asset size changes

⚠️ Insufficient baseline data to detect size changes

Unable to find bundle size details for Baseline commit: 9786d01

Possible causes

  • The baseline build 9786d01 is broken
  • The Size Auditor run for the baseline build 9786d01 was not triggered

Recommendations

  • Please merge your branch for this Pull request with the latest master build and commit your changes once again

@fabricteam
Copy link
Collaborator

fabricteam commented Feb 12, 2021

Perf Analysis

No significant results to display.

All results

Scenario Render type Master Ticks PR Ticks Iterations Status
Avatar mount 1195 1190 5000
BaseButton mount 969 973 5000
Breadcrumb mount 43899 43694 5000
ButtonNext mount 736 761 5000
Checkbox mount 1652 1651 5000
CheckboxBase mount 1379 1369 5000
ChoiceGroup mount 5104 5176 5000
ComboBox mount 1001 1081 1000
CommandBar mount 10312 10349 1000
ContextualMenu mount 6338 6377 1000
DefaultButton mount 1212 1225 5000
DetailsRow mount 3842 3868 5000
DetailsRowFast mount 3920 3874 5000
DetailsRowNoStyles mount 3732 3713 5000
Dialog mount 1579 1592 1000
DocumentCardTitle mount 1840 1846 1000
Dropdown mount 3537 3486 5000
FocusTrapZone mount 1897 1867 5000
FocusZone mount 1888 1875 5000
IconButton mount 1913 1928 5000
Label mount 366 361 5000
Layer mount 1887 1909 5000
Link mount 514 504 5000
MakeStyles mount 2040 2043 50000
MenuButton mount 1607 1577 5000
MessageBar mount 2054 2052 5000
Nav mount 3420 3448 1000
OverflowSet mount 1082 1084 5000
Panel mount 1512 1509 1000
Persona mount 884 881 1000
Pivot mount 1482 1470 1000
PrimaryButton mount 1353 1382 5000
Rating mount 8129 8212 5000
SearchBox mount 1432 1456 5000
Shimmer mount 2762 2829 5000
Slider mount 2031 2065 5000
SpinButton mount 5372 5331 5000
Spinner mount 415 444 5000
SplitButton mount 3381 3390 5000
Stack mount 537 545 5000
StackWithIntrinsicChildren mount 1699 1683 5000
StackWithTextChildren mount 4989 5021 5000
SwatchColorPicker mount 10890 10847 5000
Tabs mount 1478 1497 1000
TagPicker mount 2916 3014 5000
TeachingBubble mount 12056 12064 5000
Text mount 457 426 5000
TextField mount 1494 1550 5000
ThemeProvider mount 1201 1218 5000
ThemeProvider virtual-rerender 615 615 5000
ThemeProviderNext mount 1982 2017 5000
Toggle mount 838 842 5000
buttonNative mount 122 112 5000

Perf Analysis (Fluent)

Perf comparison
Status Scenario Fluent TPI Fabric TPI Ratio Iterations Ticks
🦄 Avatar.Fluent 0.2 0.51 0.39:1 2000 392
🦄 Button.Fluent 0.13 0.22 0.59:1 5000 660
🔧 Checkbox.Fluent 0.68 0.4 1.7:1 1000 683
🎯 Dialog.Fluent 0.17 0.23 0.74:1 5000 862
🔧 Dropdown.Fluent 3.26 0.44 7.41:1 1000 3264
🔧 Icon.Fluent 0.16 0.07 2.29:1 5000 776
🦄 Image.Fluent 0.09 0.14 0.64:1 5000 454
🔧 Slider.Fluent 1.7 0.5 3.4:1 1000 1698
🔧 Text.Fluent 0.08 0.03 2.67:1 5000 415
🦄 Tooltip.Fluent 0.12 0.92 0.13:1 5000 618

🔧 Needs work     🎯 On target     🦄 Amazing

Perf tests with no regressions
Scenario Current PR Ticks Baseline Ticks Ratio
PortalMinimalPerf.default 192 175 1.1:1
ButtonSlotsPerf.default 674 623 1.08:1
ImageMinimalPerf.default 471 436 1.08:1
ChatMinimalPerf.default 743 695 1.07:1
RadioGroupMinimalPerf.default 533 500 1.07:1
AlertMinimalPerf.default 356 336 1.06:1
ButtonMinimalPerf.default 216 204 1.06:1
LabelMinimalPerf.default 517 488 1.06:1
ListCommonPerf.default 763 717 1.06:1
SkeletonMinimalPerf.default 457 432 1.06:1
Avatar.Fluent 392 369 1.06:1
AttachmentSlotsPerf.default 1349 1288 1.05:1
ChatDuplicateMessagesPerf.default 424 403 1.05:1
DropdownManyItemsPerf.default 839 801 1.05:1
StatusMinimalPerf.default 840 798 1.05:1
Icon.Fluent 776 741 1.05:1
FlexMinimalPerf.default 361 346 1.04:1
FormMinimalPerf.default 518 500 1.04:1
HeaderMinimalPerf.default 461 444 1.04:1
AttachmentMinimalPerf.default 202 196 1.03:1
CardMinimalPerf.default 654 636 1.03:1
PopupMinimalPerf.default 782 761 1.03:1
SegmentMinimalPerf.default 438 427 1.03:1
TableMinimalPerf.default 490 474 1.03:1
AvatarMinimalPerf.default 242 238 1.02:1
DialogMinimalPerf.default 883 868 1.02:1
MenuButtonMinimalPerf.default 1751 1724 1.02:1
ProviderMergeThemesPerf.default 1677 1642 1.02:1
ProviderMinimalPerf.default 1064 1048 1.02:1
TableManyItemsPerf.default 2340 2302 1.02:1
TextMinimalPerf.default 427 419 1.02:1
TreeMinimalPerf.default 896 878 1.02:1
Button.Fluent 660 650 1.02:1
Text.Fluent 415 407 1.02:1
Tooltip.Fluent 618 608 1.02:1
AnimationMinimalPerf.default 478 471 1.01:1
CarouselMinimalPerf.default 566 561 1.01:1
HeaderSlotsPerf.default 906 900 1.01:1
SliderMinimalPerf.default 1708 1694 1.01:1
SplitButtonMinimalPerf.default 4161 4130 1.01:1
TextAreaMinimalPerf.default 570 565 1.01:1
CustomToolbarPrototype.default 4004 3976 1.01:1
TooltipMinimalPerf.default 916 910 1.01:1
TreeWith60ListItems.default 208 206 1.01:1
Checkbox.Fluent 683 675 1.01:1
ButtonOverridesMissPerf.default 1823 1827 1:1
ButtonUseCssPerf.default 902 906 1:1
ButtonUseCssNestingPerf.default 1201 1202 1:1
CheckboxMinimalPerf.default 3038 3053 1:1
DatepickerMinimalPerf.default 50966 51094 1:1
DropdownMinimalPerf.default 3221 3211 1:1
ListNestedPerf.default 649 649 1:1
LoaderMinimalPerf.default 793 791 1:1
MenuMinimalPerf.default 982 984 1:1
ReactionMinimalPerf.default 469 470 1:1
ToolbarMinimalPerf.default 1095 1095 1:1
Dropdown.Fluent 3264 3274 1:1
ChatWithPopoverPerf.default 508 512 0.99:1
EmbedMinimalPerf.default 4567 4597 0.99:1
InputMinimalPerf.default 1383 1398 0.99:1
ListWith60ListItems.default 703 709 0.99:1
RefMinimalPerf.default 263 266 0.99:1
IconMinimalPerf.default 750 760 0.99:1
VideoMinimalPerf.default 722 732 0.99:1
Dialog.Fluent 862 870 0.99:1
Slider.Fluent 1698 1717 0.99:1
BoxMinimalPerf.default 418 425 0.98:1
DividerMinimalPerf.default 421 429 0.98:1
ItemLayoutMinimalPerf.default 1386 1408 0.98:1
LayoutMinimalPerf.default 467 476 0.98:1
AccordionMinimalPerf.default 179 184 0.97:1
GridMinimalPerf.default 401 419 0.96:1
ListMinimalPerf.default 576 598 0.96:1
Image.Fluent 454 479 0.95:1
RosterPerf.default 1263 1337 0.94:1

@Hotell Hotell marked this pull request as ready for review February 16, 2021 17:56
packages/react-menu/tsconfig.json Show resolved Hide resolved
tsconfig.base.json Outdated Show resolved Hide resolved
"@fluentui/react-menu": ["packages/react-menu/src/index.ts"]
}
},
"exclude": ["node_modules"]
Copy link
Member

Choose a reason for hiding this comment

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

Just curious, why is it necessary to explicitly do this?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

do what? provide exclude ?

  • it's not necessary, but for consistency and smaller git diffs I added it so it can be easily extended by other folders/globs (which we may introduce)

Copy link
Member

Choose a reason for hiding this comment

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

Yes the comment was supposed to be specifically on the exclude line. I was just surprised to see this since our configs haven't needed to explicitly exclude node_modules in the past.

packages/react-menu/tsconfig.json Show resolved Hide resolved
Comment on lines 10 to 11
"importHelpers": true,
"noUnusedLocals": true,
Copy link
Member

Choose a reason for hiding this comment

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

These should probably be in the defaults too, or at least noUnusedLocals should (it's not included by default with strict)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

from my experience noUnusedLocals is anti pattern/distracting churn to devs

  1. to be consistent this should be handled by eslint (TS is used for type checking for linting)
  2. unused code will be removed by minifier
  3. feedback from most of devs I worked in my entire carer was quite consistent: getting your app builds fail during dev just because you have some unused stuff is extremely distracting.

Copy link
Member

Choose a reason for hiding this comment

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

Hmm switching to enforcement with lint instead of TS seems reasonable. If we're going to make that change we should probably have an issue to track it. Though until that's implemented it might still be worth having noUnusedLocals in the default config.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If we're going to make that change we should probably have an issue to track it.

I was thinking this should be rather an RFC from point of DX change , than an issue.

Comment on lines 10 to 11
"forceConsistentCasingInFileNames": true,
"esModuleInterop": true,
Copy link
Member

Choose a reason for hiding this comment

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

I don't think this should be included in the defaults since it can cause problems downstream if not all consumers are also using it. IIRC @layershifter may have more background here.

Copy link
Member

Choose a reason for hiding this comment

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

As I remember it will require esModuleInterop: true on customer's side, too. Not all our customers have it enabled.

I failed to find a PR that have been done a long time ago, but at least a commit is there (microsoft/fluent-ui-react@75c139d).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I failed to find a PR that have been done a long time ago, but at least a commit is there (microsoft/fluent-ui-react@75c139d).

unfortunately that's not really helpful, no reasoning etc :)


Overall I'm not aware of any implications to customers nor about a requirement to have this enabled as well in consumers setup.

esModuleInterop helps to consume non es2015 module code with JS module syntax and normalizes ambient definitions consumption. That's it (no changes to export declaration emit for consumers, nor from runtime perspective). Unless you can provide explicit issue I'm gonna keep it as is. thx

Copy link
Member

Choose a reason for hiding this comment

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

I created a sample project, https://github.com/layershifter/tsc-test

Where:

  • host is an application that has esModuleInterop: true and builds type definitions
  • consumer is an application that has esModuleInterop: false (i.e. default value) and consumes host

To run it:

  • clone
  • yarn
  • yarn build

You will a build failure:

$ tsc
../host/dist/index.d.ts:1:8 - error TS1259: Module '"C:/Users/olfedias/WebstormProjects/tsc-test/node_modules/@types/react/index"' can only be default-imported using the 'esModuleInterop' flag

1 import React from 'react';
         ~~~~~

  ../../node_modules/@types/react/index.d.ts:69:1
    69 export = React;
       ~~~~~~~~~~~~~~~
    This module is declared with using 'export =', and can only be used with a default import when using the 'esModuleInterop' flag.

skipLibCheck: true can workaround it, but it also defaults to false. If we will enable esModuleInterop, produced artifacts cannot be consumed by customers with default TypeScript configs.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for digging into it. I forgot about this completely (I guess sideffect for using skip lib check for couple of years everywhere)

I run into that in our codebase quite recently as well 🗡️ 74f5de4 )

This leads us back to fundamental question: What are requirements for fluent convergence regarding ambient declarations output ?

All in all this feels like right change not just to us but for every customer.

Why?

  • skipLibCheck is recommended to be set to true in official docs (it's not true by default to not introduce breaking changes, which are introduced anyway even in feature bumps)
  • if customers enable this setting they will get type checking speed boost "for free"

Copy link
Member

Choose a reason for hiding this comment

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

IMO, our packages should work with any TS config including default options as consumers can have different motivation for their compilerOptions. For example, esModuleInterop is not enabled in Teams, this change will require them either to enable skipLibCheck everywhere (they might not want to do this everywhere) or esModuleInterop.


Personally I also don't see any value from enabling esModuleInterop (for components' packages) as in general we should not use CommonJS dependencies (they are impacting tree-shaking). We have React's packages as CommonJS dependencies, but they are going to have ESM builds (facebook/react#11503) and star imports (import * as React) are recommended currently anyway:

The default imports will keep working in React 17, but in the longer term we encourage moving away from them.
https://ru.reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html#removing-unused-react-imports

Copy link
Contributor Author

@Hotell Hotell Feb 18, 2021

Choose a reason for hiding this comment

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

IMO, our packages should work with any TS config

This is way too ambitious statement :) do we support moduleResolution: "classic" etc ? ...
Consumer of a package shouldn't care nor be limited by library internal tsconfig used.

require them either to enable skipLibCheck everywhere

Thats good for them (see my previous comment), TS exec speed benefits.

as in general we should not use CommonJS dependencies

I agree, although esModuleInterop won't help you with that much :) we'd need special lint rule or even better explicit deps validator

(import * as React) are recommended currently anyway:

It's not recommended way rather than "valid way that will not get replaced when running codemod". I already touched this point that we should rather use explicit named imports. anyways this is out off topic in terms of this PR.

Copy link
Contributor Author

@Hotell Hotell Feb 22, 2021

Choose a reason for hiding this comment

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

Based on discussion I removed esModuleInterop for this PR ->

as an action point:
can I ask you to create requirements doc for how we want author ambient type declaration @layershifter ? thx

"experimentalDecorators": true,
"importHelpers": true,
"noUnusedLocals": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"moduleResolution": "node",
"preserveConstEnums": true,
Copy link
Member

Choose a reason for hiding this comment

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

This should also be in the defaults. Not preserving const enums can cause problems for consumers in some cases.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

enums is another anti pattern and has serious implications in type safety. I'd like to avoid it completely in any convergence package. I understand it's still used (even in convergence) but as I already mentioned, base config is gonna be used everywhere, thus this makes no sense for js/tools.

see tip no 4 https://medium.com/@martin_hotell/10-typescript-pro-tips-patterns-with-or-without-react-5799488d6680

Copy link
Member

Choose a reason for hiding this comment

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

Possibly a valid point, but it's not something we've discussed specifically in this repo (aside from that we must preserve const enums due to compat issues with other build systems). If we want to ban enums, that should be done with a lint rule. Until then, we should have defaults that reasonably handle the last agreed upon state of things, which currently is that enums are allowed. preserveConstEnums is probably less important for tooling packages but not significantly harmful either.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll keep this config scoped per package for reasons I mentioned for now.

that should be done with a lint rule
cant agree more. we can/should iterate on linting approach etc in a follow up PR/RFC

scripts/tasks/ts.ts Show resolved Hide resolved
scripts/tasks/ts.ts Outdated Show resolved Hide resolved
@ecraig12345
Copy link
Member

Meant to say: this is looking good in general, just lots of little comments about specific options.

Copy link
Member

@layershifter layershifter left a comment

Choose a reason for hiding this comment

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

I don't have any comments to this PR 👍

@Hotell Hotell merged commit 96f5ff4 into microsoft:master Feb 23, 2021
joshualamusga1 pushed a commit to joshualamusga1/fluentui that referenced this pull request Mar 25, 2021
* chore: create new tsconfig base with path aliases
* chore(scripts): make current tsc just task to work with ts aliases
* chore(react-menu): switch to TS path aliases config
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

6 participants