# Reducing rebuilds for converged components
## Problem description
The objective of this project is to improve the authoring process for converged components and their dependencies so that they can be more easily consumed.
Currently authoring converged components and their dependencies can be a pain. We can illustrate this problem with a simple example inspired by react-button:
Button.tsx
```typescript
...
import { useInlineTokens } from '@fluentui/react-theme-provider';
export const Button = React.forwardRef<HTMLElement, ButtonProps>((props, ref) => {
...
useInlineToken(state, '--button');
...
return (...);
});
```
useInlineTokens.ts
```typescript
export const useInlineTokens = (draftState: { style?: React.CSSProperties; tokens?: TokenSetType }, prefix: string) => {
...
};
```
While working on `Button.tsx` We export a new constant we want to use from the file.
It also turns out that in the latest merge someone else has made a modification by removing the `prefix` parameter. Any kind of git induced changes will be an issue here, even switching branches where code for packages can be different. This can cause significant headaches while trying to author different parts of the repo during the day
useInlineTokens.ts
```typescript
- export const useInlineTokens = (draftState: { style?: React.CSSProperties; tokens?: TokenSetType }, prefix: string) => {
+ export const useInlineTokens = (draftState: { style?: React.CSSProperties; tokens?: TokenSetType }) => {
...
};
+ export const FLUENT_ROX = 'yup';
```
The above change will not be reflected in the local `react-button` package. We now have several issues:
* IDE will scream if we try to import our `FLUENT_ROX` constant stating that it doesn't exist
* Building the local `rect-button` without building `react-theme-provider` will fail because `FLUENT_ROX` doesn't exist
When we rebuild `react-theme-provider` we'll get the following surprises:
* IDE will scream that we are using `useInlineTokens` incorrectly
* If you try to inspect `useInlineTokens` you'll do to a type declaration file in a lib folder
* Building the local `react-button` will fail for the same reason
* If the build will fail -> most likely tests will start failing too
The above example only illustrates this problem `for a direct dependency` This will get more frustrating as we go deeper into nested dependencies. Error messages tend to only focus on what is wrong with direct dependencies, we will have to keep digging as we go on.
## Appetite
Make the code authoring process easier for all contributors to the fluent repo, without lengthy investigations into why builds are breaking or brute forcing the problem by running a full rebuild (very time consuming). We would like the use and authoring of converged components to be as simple as possible to promote higher productivity. Building dependencies during development or during git rebases can be very tedious and will not be sustainable if the repo grows larger in the future.
Lay the groundwork for common tsconfig and directory structures for both Fabric and N* teams, which will make convergence easier and make the repo look like one project.
## Solution
### Aliases and ts project references
This is what is more or less setup in the current N* part of the repository. Each project configures its tsconfig correctly project references so that we have good IDE support for imports. This will 'trick' the IDE to detecting latest code changes to enable intellisense on imports.
However in reality we still rely on the build output of each package, but this can be solved with various aliases.
* jest can use `moduleNameMapper` to map directly to sources
* webpack can use aliases to map directly to sources
Therefore to run tests and have watch functionality for docs during deployment we'll have live changes to imports reflected. If we want to run an actual build, then imports will need to be rebuilt in each of their respective packages.
We can also go a step further and point projects' main directly to src and change this during the prepublish phase which should avoid aliases and increase the performance of our tests which currently suffer perf problems resolving such a large amount of aliases.
The advantage here is that projects are still free to use either babel or tsc to compile their code.
Pros:
- IDE support for imports without rebuilding
- Flexibility of using babel with plugins or tsc
- babel builds faster than tsc
Cons:
- Building will still require all dependencies to be rebuilt if there are changes
- Aliases can seem like magic if you don't know where to look for them
- Issues with tsc/babel incompatibilities might need to be resolved later (isolated-modules/const enums)
## Risks
There could be conflicts with what fabric currently have setup, so communication is required there to find a final solution that satisfies everyone. The idea is to try to remove as much differences as possible between fabric and n*.
References to `office-ui-fabric-react` seem to be weird, since it is a package that is a re-export of different fabric packages currently in the repo. Also can't really find many references about how that is done. Will need to speak more with fabric to understand how that would fit in with the above proposed solutions
A previous attempt has been made to set project references with some challenges, will need to understand those issues clearly and try not to repeat them
## Out of scope
### Babel/tsc compat
We will not be trying to fix compatibility between babel/tsc builds and configs. The idea here is that authoring with monorepo dependencies becomes easier. However the hope is that by configuring references and projects uniformly across projects, it will become easier to consolidate in the future.
### Build convergence
It is possible to go further with project references and use `tsc -b -w` to remove the need for aliases. ts-loader and fork-tschecker both support typescript project references. However, this would mean that tests will need to start using package imports instead of the relative path. This kind of bulld convergence could be quite powerful since we would get first class TS support for incremental package builds
Likewise there are also the benefits of doing a build convergence through Babel and this can be a bit of a lengthy debate and not entirely necessary to solve the problems outlined in this proposal.