# Fluent UI merge overview Today we have 2 separate libraries that have merged into one. Here is how we plan to merge: ## Overview * Both code bases are merging in one repo (March 2020) * Fabric becomes Fluent UI current (v7) (published under multiple names) * Existing `fluent-ui-react` code becomes Fluent UI v0 * Break "monolithic" libraries into smaller packages (e.g. react-avatar) * Stage updates in "next" packages. (e.g. react-avatar-next). * Push non-breaking changes into current to make transition easier for customers. (what React does) * Iteratively "graduate" next packages to current, which meet release criteria, adhering to deprecation policy. (See below) * Communicate graduations: what, when, why, and how on a regular rhythm. ## What happens to Fabric? Code originating from "Fabric" will become the "Fluent current" code (e.g. fluent-ui-react@7.x.x.) That is, this is our current production code that partners rely on. We will still alias publish as `office-ui-fabric-react@7.x.x` to avoid breaking partners. Our promise to customers for current code: - [x] We will not require you to change anything - [x] We will not break API contracts - [x] We will follow semantic versioning - [x] We will generally avoid changing DOM shape, styling, or behaviors unless the changes address serious issues. We also promise these for all code (current/next): - [x] We will continue to prioritize triaging and fixing current bugs, reviewing PRs, and keeping the system flowing. - [x] We will continue to make improvements and changes that are non breaking. Our current code represents code that our partners can rely on. We have basic requirements for this: - [x] Must have **tests** (functional, snapshot, visual regression, bundle, and runtime performance tests). - [x] Library exports **locked down** with API extractor. - [x] Bundle size **at par or better** - [x] Runtime perf **at par or better** - [x] **Changes have clear guidance**: what change, why was the change made, how do I deal with it, and when will I need to worry. - [x] **Visuals don't regress** without merit. Shifts in pixels make for unpredictable product experiences. FAQ: **Will our current packages still be published?** Yes. We *will* split much of the code into smaller packages however, but this should not be a contract change except for partners which use deep unsupported imports. **Will our NPM scope change?** Yes, to `@fluentui`. Existing `@uifabric` packages will continue to publish as is, but may be split into smaller `@fluentui` packages, so that we can ween off the old naming over time. ## What happens to code in "fluent-ui-react"? This code is being iterated to become "Fluent next" code. That is, this code will be incubating without the strict requirements, to stage major or breaking improvements on current bits over time. Improvements will come in this form: * Naming changes which refine taxonomies * Prop names to create cleaner API surfaces * Slots and slot props standardized across the components * Breaking larger components into smaller ones * Component rewrites which may be destabilizing, change behaviors or DOM shapes ## How will this work? 1. We will break current and next into smaller subpackages. For example: "@fluentui/react-avatar" will represent current Avatar code. "@fluentui/react-avatar-next" will represent next. The code will live in the same repo, side by side. 2. When the -next version has met release criteria, we will stage a major release upgrading current. There will still be suite packages to target the specific builds: `fluent-ui-react` `office-ui-fabric-react` `fluent-ui-react-next` ### What are the release criteria? 1. It must be at least as fast as the current release. 2. It must be at least as small as the current bundle. 3. Similar to React deprecation policy: For dropping behaviors or functionality, there must be at least one release which allows the partner to stop using the deprecated feature or functionality. 4. Like the React library itself, we should support both old a 5. Any features the current release supported that the next one does not must have clear documented reasonings for customers. Breaking something for the sake of breaking is not a reason to them. ### What is the deprecation policy? Deprecations come in 2 forms: * There was an old way of doing things, switch to new way. (Customers can work with these.) * There was an old way, but it is being removed with no alternative. (Customers hate these.) Customers need a way to ween themselves off using dropped features. We need to follow the React model: introduce deprecations in the current build to make transitioning to next (where things get dropped) easier. #### Example 1: `PersonaCoin` should be renamed to `Avatar`. We can introduce a non breaking change right now to current to stage this rename by exporting old and new names. ```tsx /** * @deprecated Use Avatar instead. */ export const PersonaCoin = Avatar; ``` Prop name changes can also be staged. E.g. `imageUrl` is deprecated in favor of `image` slot prop. We can support old and new, and add a deprecation warning to old. In the `next` build, we remove old. ```tsx /** interface IAvatarProps { /** * @deprecated Use image slot to provide url or image props. */ imageUrl: string; } ``` #### Example 2: we want to drop the `styles` prop. This is used to inject styles into the component. We know this is a performance concern. If users can use alternatives in the current build, they can do incremental work to stage for upgrades. We must provide guidance (in current release) for them to migrate away to something else. Perhaps this is an opportunity to show `compose`: ```tsx // Instead of this: <Button styles={{ ... }} /> // This, if you need a full stylesheet: const BlueButton = compose(Button, { styles: { ... }}); <BlueButton ... /> // Or inline if you need a quick positioning tweak: <BlueButton style={{ ... }} /> // Or inline on a slot if you need a part to be tweaked: <BlueButton icon={{ style: { ... }}} /> ``` ## How do partners know when their code is wrong? Partners need a way to know that their code has deprecation usages. We should have announcement mails for upcoming deprecations. We have code utilities for these. ### Build errors via eslint When you add the `@deprecated` flag to your jsdoc comment for a Component or prop, eslint can give you warnings on usage. We need to test and have documentation on this approach. Recommend we work with Teams and ODSP on enabling eslint depreactions creating warnings in their builds, so that we are sure this can work. ### Console logging Not everyone will use eslint. We can also use console logging (in non production builds only) to warn about deprecations. ```tsx // Warn about deprecated props usage. warnDeprecations('ComponentName', props, { 'oldPropName': 'newPropName' }); ``` ### Strict mode The last idea (not implemented) we could adapt is like React; enable strict mode. In this mode, we throw instead of log. ## What about changes which don't require breaks? Any changes we're sure of that don't require breaks should be made in current. Examples: * New components * New features * Additional functionality * Deprecations * Performance improvements