Skip to content

feat: Add unified fluentui-react-native mono-package with subpath exports and migration codemod#4066

Draft
Saadnajmi wants to merge 7 commits intomicrosoft:mainfrom
Saadnajmi:feat/unified-mono-package
Draft

feat: Add unified fluentui-react-native mono-package with subpath exports and migration codemod#4066
Saadnajmi wants to merge 7 commits intomicrosoft:mainfrom
Saadnajmi:feat/unified-mono-package

Conversation

@Saadnajmi
Copy link
Collaborator

Summary

Introduces a new unified mono-package (fluentui-react-native) that re-exports every publishable package in the monorepo via subpath exports. Consumers only need a single dependency and a single version number.

Also includes a jscodeshift codemod that automates migration of both source imports and package.json dependencies, and demonstrates the migration on tester-core (155 files).

Motivation

Today, consumers must track ~70 individual @fluentui-react-native/* packages with independent version numbers. This makes upgrades painful and package.json files unwieldy. A single fluentui-react-native package with subpath imports gives consumers one dependency to manage while preserving tree-shaking.

What's included

1. Mono-package (packages/libraries/fluentui-react-native/)

  • 76 subpath exports (70 individual + 6 category barrels) — all resolve to TypeScript source files in src/
  • No build step — exports point directly to .ts re-export files; consumers' bundlers (Metro, Webpack) compile them as part of the app build
  • ESM-only ("type": "module", "sideEffects": false) for optimal tree-shaking
  • Auto-generatedupdate-exports.mts discovers all publishable packages, generates src/ files, and updates package.json exports/dependencies
  • CI-enforcedcheck-exports task in lage buildci fails if any publishable package is missing

Usage:

// Individual subpaths (recommended — one package per import)
import { Button } from 'fluentui-react-native/button';
import { ThemeProvider } from 'fluentui-react-native/theme';

// Category barrels (convenience — all packages in a group)
import { Button, Avatar } from 'fluentui-react-native/components';
import { ThemeProvider } from 'fluentui-react-native/core';

2. Migration codemod (packages/codemods/)

A jscodeshift transform + package.json migration tool:

  • Source migration: rewrites @fluentui-react-native/*, @fluentui/react-native, and @uifabricshared/* imports to fluentui-react-native/<subpath>
  • Barrel decomposition: expands import { Button, Theme } from '@fluentui/react-native' into per-symbol subpath imports
  • package.json migration: removes individual scoped dependencies, adds single fluentui-react-native dependency
  • Supports both import and require() syntax
yarn migrate-to-mono-package --path src/

3. tester-core migration (demonstration)

  • Migrated 155 source files from individual @fluentui-react-native/* imports to fluentui-react-native/* subpaths
  • Removed 61 individual dependencies from package.json, replaced with single fluentui-react-native
  • Converted tester-core to ESM ("type": "module") since the mono-package is ESM-only

4. Build system changes

  • lage.config.mjs: Added check-exports task to the buildci pipeline
  • lintPackage.ts: Skip "." export validation for subpath-only packages; skip default entry enforcement when source file doesn't exist
  • buildConfig.ts: Suppress CJS build for packages without a main field (not just type: module packages)
  • End apps (fluent-tester, win32, win32-81): Use module: esnext / moduleResolution: bundler to support ESM tester-core dependency; removed unnecessary build-cjs

Design decisions

Decision Rationale
Unscoped package name (fluentui-react-native) Short imports: fluentui-react-native/button vs @fluentui-react-native/mono/button
Subpath exports only (no root barrel) Prevents accidental import of everything; forces tree-shakeable imports
Source .ts exports (no lib/) Standard for React Native packages; avoids build step; bundlers compile directly
Category barrels with @ts-nocheck Aggregating overlapping packages causes TS2308 duplicate export errors; individual subpaths are unaffected
Auto-generation script Single source of truth; CI prevents drift; adding a new package only requires running yarn update-exports

Testing

  • yarn lage buildci passes (build, lint, format, depcheck, lint-package, check-exports, check-publishing)
  • tester-core builds and type-checks with migrated imports
  • update-exports.mts --check validates all src/ files and package.json fields

Migration guide

Existing consumers can migrate incrementally:

  1. yarn add fluentui-react-native
  2. Run the codemod: yarn migrate-to-mono-package --path src/
  3. Verify the build

The individual @fluentui-react-native/* packages continue to be published — this is additive, not breaking.

- New jscodeshift transform: migrate-to-mono-package
- Rewrites @fluentui-react-native/* and @uifabricshared/* to fluentui-react-native/*
- Decomposes @fluentui/react-native barrel into per-package subpath imports
- Replaces yargs with Node built-in parseArgs
- Includes test fixtures covering scoped, barrel, require(), and skip cases
@changeset-bot
Copy link

changeset-bot bot commented Mar 12, 2026

⚠️ No Changeset found

Latest commit: ccb9487

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@Saadnajmi Saadnajmi marked this pull request as draft March 12, 2026 21:07
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.

1 participant