From 27d14950a3df9bd57679cbcee0266af900fdf588 Mon Sep 17 00:00:00 2001 From: Martin Hochel Date: Tue, 18 Aug 2026 12:16:35 +0200 Subject: [PATCH 1/2] chore(react-components): verify bundle isolation of base hooks BaseHooks.fixture.js imports all 103 use*Base_unstable hooks from the 39 suite dependencies that export them. Named imports, since a namespace import would retain every styled component and defeat the check. Baselines what base hooks currently drag in as tracked debt: tabster (55 modules across 22 packages, via useArrowNavigationGroup and useFocusFinders), Griffel (react-combobox Listbox styles, react-positioning SafeZoneArea) and react-motion (react-nav useNavCategoryItem). The four styled monosize fixtures in the same folder are left unlisted, so they are measured for bytes without being held to an isolation guarantee they were never meant to carry. --- ...-3f1c8a7e-6b02-4d9a-9c41-8e5b0a2d7c14.json | 7 + .../bundle-isolation.config.json | 11 + .../bundle-size/BaseHooks.fixture.js | 237 ++++++++++++++++++ .../react-components/package.json | 3 + .../react-components/project.json | 14 ++ yarn.lock | 1 + 6 files changed, 273 insertions(+) create mode 100644 change/@fluentui-react-components-3f1c8a7e-6b02-4d9a-9c41-8e5b0a2d7c14.json create mode 100644 packages/react-components/react-components/bundle-isolation.config.json create mode 100644 packages/react-components/react-components/bundle-size/BaseHooks.fixture.js diff --git a/change/@fluentui-react-components-3f1c8a7e-6b02-4d9a-9c41-8e5b0a2d7c14.json b/change/@fluentui-react-components-3f1c8a7e-6b02-4d9a-9c41-8e5b0a2d7c14.json new file mode 100644 index 0000000000000..44c8aad060857 --- /dev/null +++ b/change/@fluentui-react-components-3f1c8a7e-6b02-4d9a-9c41-8e5b0a2d7c14.json @@ -0,0 +1,7 @@ +{ + "type": "none", + "comment": "chore: verify bundle isolation of base hooks", + "packageName": "@fluentui/react-components", + "email": "martinhochel@microsoft.com", + "dependentChangeType": "none" +} diff --git a/packages/react-components/react-components/bundle-isolation.config.json b/packages/react-components/react-components/bundle-isolation.config.json new file mode 100644 index 0000000000000..ec85054fa7b42 --- /dev/null +++ b/packages/react-components/react-components/bundle-isolation.config.json @@ -0,0 +1,11 @@ +{ + "$schema": "../../../tools/verify-bundle-isolation/schema.json", + "fixturesRoot": "./bundle-size", + "externals": ["react", "react-dom", "react/jsx-runtime", "react/compiler-runtime"], + "forbiddenPackages": ["tabster", "@griffel/*", "@fluentui/react-icons", "@fluentui/react-motion"], + "fixtures": { + "BaseHooks.fixture.js": { + "allowedViolations": ["@fluentui/react-motion", "@griffel/core", "@griffel/react", "tabster"] + } + } +} diff --git a/packages/react-components/react-components/bundle-size/BaseHooks.fixture.js b/packages/react-components/react-components/bundle-size/BaseHooks.fixture.js new file mode 100644 index 0000000000000..07beaa3e59699 --- /dev/null +++ b/packages/react-components/react-components/bundle-size/BaseHooks.fixture.js @@ -0,0 +1,237 @@ +// Named imports only - a namespace import would retain every styled component and defeat the isolation check. +import { + useAccordionBase_unstable, + useAccordionHeaderBase_unstable, + useAccordionPanelBase_unstable, +} from '@fluentui/react-accordion'; +import { + useAvatarBase_unstable, + useAvatarGroupBase_unstable, + useAvatarGroupItemBase_unstable, + useAvatarGroupPopoverBase_unstable, +} from '@fluentui/react-avatar'; +import { + useBadgeBase_unstable, + useCounterBadgeBase_unstable, + usePresenceBadgeBase_unstable, +} from '@fluentui/react-badge'; +import { + useBreadcrumbBase_unstable, + useBreadcrumbButtonBase_unstable, + useBreadcrumbDividerBase_unstable, + useBreadcrumbItemBase_unstable, +} from '@fluentui/react-breadcrumb'; +import { + useButtonBase_unstable, + useCompoundButtonBase_unstable, + useMenuButtonBase_unstable, + useSplitButtonBase_unstable, + useToggleButtonBase_unstable, +} from '@fluentui/react-button'; +import { + useCardBase_unstable, + useCardFooterBase_unstable, + useCardHeaderBase_unstable, + useCardPreviewBase_unstable, +} from '@fluentui/react-card'; +import { useCheckboxBase_unstable } from '@fluentui/react-checkbox'; +import { + useAlphaSliderBase_unstable, + useColorAreaBase_unstable, + useColorPickerBase_unstable, + useColorSliderBase_unstable, +} from '@fluentui/react-color-picker'; +import { useComboboxBase_unstable, useDropdownBase_unstable, useOptionBase_unstable } from '@fluentui/react-combobox'; +import { useDividerBase_unstable } from '@fluentui/react-divider'; +import { useInlineDrawerBase_unstable } from '@fluentui/react-drawer'; +import { useFieldBase_unstable } from '@fluentui/react-field'; +import { useImageBase_unstable } from '@fluentui/react-image'; +import { useInputBase_unstable } from '@fluentui/react-input'; +import { useLabelBase_unstable } from '@fluentui/react-label'; +import { useLinkBase_unstable } from '@fluentui/react-link'; +import { + useMenuBase_unstable, + useMenuItemBase_unstable, + useMenuItemCheckboxBase_unstable, + useMenuItemLinkBase_unstable, + useMenuItemRadioBase_unstable, + useMenuItemSwitchBase_unstable, + useMenuListBase_unstable, + useMenuPopoverBase_unstable, + useMenuTriggerBase_unstable, +} from '@fluentui/react-menu'; +import { useMessageBarBase_unstable } from '@fluentui/react-message-bar'; +import { + useAppItemBase_unstable, + useAppItemStaticBase_unstable, + useNavBase_unstable, + useNavCategoryItemBase_unstable, + useNavItemBase_unstable, + useNavSubItemBase_unstable, + useNavSubItemGroupBase_unstable, +} from '@fluentui/react-nav'; +import { usePersonaBase_unstable } from '@fluentui/react-persona'; +import { useProgressBarBase_unstable } from '@fluentui/react-progress'; +import { useRadioBase_unstable, useRadioGroupBase_unstable } from '@fluentui/react-radio'; +import { + useRatingBase_unstable, + useRatingDisplayBase_unstable, + useRatingItemBase_unstable, +} from '@fluentui/react-rating'; +import { useSearchBoxBase_unstable } from '@fluentui/react-search'; +import { useSelectBase_unstable } from '@fluentui/react-select'; +import { useSkeletonBase_unstable, useSkeletonItemBase_unstable } from '@fluentui/react-skeleton'; +import { useSliderBase_unstable } from '@fluentui/react-slider'; +import { useSpinButtonBase_unstable } from '@fluentui/react-spinbutton'; +import { useSpinnerBase_unstable } from '@fluentui/react-spinner'; +import { + useColorSwatchBase_unstable, + useEmptySwatchBase_unstable, + useImageSwatchBase_unstable, + useSwatchPickerBase_unstable, + useSwatchPickerRowBase_unstable, +} from '@fluentui/react-swatch-picker'; +import { useSwitchBase_unstable } from '@fluentui/react-switch'; +import { useTabBase_unstable, useTabListBase_unstable } from '@fluentui/react-tabs'; +import { + useTagPickerBase_unstable, + useTagPickerButtonBase_unstable, + useTagPickerControlBase_unstable, + useTagPickerInputBase_unstable, +} from '@fluentui/react-tag-picker'; +import { + useInteractionTagBase_unstable, + useInteractionTagPrimaryBase_unstable, + useInteractionTagSecondaryBase_unstable, + useTagBase_unstable, + useTagGroupBase_unstable, +} from '@fluentui/react-tags'; +import { + useTeachingPopoverCarouselBase_unstable, + useTeachingPopoverCarouselFooterButtonBase_unstable, + useTeachingPopoverCarouselNavBase_unstable, + useTeachingPopoverCarouselNavButtonBase_unstable, + useTeachingPopoverFooterBase_unstable, + useTeachingPopoverHeaderBase_unstable, + useTeachingPopoverTitleBase_unstable, +} from '@fluentui/react-teaching-popover'; +import { useTextareaBase_unstable } from '@fluentui/react-textarea'; +import { useToastBase_unstable, useToastBodyBase_unstable, useToastTitleBase_unstable } from '@fluentui/react-toast'; +import { + useToolbarBase_unstable, + useToolbarButtonBase_unstable, + useToolbarDividerBase_unstable, + useToolbarRadioButtonBase_unstable, + useToolbarToggleButtonBase_unstable, +} from '@fluentui/react-toolbar'; +import { useTooltipBase_unstable } from '@fluentui/react-tooltip'; + +console.log( + useAccordionBase_unstable, + useAccordionHeaderBase_unstable, + useAccordionPanelBase_unstable, + useAvatarBase_unstable, + useAvatarGroupBase_unstable, + useAvatarGroupItemBase_unstable, + useAvatarGroupPopoverBase_unstable, + useBadgeBase_unstable, + useCounterBadgeBase_unstable, + usePresenceBadgeBase_unstable, + useBreadcrumbBase_unstable, + useBreadcrumbButtonBase_unstable, + useBreadcrumbDividerBase_unstable, + useBreadcrumbItemBase_unstable, + useButtonBase_unstable, + useCompoundButtonBase_unstable, + useMenuButtonBase_unstable, + useSplitButtonBase_unstable, + useToggleButtonBase_unstable, + useCardBase_unstable, + useCardFooterBase_unstable, + useCardHeaderBase_unstable, + useCardPreviewBase_unstable, + useCheckboxBase_unstable, + useAlphaSliderBase_unstable, + useColorAreaBase_unstable, + useColorPickerBase_unstable, + useColorSliderBase_unstable, + useComboboxBase_unstable, + useDropdownBase_unstable, + useOptionBase_unstable, + useDividerBase_unstable, + useInlineDrawerBase_unstable, + useFieldBase_unstable, + useImageBase_unstable, + useInputBase_unstable, + useLabelBase_unstable, + useLinkBase_unstable, + useMenuBase_unstable, + useMenuItemBase_unstable, + useMenuItemCheckboxBase_unstable, + useMenuItemLinkBase_unstable, + useMenuItemRadioBase_unstable, + useMenuItemSwitchBase_unstable, + useMenuListBase_unstable, + useMenuPopoverBase_unstable, + useMenuTriggerBase_unstable, + useMessageBarBase_unstable, + useAppItemBase_unstable, + useAppItemStaticBase_unstable, + useNavBase_unstable, + useNavCategoryItemBase_unstable, + useNavItemBase_unstable, + useNavSubItemBase_unstable, + useNavSubItemGroupBase_unstable, + usePersonaBase_unstable, + useProgressBarBase_unstable, + useRadioBase_unstable, + useRadioGroupBase_unstable, + useRatingBase_unstable, + useRatingDisplayBase_unstable, + useRatingItemBase_unstable, + useSearchBoxBase_unstable, + useSelectBase_unstable, + useSkeletonBase_unstable, + useSkeletonItemBase_unstable, + useSliderBase_unstable, + useSpinButtonBase_unstable, + useSpinnerBase_unstable, + useColorSwatchBase_unstable, + useEmptySwatchBase_unstable, + useImageSwatchBase_unstable, + useSwatchPickerBase_unstable, + useSwatchPickerRowBase_unstable, + useSwitchBase_unstable, + useTabBase_unstable, + useTabListBase_unstable, + useTagPickerBase_unstable, + useTagPickerButtonBase_unstable, + useTagPickerControlBase_unstable, + useTagPickerInputBase_unstable, + useInteractionTagBase_unstable, + useInteractionTagPrimaryBase_unstable, + useInteractionTagSecondaryBase_unstable, + useTagBase_unstable, + useTagGroupBase_unstable, + useTeachingPopoverCarouselBase_unstable, + useTeachingPopoverCarouselFooterButtonBase_unstable, + useTeachingPopoverCarouselNavBase_unstable, + useTeachingPopoverCarouselNavButtonBase_unstable, + useTeachingPopoverFooterBase_unstable, + useTeachingPopoverHeaderBase_unstable, + useTeachingPopoverTitleBase_unstable, + useTextareaBase_unstable, + useToastBase_unstable, + useToastBodyBase_unstable, + useToastTitleBase_unstable, + useToolbarBase_unstable, + useToolbarButtonBase_unstable, + useToolbarDividerBase_unstable, + useToolbarRadioButtonBase_unstable, + useToolbarToggleButtonBase_unstable, + useTooltipBase_unstable, +); + +export default { + name: 'react-components: all base hooks', +}; diff --git a/packages/react-components/react-components/package.json b/packages/react-components/react-components/package.json index 17b5e8b9759db..91647b3bc2965 100644 --- a/packages/react-components/react-components/package.json +++ b/packages/react-components/react-components/package.json @@ -75,6 +75,9 @@ "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" }, + "devDependencies": { + "@fluentui/verify-bundle-isolation": "*" + }, "peerDependencies": { "@types/react": ">=16.14.0 <20.0.0", "@types/react-dom": ">=16.9.0 <20.0.0", diff --git a/packages/react-components/react-components/project.json b/packages/react-components/react-components/project.json index 6849412701718..744589c349cf5 100644 --- a/packages/react-components/react-components/project.json +++ b/packages/react-components/react-components/project.json @@ -27,6 +27,20 @@ } ] } + }, + "verify-bundle-isolation": { + "cache": true, + "dependsOn": ["build", "^build"], + "command": "yarn run -T verify-bundle-isolation", + "options": { + "cwd": "{projectRoot}" + }, + "inputs": ["default", "^default", { "externalDependencies": ["ajv", "webpack"] }], + "outputs": ["{projectRoot}/dist/bundle-isolation"], + "metadata": { + "technologies": ["webpack"], + "description": "Assert base hooks do not bundle tabster, Griffel, react-icons or motion" + } } } } diff --git a/yarn.lock b/yarn.lock index 29a79676267e6..c6fc8314396ef 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3960,6 +3960,7 @@ __metadata: "@fluentui/react-tree": "npm:^9.16.5" "@fluentui/react-utilities": "npm:^9.26.6" "@fluentui/react-virtualizer": "npm:9.0.0-alpha.115" + "@fluentui/verify-bundle-isolation": "npm:*" "@griffel/react": "npm:^1.5.32" "@swc/helpers": "npm:^0.5.1" peerDependencies: From d917292e291ac67331400bc6377b8a5ee0793d6f Mon Sep 17 00:00:00 2001 From: Martin Hochel Date: Thu, 20 Aug 2026 12:53:04 +0200 Subject: [PATCH 2/2] chore(workspace-plugin): infer the verify-bundle-isolation target The target was copy-pasted into each consuming project.json, and each consumer declared the tool as a devDependency purely to create an nx graph edge so cache and affected stayed correct. The plugin now infers the target from the presence of bundle-isolation.config.json, the same way bundle-size is inferred from a bundle-size directory, and a {workspaceRoot} input on the tool covers both cache invalidation and affected - the convention already used by the rit targets. Both devDependencies go away. --- ...-b41d2e90-7c35-4a18-9f6e-2d0c81a4f7b3.json | 7 ++++ .../react-components/package.json | 3 -- .../react-components/project.json | 14 -------- .../library/package.json | 1 - .../library/project.json | 14 -------- tools/verify-bundle-isolation/README.md | 32 ++++------------- .../src/plugins/workspace-plugin.spec.ts | 34 ++++++++++++++++++ .../src/plugins/workspace-plugin.ts | 36 +++++++++++++++++++ yarn.lock | 2 -- 9 files changed, 84 insertions(+), 59 deletions(-) create mode 100644 change/@fluentui-react-headless-components-preview-b41d2e90-7c35-4a18-9f6e-2d0c81a4f7b3.json diff --git a/change/@fluentui-react-headless-components-preview-b41d2e90-7c35-4a18-9f6e-2d0c81a4f7b3.json b/change/@fluentui-react-headless-components-preview-b41d2e90-7c35-4a18-9f6e-2d0c81a4f7b3.json new file mode 100644 index 0000000000000..a5ee5e47aa9b5 --- /dev/null +++ b/change/@fluentui-react-headless-components-preview-b41d2e90-7c35-4a18-9f6e-2d0c81a4f7b3.json @@ -0,0 +1,7 @@ +{ + "type": "none", + "comment": "chore: infer verify-bundle-isolation target from workspace plugin", + "packageName": "@fluentui/react-headless-components-preview", + "email": "martinhochel@microsoft.com", + "dependentChangeType": "none" +} diff --git a/packages/react-components/react-components/package.json b/packages/react-components/react-components/package.json index 91647b3bc2965..17b5e8b9759db 100644 --- a/packages/react-components/react-components/package.json +++ b/packages/react-components/react-components/package.json @@ -75,9 +75,6 @@ "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" }, - "devDependencies": { - "@fluentui/verify-bundle-isolation": "*" - }, "peerDependencies": { "@types/react": ">=16.14.0 <20.0.0", "@types/react-dom": ">=16.9.0 <20.0.0", diff --git a/packages/react-components/react-components/project.json b/packages/react-components/react-components/project.json index 744589c349cf5..6849412701718 100644 --- a/packages/react-components/react-components/project.json +++ b/packages/react-components/react-components/project.json @@ -27,20 +27,6 @@ } ] } - }, - "verify-bundle-isolation": { - "cache": true, - "dependsOn": ["build", "^build"], - "command": "yarn run -T verify-bundle-isolation", - "options": { - "cwd": "{projectRoot}" - }, - "inputs": ["default", "^default", { "externalDependencies": ["ajv", "webpack"] }], - "outputs": ["{projectRoot}/dist/bundle-isolation"], - "metadata": { - "technologies": ["webpack"], - "description": "Assert base hooks do not bundle tabster, Griffel, react-icons or motion" - } } } } diff --git a/packages/react-components/react-headless-components-preview/library/package.json b/packages/react-components/react-headless-components-preview/library/package.json index ae979fed08df4..f2ebdfa9ae56f 100644 --- a/packages/react-components/react-headless-components-preview/library/package.json +++ b/packages/react-components/react-headless-components-preview/library/package.json @@ -607,7 +607,6 @@ }, "devDependencies": { "@fluentui/scripts-cypress": "*", - "@fluentui/verify-bundle-isolation": "*", "@oddbird/popover-polyfill": "^0.6.1" }, "type": "module" diff --git a/packages/react-components/react-headless-components-preview/library/project.json b/packages/react-components/react-headless-components-preview/library/project.json index 7b99dac170d30..ecab81877a1e1 100644 --- a/packages/react-components/react-headless-components-preview/library/project.json +++ b/packages/react-components/react-headless-components-preview/library/project.json @@ -10,20 +10,6 @@ "options": { "exportSubpaths": true } - }, - "verify-bundle-isolation": { - "cache": true, - "dependsOn": ["build", "^build"], - "command": "yarn run -T verify-bundle-isolation", - "options": { - "cwd": "{projectRoot}" - }, - "inputs": ["default", "^default", { "externalDependencies": ["ajv", "webpack"] }], - "outputs": ["{projectRoot}/dist/bundle-isolation"], - "metadata": { - "technologies": ["webpack"], - "description": "Assert entry points do not bundle tabster, Griffel or react-icons" - } } } } diff --git a/tools/verify-bundle-isolation/README.md b/tools/verify-bundle-isolation/README.md index 7dcf1916b5d54..84530c39e8cac 100644 --- a/tools/verify-bundle-isolation/README.md +++ b/tools/verify-bundle-isolation/README.md @@ -25,35 +25,17 @@ no longer uses is not reported. ## Usage -Add the tool as a devDependency of the package to check and give it a target: +Add a `bundle-isolation.config.json` to the package root. That is the whole setup — the workspace plugin infers the +`verify-bundle-isolation` target from the presence of that file, the same way it infers `bundle-size` from a +`bundle-size/` directory. Nothing to add to `project.json`, and the tool does not need to be a devDependency of the +package. -```jsonc -// package.json -{ "devDependencies": { "@fluentui/verify-bundle-isolation": "*" } } ``` - -```jsonc -// project.json -{ - "targets": { - "verify-bundle-isolation": { - "cache": true, - "dependsOn": ["build", "^build"], - "command": "yarn run -T verify-bundle-isolation", - "options": { "cwd": "{projectRoot}" }, - "inputs": ["default", "^default", { "externalDependencies": ["ajv", "webpack"] }], - "outputs": ["{projectRoot}/dist/bundle-isolation"] - } - } -} +yarn nx run :verify-bundle-isolation ``` -The check must run against built output, hence `dependsOn`. It reports an error if bundling resolves to package sources -instead, because the verdict would not reflect what ships. - -`^default` is what makes the cache correct: this task's result depends on every dependency's files, and on the tool -itself, which is a dependency by virtue of the devDependency. Replacing it with a hand-written input list silently -serves stale verdicts after a dependency changes. +The target runs against built output. Bundling that resolves to package sources is reported as an error, because the +verdict would not reflect what ships. The repo pins webpack to a single version through `resolutions` in the root `package.json`. That is deliberate - the verdict is only meaningful if it comes from the same bundler that produces the bundle-size numbers, and webpack 5.109 diff --git a/tools/workspace-plugin/src/plugins/workspace-plugin.spec.ts b/tools/workspace-plugin/src/plugins/workspace-plugin.spec.ts index 7e9d7a1112c3a..75e8562fa07de 100644 --- a/tools/workspace-plugin/src/plugins/workspace-plugin.spec.ts +++ b/tools/workspace-plugin/src/plugins/workspace-plugin.spec.ts @@ -207,6 +207,40 @@ describe(`workspace-plugin`, () => { `); }); + it('should add the verify-bundle-isolation target only when a bundle-isolation.config.json exists', async () => { + await tempFs.createFiles({ + 'with-config/project.json': serializeJson({}), + 'with-config/package.json': serializeJson({}), + 'with-config/bundle-isolation.config.json': serializeJson({}), + 'no-config/project.json': serializeJson({}), + 'no-config/package.json': serializeJson({}), + // a monosize fixtures dir alone must not be mistaken for an isolation opt-in + 'no-config/bundle-size/A.fixture.js': '', + }); + + const withConfig = await createNodesFunction(['with-config/project.json'], options, context); + const noConfig = await createNodesFunction(['no-config/project.json'], options, context); + + expect(getTargetsNames(noConfig, 'no-config')).not.toContain('verify-bundle-isolation'); + expect(getTargets(withConfig, 'with-config')?.['verify-bundle-isolation']).toEqual({ + cache: true, + dependsOn: ['build', '^build'], + command: 'yarn run -T verify-bundle-isolation', + options: { cwd: 'with-config' }, + inputs: [ + 'default', + '^default', + '{workspaceRoot}/tools/verify-bundle-isolation/**', + { externalDependencies: ['ajv', 'webpack'] }, + ], + outputs: ['{projectRoot}/dist/bundle-isolation'], + metadata: { + technologies: ['webpack'], + description: 'Assert entry points do not bundle runtimes the package is meant to stay free of', + }, + }); + }); + describe(`v9 project nodes`, () => { describe(`React Integration Tester config`, () => { it(`should not create atomized targets if project doesnt have required configurations`, async () => { diff --git a/tools/workspace-plugin/src/plugins/workspace-plugin.ts b/tools/workspace-plugin/src/plugins/workspace-plugin.ts index 154f5fe7a0ed3..780ea2be44bef 100644 --- a/tools/workspace-plugin/src/plugins/workspace-plugin.ts +++ b/tools/workspace-plugin/src/plugins/workspace-plugin.ts @@ -197,6 +197,11 @@ function buildWorkspaceProjectConfiguration( targets['bundle-size'] = bundleSizeTarget; } + const verifyBundleIsolationTarget = buildVerifyBundleIsolationTarget(projectRoot, options, context, config); + if (verifyBundleIsolationTarget) { + targets['verify-bundle-isolation'] = verifyBundleIsolationTarget; + } + // react v9 lib if (config.projectJSON.projectType === 'library' && config.tags.includes('vNext')) { // *-stories projects @@ -566,6 +571,37 @@ function buildBundleSizeTarget( }; } +function buildVerifyBundleIsolationTarget( + projectRoot: string, + options: Required, + context: CreateNodesContextV2, + config: TaskBuilderConfig, +): TargetConfiguration | null { + if (!existsSync(join(projectRoot, 'bundle-isolation.config.json'))) { + return null; + } + + return { + cache: true, + // Must bundle built output - resolving to sources makes the verdict meaningless, and the tool errors on it. + dependsOn: ['build', '^build'], + command: `${config.pmc.exec} verify-bundle-isolation`, + options: { cwd: projectRoot }, + inputs: [ + 'default', + '^default', + // Also what makes `nx affected` select consumers when the checker itself changes. + '{workspaceRoot}/tools/verify-bundle-isolation/**', + { externalDependencies: ['ajv', 'webpack'] }, + ], + outputs: ['{projectRoot}/dist/bundle-isolation'], + metadata: { + technologies: ['webpack'], + description: 'Assert entry points do not bundle runtimes the package is meant to stay free of', + }, + }; +} + function buildE2eTarget( projectRoot: string, options: Required, diff --git a/yarn.lock b/yarn.lock index c6fc8314396ef..b5addb6a3c112 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3960,7 +3960,6 @@ __metadata: "@fluentui/react-tree": "npm:^9.16.5" "@fluentui/react-utilities": "npm:^9.26.6" "@fluentui/react-virtualizer": "npm:9.0.0-alpha.115" - "@fluentui/verify-bundle-isolation": "npm:*" "@griffel/react": "npm:^1.5.32" "@swc/helpers": "npm:^0.5.1" peerDependencies: @@ -4368,7 +4367,6 @@ __metadata: "@fluentui/react-tooltip": "npm:^9.10.5" "@fluentui/react-utilities": "npm:^9.26.6" "@fluentui/scripts-cypress": "npm:*" - "@fluentui/verify-bundle-isolation": "npm:*" "@oddbird/popover-polyfill": "npm:^0.6.1" "@swc/helpers": "npm:^0.5.1" peerDependencies: