Skip to content

feat(v9,headless): ship web packages ESM-first (type:module), drop node export condition#36327

Draft
Hotell wants to merge 24 commits into
microsoft:masterfrom
Hotell:feat/v9-valid-esm-drop-node-condition
Draft

feat(v9,headless): ship web packages ESM-first (type:module), drop node export condition#36327
Hotell wants to merge 24 commits into
microsoft:masterfrom
Hotell:feat/v9-valid-esm-drop-node-condition

Conversation

@Hotell

@Hotell Hotell commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Draft. Stacks on #36324 (module-condition) and supersedes it — this branch drops the node condition entirely. Open for early review / CI.

Summary

Migrates converged v9 web packages to ESM-first packaging so bare-Node SSR can import real ESM (and tree-shake), while require still gets CommonJS — no consumer config, no dual-package hazard for single-format graphs.

// package.json
"type": "module",
"main": "lib-commonjs/index.cjs",
"exports": { ".": {
  "import":  { "types": "./dist/index.d.ts",  "default": "./lib/index.js" },
  "require": { "types": "./dist/index.d.cts", "default": "./lib-commonjs/index.cjs" }
}}
  • lib/ ships valid native ESM (fully-specified .js via swc resolveFully).
  • lib-commonjs/ ships .cjs (required under type: module).
  • The node condition is dropped: bare-Node import → ESM, require → CJS; bundlers resolve import → ESM and tree-shake.
  • Per-condition types: require points at a rolled dist/*.d.cts so node16/nodenext CJS consumers are @arethetypeswrong-clean.

Why (vs the module condition in #36324)

The module condition only helps bundled SSR. This unlocks bare-Node externalized ESM (edge/workers, externalized deps) too, by making lib/ genuinely Node-loadable ESM. Latest Griffel (type: module, no node) already ships this exact shape, so the ecosystem is aligned.

What's automated (no per-package manual steps)

  • Build executor: auto-renames lib-commonjs/*.js*.cjs (+ rewrites relative require/maps) and copies dist/*.d.ts*.d.ctsgated on type: module (no-op otherwise).
  • Generators (migrate-converged-pkg, react-library): emit the ESM-first shape, .cjs dev configs, nested-types exports, and dist/*.d.cts in files.
  • Plugin: recognizes jest.config.cjs; adds an optional attw target (dependsOn: build, not in CI gates).

Scope / exclusions

  • Included: 84 converged v9 web packages (type: module).
  • Excluded (kept CommonJS): platform:node packages, storybook addons / preset.js, and just-scripts packages (charts — just.config.* is incompatible with type: module).

Validation

  • react-text dependency chain (bottom-up: tokens, keyboard-keys, react-utilities, react-theme, react-jsx-runtime, react-shared-contexts, react-text): bare-Node require ✅ and import ✅ both load; functionally real.
  • attw (react-text, react-utilities): 🟢 node16-from-CJS, 🟢 node16-from-ESM, 🟢 bundler, 🟢 node10 (exit 0).
  • vNext build sweep: "Successfully ran target build for 91 projects", exit 0.
  • workspace-plugin tests: 37 suites / 239 ✅.

Known limitation (follow-up, not a regression)

Bare-Node import of icon-dependent packages currently fails inside @fluentui/react-icons — an external package whose ESM (lib/index.js) uses extensionless imports (not valid bare-Node ESM). Bundled SSR, client, and require() are unaffected. Needs an upstream fully-specified-ESM fix in react-icons (or temporary exclusion of icon-dependent packages).

Reviewer notes

  • The all-or-nothing nature: bare-Node import only "lights up" once a package's entire transitive @fluentui/* closure is migrated (CJS export * barrels break Node's named-import interop). Throughout rollout, require + bundled never regress.
  • Change-file messages for type: module packages updated to describe the ESM-first state; excluded packages keep the module-condition message.

@github-actions

Copy link
Copy Markdown

Pull request demo site: URL

Comment thread .gitignore
@@ -153,3 +153,5 @@ gulp-cache
.cursor/rules/nx-rules.mdc

@github-actions github-actions Bot Jun 19, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🕵🏾‍♀️ visual changes to review in the Visual Change Report

vr-tests-react-components/Menu Converged - submenuIndicator slotted content 2 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/Menu Converged - submenuIndicator slotted content.default - RTL.submenus open.chromium.png 404 Changed
vr-tests-react-components/Menu Converged - submenuIndicator slotted content.default.submenus open.chromium.png 413 Changed
vr-tests-react-components/Positioning 2 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/Positioning.Positioning end.chromium.png 12 Changed
vr-tests-react-components/Positioning.Positioning end.updated 2 times.chromium.png 625 Changed
vr-tests-react-components/ProgressBar converged 3 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/ProgressBar converged.Indeterminate + thickness - Dark Mode.default.chromium.png 25 Changed
vr-tests-react-components/ProgressBar converged.Indeterminate + thickness.default.chromium.png 27 Changed
vr-tests-react-components/ProgressBar converged.Indeterminate + thickness - High Contrast.default.chromium.png 171 Changed
vr-tests-react-components/Skeleton converged 1 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/Skeleton converged.Opaque Skeleton with square - Dark Mode.default.chromium.png 3 Changed
vr-tests-react-components/TagPicker 1 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/TagPicker.disabled.disabled input hover.chromium.png 677 Changed
vr-tests-web-components/Avatar 1 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-web-components/Avatar. - Dark Mode.normal.chromium_1.png 298 Changed
vr-tests-web-components/MenuList 1 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-web-components/MenuList. - RTL.2nd selected.chromium_3.png 38816 Changed
vr-tests/Callout 4 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests/Callout.No callout width specified.default.chromium.png 2143 Changed
vr-tests/Callout.No beak.default.chromium.png 2192 Changed
vr-tests/Callout.Right top edge.default.chromium.png 1126 Changed
vr-tests/Callout.Top left edge.default.chromium.png 2212 Changed
vr-tests/react-charting-VerticalBarChart 1 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests/react-charting-VerticalBarChart.Basic - Secondary Y Axis.default.chromium.png 3 Changed

There were 1 duplicate changes discarded. Check the build logs for more information.

@github-actions

github-actions Bot commented Jun 29, 2026

Copy link
Copy Markdown

📊 Bundle size report

Package & Exports Baseline (minified/GZIP) PR Change
react-accordion
Accordion (including children components)
91.134 kB
28.705 kB
92.141 kB
29.057 kB
1.007 kB
352 B
react-avatar
Avatar
47.232 kB
14.856 kB
48.396 kB
15.296 kB
1.164 kB
440 B
react-avatar
AvatarGroup
16.259 kB
6.507 kB
17.265 kB
6.886 kB
1.006 kB
379 B
react-avatar
AvatarGroupItem
60.375 kB
18.757 kB
61.404 kB
19.158 kB
1.029 kB
401 B
react-badge
Badge
22.972 kB
7.347 kB
24.112 kB
7.775 kB
1.14 kB
428 B
react-badge
CounterBadge
23.691 kB
7.6 kB
24.832 kB
8.036 kB
1.141 kB
436 B
react-badge
PresenceBadge
22.943 kB
8.297 kB
24.084 kB
8.72 kB
1.141 kB
423 B
react-breadcrumb
@fluentui/react-breadcrumb - package
103.101 kB
28.806 kB
103.75 kB
29.06 kB
649 B
254 B
react-button
Button
32.682 kB
8.489 kB
33.822 kB
8.925 kB
1.14 kB
436 B
react-button
CompoundButton
39.56 kB
9.845 kB
40.698 kB
10.275 kB
1.138 kB
430 B
react-button
MenuButton
37.631 kB
9.888 kB
38.772 kB
10.311 kB
1.141 kB
423 B
react-button
SplitButton
46.582 kB
11.513 kB
47.767 kB
11.95 kB
1.185 kB
437 B
react-button
ToggleButton
52.348 kB
10.622 kB
53.488 kB
11.055 kB
1.14 kB
433 B
react-calendar-compat
Calendar Compat
142.457 kB
40.133 kB
143.595 kB
40.564 kB
1.138 kB
431 B
react-card
Card - All
93.047 kB
26.935 kB
94.213 kB
27.347 kB
1.166 kB
412 B
react-card
Card
85.651 kB
25.029 kB
86.793 kB
25.468 kB
1.142 kB
439 B
react-card
CardFooter
11.509 kB
4.597 kB
12.65 kB
5.026 kB
1.141 kB
429 B
react-card
CardHeader
14.046 kB
5.426 kB
15.205 kB
5.875 kB
1.159 kB
449 B
react-card
CardPreview
11.591 kB
4.711 kB
12.731 kB
5.138 kB
1.14 kB
427 B
react-charts
AreaChart
405.701 kB
126.547 kB
406.722 kB
126.928 kB
1.021 kB
381 B
react-charts
DeclarativeChart
756.891 kB
221.341 kB
757.91 kB
221.719 kB
1.019 kB
378 B
react-charts
DonutChart
316.025 kB
97.235 kB
317.045 kB
97.608 kB
1.02 kB
373 B
react-charts
FunnelChart
307.255 kB
94.015 kB
308.274 kB
94.39 kB
1.019 kB
375 B
react-charts
GanttChart
388.715 kB
120.982 kB
389.734 kB
121.357 kB
1.019 kB
375 B
react-charts
GaugeChart
315.327 kB
96.636 kB
316.347 kB
97.012 kB
1.02 kB
376 B
react-charts
GroupedVerticalBarChart
396.607 kB
123.702 kB
397.627 kB
124.088 kB
1.02 kB
386 B
react-charts
HeatMapChart
390.783 kB
122.019 kB
391.808 kB
122.421 kB
1.025 kB
402 B
react-charts
HorizontalBarChart
295.558 kB
89.766 kB
296.578 kB
90.119 kB
1.02 kB
353 B
react-charts
Legends
235.051 kB
70.488 kB
236.104 kB
70.858 kB
1.053 kB
370 B
react-charts
LineChart
417.018 kB
129.669 kB
418.038 kB
130.034 kB
1.02 kB
365 B
react-charts
PolarChart
344.549 kB
107.487 kB
345.569 kB
107.829 kB
1.02 kB
342 B
react-charts
SankeyChart
212.691 kB
68.111 kB
213.72 kB
68.49 kB
1.029 kB
379 B
react-charts
ScatterChart
396.309 kB
123.712 kB
397.328 kB
124.09 kB
1.019 kB
378 B
react-charts
VerticalBarChart
433.101 kB
128.668 kB
434.123 kB
129.013 kB
1.022 kB
345 B
react-charts
VerticalStackedBarChart
402.769 kB
125.143 kB
403.792 kB
125.513 kB
1.023 kB
370 B
react-checkbox
Checkbox
29.636 kB
10.543 kB
30.8 kB
10.919 kB
1.164 kB
376 B
react-color-picker
ColorArea
43.437 kB
15.726 kB
44.459 kB
16.106 kB
1.022 kB
380 B
react-color-picker
ColorPicker
15.001 kB
6.047 kB
16.007 kB
6.424 kB
1.006 kB
377 B
react-color-picker
ColorSlider
38.425 kB
14.208 kB
39.447 kB
14.588 kB
1.022 kB
380 B
react-combobox
Combobox (including child components)
138.327 kB
44.65 kB
139.351 kB
45.018 kB
1.024 kB
368 B
react-combobox
Dropdown (including child components)
138.089 kB
44.425 kB
139.119 kB
44.805 kB
1.03 kB
380 B
react-components
react-components: Button, FluentProvider & webLightTheme
66.33 kB
18.992 kB
67.495 kB
19.442 kB
1.165 kB
450 B
react-components
react-components: Accordion, Button, FluentProvider, Image, Menu, Popover
226.55 kB
68.025 kB
227.572 kB
68.382 kB
1.022 kB
357 B
react-components
react-components: FluentProvider & webLightTheme
39.537 kB
13.108 kB
40.701 kB
13.537 kB
1.164 kB
429 B
react-components
react-components: entire library
1.297 MB
325.698 kB
1.297 MB
325.982 kB
624 B
284 B
react-datepicker-compat
DatePicker Compat
216.522 kB
63.939 kB
217.686 kB
64.359 kB
1.164 kB
420 B
react-dialog
Dialog (including children components)
90.196 kB
27.88 kB
91.221 kB
28.272 kB
1.025 kB
392 B
react-divider
Divider
15.078 kB
5.401 kB
16.233 kB
5.849 kB
1.155 kB
448 B
react-field
Field
21.114 kB
7.884 kB
22.31 kB
8.312 kB
1.196 kB
428 B
react-headless-components-preview
react-headless-components-preview: entire library
248.878 kB
71.493 kB
249.421 kB
71.732 kB
543 B
239 B
react-image
Image
12.343 kB
5.014 kB
13.484 kB
5.445 kB
1.141 kB
431 B
react-input
Input
25.037 kB
8.172 kB
26.178 kB
8.603 kB
1.141 kB
431 B
react-jsx-runtime
JSX Runtime
1.495 kB
667 B
2.14 kB
950 B
645 B
283 B
react-label
Label
11.689 kB
4.733 kB
12.83 kB
5.166 kB
1.141 kB
433 B
react-link
Link
15.257 kB
6.039 kB
16.397 kB
6.468 kB
1.14 kB
429 B
react-list
List
74.656 kB
23.003 kB
75.662 kB
23.407 kB
1.006 kB
404 B
react-list
ListItem
98.17 kB
29.866 kB
99.199 kB
30.256 kB
1.029 kB
390 B
react-menu
Menu (including children components)
160.109 kB
50.719 kB
161.138 kB
51.119 kB
1.029 kB
400 B
react-menu
Menu (including selectable components)
163.287 kB
51.363 kB
164.316 kB
51.76 kB
1.029 kB
397 B
react-message-bar
MessageBar (all components)
22.296 kB
8.176 kB
25.273 kB
8.915 kB
2.977 kB
739 B
react-overflow
hooks only
9.123 kB
3.242 kB
10.272 kB
3.703 kB
1.149 kB
461 B
react-persona
Persona
54.187 kB
16.789 kB
55.351 kB
17.228 kB
1.164 kB
439 B
react-popover
Popover
125.737 kB
40.424 kB
126.763 kB
40.832 kB
1.026 kB
408 B
react-portal
Portal
12.729 kB
4.959 kB
13.861 kB
5.398 kB
1.132 kB
439 B
react-positioning
useSafeZoneArea
12.438 kB
4.992 kB
13.439 kB
5.378 kB
1.001 kB
386 B
react-progress
ProgressBar
19.12 kB
7.426 kB
20.266 kB
7.839 kB
1.146 kB
413 B
react-provider
FluentProvider
18.923 kB
7.271 kB
20.087 kB
7.7 kB
1.164 kB
429 B
react-radio
Radio
27.005 kB
8.717 kB
28.169 kB
9.161 kB
1.164 kB
444 B
react-radio
RadioGroup
12.768 kB
5.175 kB
13.932 kB
5.613 kB
1.164 kB
438 B
react-select
Select
24.883 kB
8.938 kB
26.023 kB
9.349 kB
1.14 kB
411 B
react-slider
Slider
32.258 kB
11.095 kB
33.424 kB
11.518 kB
1.166 kB
423 B
react-spinbutton
SpinButton
32.541 kB
10.59 kB
33.682 kB
11.015 kB
1.141 kB
425 B
react-spinner
Spinner
22.439 kB
7.341 kB
23.606 kB
7.779 kB
1.167 kB
438 B
react-swatch-picker
@fluentui/react-swatch-picker - package
92.334 kB
27.312 kB
92.844 kB
27.513 kB
510 B
201 B
react-switch
Switch
32.252 kB
10.168 kB
33.415 kB
10.576 kB
1.163 kB
408 B
react-table
DataGrid
147.112 kB
43.626 kB
148.156 kB
44.016 kB
1.044 kB
390 B
react-table
Table (Primitives only)
36.938 kB
12.299 kB
38.078 kB
12.686 kB
1.14 kB
387 B
react-table
Table as DataGrid
118.69 kB
33.329 kB
119.861 kB
33.753 kB
1.171 kB
424 B
react-table
Table (Selection only)
65.482 kB
18.596 kB
66.66 kB
18.96 kB
1.178 kB
364 B
react-table
Table (Sort only)
64.125 kB
18.206 kB
65.303 kB
18.576 kB
1.178 kB
370 B
react-tag-picker
@fluentui/react-tag-picker - package
174.362 kB
54.169 kB
174.898 kB
54.382 kB
536 B
213 B
react-tags
InteractionTag
12.464 kB
4.941 kB
13.622 kB
5.379 kB
1.158 kB
438 B
react-tags
Tag
28.391 kB
8.901 kB
29.548 kB
9.332 kB
1.157 kB
431 B
react-tags
TagGroup
69.747 kB
21.399 kB
70.897 kB
21.798 kB
1.15 kB
399 B
react-teaching-popover
TeachingPopover
100.85 kB
31.8 kB
101.864 kB
32.171 kB
1.014 kB
371 B
react-text
Text - Default
14.03 kB
5.454 kB
15.17 kB
5.88 kB
1.14 kB
426 B
react-text
Text - Wrappers
17.182 kB
5.763 kB
18.329 kB
6.195 kB
1.147 kB
432 B
react-textarea
Textarea
23.403 kB
8.444 kB
24.543 kB
8.88 kB
1.14 kB
436 B
react-timepicker-compat
TimePicker
141.074 kB
46.033 kB
142.112 kB
46.395 kB
1.038 kB
362 B
react-toast
Toast (including Toaster)
90.607 kB
28.141 kB
91.771 kB
28.544 kB
1.164 kB
403 B
react-tooltip
Tooltip
53.174 kB
18.859 kB
54.347 kB
19.277 kB
1.173 kB
418 B
react-tree
FlatTree
135.92 kB
40.451 kB
136.944 kB
40.826 kB
1.024 kB
375 B
react-tree
PersonaFlatTree
137.772 kB
40.964 kB
138.796 kB
41.338 kB
1.024 kB
374 B
react-tree
PersonaTree
133.833 kB
39.732 kB
134.857 kB
40.1 kB
1.024 kB
368 B
react-tree
Tree
131.987 kB
39.257 kB
133.011 kB
39.63 kB
1.024 kB
373 B
Unchanged fixtures
Package & Exports Size (minified/GZIP)
global-context
createContext
512 B
327 B
global-context
createContextSelector
533 B
335 B
keyboard-key
keyboard-key package
3.927 kB
1.99 kB
keyboard-keys
Multiple keyCodes
50 B
70 B
keyboard-keys
Multiple keys
87 B
94 B
keyboard-keys
Single key
44 B
64 B
keyboard-keys
Single keyCode
39 B
59 B
priority-overflow
createOverflowManager
5.376 kB
2.176 kB
react
ActivityItem
71.371 kB
23.398 kB
react
Announced
38.623 kB
13.324 kB
react
Autofill
15.571 kB
4.81 kB
react
Breadcrumb
200.956 kB
59.648 kB
react
Button
194.505 kB
55.936 kB
react
ButtonGrid
179.393 kB
53.938 kB
react
Calendar
121.313 kB
36.879 kB
react
Callout
84.45 kB
27.641 kB
react
Check
53.357 kB
17.884 kB
react
Checkbox
60.129 kB
19.922 kB
react
ChoiceGroup
65.639 kB
21.515 kB
react
ChoiceGroupOption
58.92 kB
19.402 kB
react
Coachmark
92.851 kB
29.355 kB
react
Color
7.94 kB
3.172 kB
react
ColorPicker
135.121 kB
42.173 kB
react
ComboBox
250.838 kB
71.554 kB
react
CommandBar
202.012 kB
59.433 kB
react
ContextualMenu
154.38 kB
47.613 kB
react
DatePicker
183.402 kB
55.937 kB
react
DateTimeUtilities
5.447 kB
1.915 kB
react
DetailsList
230.08 kB
65.862 kB
react
Dialog
210.311 kB
62.403 kB
react
Divider
19.739 kB
6.887 kB
react
DocumentCard
215.994 kB
63.712 kB
react
DragDrop
8.546 kB
2.788 kB
react
DraggableZone
34.431 kB
11.533 kB
react
Dropdown
233.302 kB
68.007 kB
react
ExtendedPicker
96.974 kB
27.904 kB
react
Fabric
41.879 kB
14.387 kB
react
Facepile
209.528 kB
62.425 kB
react
FloatingPicker
241.016 kB
68.269 kB
react
FocusTrapZone
17.141 kB
5.925 kB
react
FocusZone
55.251 kB
17.489 kB
react
Grid
179.393 kB
53.938 kB
react
GroupedList
135.186 kB
40.719 kB
react
GroupedListV2
122.81 kB
37.804 kB
react
HoverCard
96.935 kB
30.737 kB
react
Icon
52.038 kB
17.313 kB
react
Icons
66.49 kB
24.436 kB
react
Image
47.052 kB
15.744 kB
react
Keytip
81.452 kB
26.716 kB
react
KeytipData
14.201 kB
4.628 kB
react
KeytipLayer
103.24 kB
31.95 kB
react
Keytips
106.024 kB
32.948 kB
react
Label
38.475 kB
13.292 kB
react
Layer
48.24 kB
16.396 kB
react
Link
39.816 kB
13.701 kB
react
List
39.497 kB
12.494 kB
react
MarqueeSelection
74.641 kB
22.449 kB
react
MessageBar
189.539 kB
56.372 kB
react
Modal
93.889 kB
30.27 kB
react
Nav
186.976 kB
55.774 kB
react
OverflowSet
33.505 kB
11.328 kB
react
Overlay
41.036 kB
14.129 kB
react
Panel
200.478 kB
59.387 kB
react
Persona
114.742 kB
36.482 kB
react
PersonaCoin
114.742 kB
36.482 kB
react
PersonaPresence
58.227 kB
19.418 kB
react
Pickers
298.061 kB
83.044 kB
react
Pivot
187.885 kB
56.545 kB
react
Popup
12.463 kB
4.234 kB
react
Positioning
22.915 kB
7.719 kB
react
PositioningContainer
73.596 kB
23.734 kB
react
ProgressIndicator
39.628 kB
13.574 kB
react
Rating
82.237 kB
26.137 kB
react
Fluent UI React (entire library)
1.019 MB
283.242 kB
react
ResizeGroup
13.501 kB
4.424 kB
react
ResponsiveMode
8.281 kB
3.009 kB
react
ScrollablePane
55.692 kB
17.766 kB
react
SearchBox
187.781 kB
55.981 kB
react
SelectableOption
927 B
479 B
react
SelectedItemsList
231.501 kB
67.228 kB
react
Selection
42.569 kB
12.305 kB
react
Separator
35.516 kB
12.176 kB
react
Shimmer
49.4 kB
16.308 kB
react
ShimmeredDetailsList
240.861 kB
68.588 kB
react
Slider
57.778 kB
19.246 kB
react
SpinButton
191.448 kB
57.054 kB
react
Spinner
41.91 kB
14.517 kB
react
Stack
42.19 kB
14.432 kB
react
Sticky
32.728 kB
10.531 kB
react
Styling
46.184 kB
15.177 kB
react
SwatchColorPicker
189.788 kB
57.465 kB
react
TeachingBubble
204.799 kB
60.367 kB
react
Text
37.037 kB
12.847 kB
react
TextField
80.949 kB
25.358 kB
react
Theme
43.637 kB
14.212 kB
react
ThemeGenerator
12.535 kB
4.159 kB
react
TimePicker
240.666 kB
69.355 kB
react
Toggle
46.352 kB
16.008 kB
react
Tooltip
87.224 kB
28.202 kB
react
Utilities
83.089 kB
25.197 kB
react
Viewport
24.023 kB
7.683 kB
react
WeeklyDayPicker
101.499 kB
31.697 kB
react
WindowProvider
1.262 kB
614 B
react-aria
ARIA - useARIAButtonProps
1.364 kB
636 B
react-aria
ARIA - AriaLiveAnnouncer
3.299 kB
1.508 kB
react-charting
AreaChart
303.907 kB
95.157 kB
react-charting
ChartHoverCard
37.146 kB
12.686 kB
react-charting
DeclarativeChart
678.456 kB
191.9 kB
react-charting
DonutChart
204.633 kB
64.207 kB
react-charting
GanttChart
283.727 kB
89.15 kB
react-charting
GaugeChart
197.931 kB
61.641 kB
react-charting
GroupedVerticalBarChart
295.721 kB
92.416 kB
react-charting
HeatMapChart
286.584 kB
89.82 kB
react-charting
HorizontalBarChart
127.486 kB
40.04 kB
react-charting
HorizontalBarChartWithAxis
294.866 kB
91.562 kB
react-charting
Legends
152.166 kB
46.77 kB
react-charting
LineChart
333.45 kB
102.181 kB
react-charting
MultiStackedBarChart
182.75 kB
55.771 kB
react-charting
PieChart
135.094 kB
42.64 kB
react-charting
PolarChart
236.277 kB
74.791 kB
react-charting
SankeyChart
158.743 kB
49.564 kB
react-charting
ScatterChart
289.929 kB
91.473 kB
react-charting
Sparkline
88.073 kB
29.821 kB
react-charting
StackedBarChart
176.303 kB
53.339 kB
react-charting
TreeChart
85.693 kB
27.043 kB
react-charting
VerticalBarChart
304.556 kB
93.633 kB
react-charting
VerticalStackedBarChart
301.724 kB
93.359 kB
react-charts
HorizontalBarChartWithAxis
63 B
83 B
react-charts
Sparkline
81.004 kB
26.853 kB
react-jsx-runtime
Classic Pragma
1.282 kB
613 B
react-jsx-runtime
JSX Dev Runtime
2.139 kB
988 B
react-motion
@fluentui/react-motion - createMotionComponent()
4.339 kB
1.881 kB
react-motion
@fluentui/react-motion - createPresenceComponent()
6.097 kB
2.501 kB
react-motion
@fluentui/react-motion - PresenceGroup
1.727 kB
823 B
react-portal-compat
PortalCompatProvider
5.355 kB
2.153 kB
react-positioning
usePositioning
28.889 kB
10.158 kB
react-theme
Single theme token import
69 B
89 B
react-theme
Teams: all themes
37.985 kB
7.895 kB
react-theme
Teams: Light theme
20.803 kB
5.851 kB
react-utilities
SSRProvider
186 B
162 B
🤖 This report was generated against 869622d25f20f08cb9b39d355faa589b83a236bf

@Hotell Hotell force-pushed the feat/v9-valid-esm-drop-node-condition branch from f005762 to 067d2cc Compare June 30, 2026 08:42
@@ -26,6 +26,7 @@
"dist/esm/",
"dist/*.js",
"dist/*.d.ts",
"dist/*.d.cts",

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

undo

@Hotell Hotell changed the title feat(v9): ship web packages ESM-first (type:module), drop node export condition feat(v9,headless): ship web packages ESM-first (type:module), drop node export condition Jun 30, 2026
@Hotell Hotell force-pushed the feat/v9-valid-esm-drop-node-condition branch from 067d2cc to 097fcdd Compare July 8, 2026 13:47
Hotell added 20 commits July 9, 2026 18:27
…targeted bundlers

Adds a `module` condition nested in `node` to every converged v9 package's export map:
- node-targeted bundlers (webpack/rollup/vite/esbuild) resolve the ESM build and tree-shake
- bare Node ignores `module` and falls back to CommonJS, keeping SSR single-instance / dual-package-hazard free
- enables fully-specified .js import emit via swc `baseUrl` so lib/ is valid ESM

Updates the migrate-converged-pkg generator (source of truth) + swcrc template, and rolls the change out across all v9 packages with matching beachball change files.
…rt condition

Migrates converged v9 web packages to ESM-first packaging:
- `type: module` with valid ESM under lib/ (fully-specified .js) and CommonJS under lib-commonjs/*.cjs
- drop the `node` export condition; bare-Node `import` resolves ESM, `require` resolves CJS
- per-condition types: `require` points at a rolled `dist/*.d.cts` (attw-clean for node16/nodenext CJS)
- rename CJS dev configs to .cjs (jest/eslint/tests) for type:module compatibility

Build executor auto-emits lib-commonjs .cjs + dist .d.cts (gated on type:module).
Generators (migrate-converged-pkg, react-library) emit the new web shape; optional `attw` target added.
Excludes CJS-first (platform:node, storybook addons) and just-scripts (charts) packages.
@fluentui/tokens is now type:module (ESM, named exports, no default). The generate-tokens script relied on CJS-interop default import; switch to a namespace import.
…e tests

- rit.config.js -> .cjs (react-provider) + teach rit loader (args.ts) and workspace-plugin rit-target inference to prefer .cjs
- .storybook/main.js -> .cjs (recipes), scripts/server.js -> .cjs (tokens)
- getDependencies.spec: react-text main is now lib-commonjs/index.cjs; refresh dep-tree order snapshot
- react-library spec: drop stale jest.config.js from scaffold snapshot
Graph traversal order is non-deterministic across machines; sort deps by name for a stable snapshot.
Migrate @fluentui/scripts-cypress to type:module so its TS source loads
correctly when imported from migrated (type:module) cypress configs:

- package.json: type:module; rename node-run configs to .cjs (eslint/jest)
- base.config.ts: __dirname -> import.meta.dirname; add webpack resolve.extensionAlias (.js->.ts)
- index.ts: explicit .ts specifier for base.config re-export (resolves under native ESM via require(esm) from CommonJS cypress configs); explicit extension on browser type import
- browser/index.ts + support/*.js: fully-specified import specifiers; convert support require() to static ESM import
- tsconfig.lib.json: noEmit + allowImportingTsExtensions (source-only package)
- rit cypress.config template: __dirname -> process.cwd() for ESM/CJS sandbox parity

Validated: react-utilities/babel-preset-global-context/react-headless-components-preview e2e,
react-menu-grid-preview test-rit (17) e2e + test, scripts-cypress lint/test/type-check,
workspace-plugin (239) and react-integration-tester (37) unit tests.
…odule)

Complete the ESM-first migration for the one missed web package (it still
shipped the pre-migration shape: main=lib-commonjs/index.js, no type field):

- package.json: type:module, main->lib-commonjs/index.cjs, per-subpath exports
  rewritten to ESM-first nested shape (import.types=.d.ts/default=lib.js,
  require.types=.d.cts/default=lib-commonjs/*.cjs), dist/*.d.cts in files
- jest/eslint/test-setup configs renamed to .cjs
- generate-api: read subpath types from nested import.types (not just flat types)
  so exportSubpaths rollups work with the ESM-first export shape

Also simplify @fluentui/scripts-cypress: inline base.config into index.ts to
remove the only cross-file relative import. This fixes a type-check regression
where the prior explicit .ts specifier leaked an allowImportingTsExtensions
requirement into every cypress consumer, while still resolving under Node's
native ESM loader for CommonJS cypress configs.

Validated: react-headless build/attw(green)/lint/test(712)/type-check/e2e(185),
react-utilities & babel-preset-global-context e2e, react-menu-grid-preview
test-rit(17) e2e, scripts-cypress lint/type-check, workspace-plugin (239) tests.
- react-examples (v8, tsc --module commonjs) compiled FocusTrapZone.e2e.tsx,
  which imports @fluentui/scripts-cypress; the inlined base.config uses
  import.meta (required for type:module) and is invalid under module:commonjs.
  Exclude e2e cypress test files from the v8 library build (they're bundled by
  cypress at runtime, never part of the shipped lib).
- scripts-monorepo: annotate the getDependencies.spec sort comparator so checkJs
  doesn't flag implicit-any params (TS7006).
…module

- rit-tests-v8 cypress.config: __dirname -> import.meta.dirname (cypress loads it as ESM once it imports the type:module @fluentui/scripts-cypress)
- react-examples FocusTrapZone e2e: import mount from @cypress/react directly (v8-local) instead of ESM scripts-cypress, so the v8 commonjs build doesn't pull in import.meta; ignore e2e specs in eslint (bundled by cypress, not in tsconfig program)
… instead

Restore mount import from @fluentui/scripts-cypress (preserves StrictMode default).
Build no longer compiles e2e specs (excluded in tsconfig.json) so the ESM-only
scripts-cypress import.meta never reaches the commonjs tsc; eslint ignores e2e.
…resolution

react-message-bar: MessagebarActions -> MessageBarActions; react-table: createColumn -> createTableColumn. These named exports were always wrong but only error now under strict ESM.
…aths resolve

type:module packages emit bare subpath imports (e.g. use-sync-external-store/shim) without extensions; webpack treats lib/ as ESM and enforces fully-specified. Disable it for the measure bundler.
…ayout

scaffolded package lives at <scope>/<name>/library (4 deep); preset must be ../../../../jest.preset.js. Fixes check-tools react-component generator running test.
…import.meta

cy specs import scripts-cypress whose inlined base.config uses import.meta; type-check under commonjs failed (TS1343). esnext module allows it (type-check only, noEmit).
…oad as ESM

Their cypress.config.ts imports the type:module @fluentui/scripts-cypress, which forces Node to load the config as ESM; ts-node was emitting CommonJS (exports) into that ESM scope (TS-node CJS/ESM mismatch) -> 'exports is not defined in ES module scope'. Aligning the apps to type:module makes ts-node emit ESM. Renamed jest/eslint/rit/test-setup configs to .cjs accordingly.

Validated: rit-tests-v8 e2e(17)+lint+test+type-check, rit-tests-v9 test-rit(17) type-check+test+lint.
Hotell added 4 commits July 9, 2026 18:28
…ng type:module

Give @fluentui/scripts-cypress a build (SWC -> lib/ ESM + lib-commonjs/*.cjs) instead of
being consumed as raw .ts source via main: src/index.ts. Consumers now resolve the format
that matches them (import -> lib/index.js, require -> lib-commonjs/index.cjs), so per-file
transpilers like ts-node never recompile it against a consumer's tsconfig.

This removes the architectural leak where CommonJS consumers (the rit harness) were forced to
become type:module: rit-tests-v8/v9 are reverted to plain CommonJS.

- scripts-cypress: .swcrc + project.json build target (generateApi:false), ESM-first package.json
  (main/module/browser/exports), split base.config back out, move support/fixtures to package root
  (referenced via ../ so the built output points at them)
- nx.json: component e2e dependsOn scripts-cypress:build (rit prepare already ^build)
- apps/rit-tests-v8/v9: drop type:module, configs back to .js, cypress.config __dirname

Validated: react-utilities & babel-preset-global-context e2e, rit-tests-v8 test-rit(17) e2e,
rit-tests-v8/v9 lint+test+type-check, scripts-cypress build+lint+type-check, react-examples
build+lint, workspace-plugin (239) + react-integration-tester (37) tests, e2e dependsOn auto-builds.
…r build)

It only existed to map .js->.ts when bundling scripts-cypress's raw .ts source under type:module. Now that the package is built, the browser/support files webpack bundles are real .js. Validated: react-headless(185)/react-utilities/rit-tests-v8 e2e.
…orkaround

Enable generateApi (api-extractor) so scripts-cypress ships dist/index.d.ts. The rolled
declaration has no import.meta (implementation stripped), so CommonJS consumers type-checking
against it no longer hit TS1343. types/exports now point at dist/index.d.ts.

- rit-tests-v8/v9 tsconfig.cy.json: remove module:esnext (no longer needed)
- react-examples keeps excluding e2e specs from the v8 build (cypress test files don't belong in
  lib, unrelated to import.meta)

Validated: scripts-cypress build(d.ts clean of import.meta)/type-check/lint, rit-tests-v8/v9 type-check, react-examples build+lint, react-utilities e2e.
@Hotell Hotell force-pushed the feat/v9-valid-esm-drop-node-condition branch from 097fcdd to 49ee7a2 Compare July 9, 2026 16:28
Hotell added a commit to Hotell/fluentui-system-icons that referenced this pull request Jul 10, 2026
Make @fluentui/react-icons valid native ESM so bare-Node `import` loads real
ESM (and tree-shakes) while `require` still gets CommonJS. Complements the v9
web/headless packages moving to ESM-first (microsoft/fluentui#36327), which
were blocked by react-icons shipping extensionless ESM imports.

- Add `"type": "module"`; `main` -> `lib-cjs/index.cjs`.
- New scripts/module-format.js: fully-specify `lib/` ESM specifiers (.js /
  /index.js) and finalize `lib-cjs/` as `.cjs` + `.d.cts` after tsc/griffel.
- Restructure every `exports` subpath to conditional import/require with
  per-condition types (`.d.ts` for import, `.d.cts` for require).
- Keep build tooling CommonJS via scripts/package.json; rename svgo config to
  .cjs and make fluent-icons-transform.js ESM.
- Update build-verify tests/snapshots for the .cjs/.d.cts/fully-specified output.

attw: node16 (ESM+CJS) and bundler resolve clean; bare-Node import and require
of the root barrel and atom subpaths both load.
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.

1 participant