Skip to content

feat(atomic-loader): support @fluentui/react-brand-icons#1096

Closed
micahgodbolt wants to merge 1 commit into
microsoft:mainfrom
micahgodbolt:feat/brand-icons-atomic-loader
Closed

feat(atomic-loader): support @fluentui/react-brand-icons#1096
micahgodbolt wants to merge 1 commit into
microsoft:mainfrom
micahgodbolt:feat/brand-icons-atomic-loader

Conversation

@micahgodbolt

Copy link
Copy Markdown
Member

Problem

@fluentui/react-brand-icons (published from microsoftdesign/Design System/_git/fluent-product-icons) already ships atomic subpath exports (./svg/*), but the @fluentui/react-icons-atomic-webpack-loader is hardcoded to only transform @fluentui/react-icons barrel imports.

This forces consumers to either:

  • Use barrel imports and pull the entire 340-icon bundle
  • Manually rewrite every import to atomic paths
  • Avoid the package entirely (which is what m365-copilot-nav in 1JS does today)

Key Insight: The Packages Are Nearly Identical

Feature react-icons react-brand-icons
Icon suffixes Regular, Filled, Light, Color Regular, Filled, Color
Atom path pattern ./svg/<kebab-name> ./svg/<kebab-name>
Utility exports wrapIcon, bundleIcon, createFluentIcon, useIconState Same
sideEffects false false
Suffix regex match ✅ (subset — same regex works)

The existing ICON_SUFFIX_REGEX (/(\d*)?(Regular|Filled|Light|Color)$/) already matches brand icon names with zero changes.

Proposed Solution

Extend the existing loader (not a new package) with a modules option:

src/transform.ts

Replace hardcoded MODULE_NAME = '@fluentui/react-icons' with a configurable Set of module names. Pass the matched module name through to getAtomicImportPath so paths resolve correctly per-package.

src/index.ts

Add modules option (default: both packages). Update fast-path string check to test against all configured modules.

API (backward compatible)

{
  loader: '@fluentui/react-icons-atomic-webpack-loader',
  options: {
    // Default: ['@fluentui/react-icons', '@fluentui/react-brand-icons']
    // Opt out of brand-icons:
    modules: ['@fluentui/react-icons'],
  },
}

Before / After

// Input
import { AddFilled } from '@fluentui/react-icons';
import { WordColor } from '@fluentui/react-brand-icons';

// Output (after loader)
import { AddFilled } from '@fluentui/react-icons/svg/add';
import { WordColor } from '@fluentui/react-brand-icons/svg/word';

Implementation

I have a working implementation with all 25 tests passing (17 existing + 8 new). The diff is ~130 lines across 4 files:

  • src/transform.ts — parameterize module name
  • src/index.ts — add modules option, update fast-path
  • test/transform.test.ts — 8 new tests
  • README.md — document brand-icons + modules option

Happy to submit a PR if someone can point me to the right process (my EMU account can't fork this repo). I can share a git format-patch if helpful.

Motivation

1JS consumers (M365 Copilot, etc.) need brand icons but can't adopt them without atomic import support — the bundle cost of the barrel import is prohibitive.

Extend the atomic webpack loader to transform barrel imports from
@fluentui/react-brand-icons in addition to @fluentui/react-icons.

Both packages use the same atomic subpath export pattern (./svg/*),
the same icon suffix convention (Regular, Filled, Color), and the
same utility exports (bundleIcon, createFluentIcon, etc.).

Changes:
- Parameterize the hardcoded MODULE_NAME to support multiple packages
- Add 'modules' option to configure which packages are transformed
- Default to both @fluentui/react-icons and @fluentui/react-brand-icons
- Add tests for brand icon imports, re-exports, mixed files, and opt-out
- Update README with brand-icons examples and modules option docs

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@micahgodbolt micahgodbolt requested a review from a team as a code owner June 8, 2026 19:31
@dmytrokirpa dmytrokirpa requested review from Hotell and mainframev June 9, 2026 12:03

@Hotell Hotell left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

needs different design

function getAtomicImportPath(importName: string, iconVariant: 'svg' | 'fonts' | 'svg-sprite', moduleName: string): string {
if (importName === 'useIconContext' || importName === 'IconDirectionContextProvider') {
return '@fluentui/react-icons/providers';
return `${moduleName}/providers`;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

this is wrong, product icons has no provider, no utils export map

Image

iconVariant: 'svg' | 'fonts' | 'svg-sprite';
path: string;
/** Icon package names to transform. Defaults to react-icons and react-brand-icons. */
modules?: string[];

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

this is bad design, product icons don't and wont support all iconVariants, so this api needs either better more generic design or handle the logic properly internally

@Hotell

Hotell commented Jun 10, 2026

Copy link
Copy Markdown
Collaborator

also FYI the chunk is tree shakeable, the atomizer purpose is primarily for 2 things:

  • preventing dupes with chunks and lazy loading scenarios
  • bundler speed processing / dev loop

@Hotell

Hotell commented Jun 16, 2026

Copy link
Copy Markdown
Collaborator

this is replaced #1113 feel free to close @micahgodbolt

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.

2 participants