Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
Comment thread
Hotell marked this conversation as resolved.
"type": "none",
"comment": "chore: verify bundle isolation of base hooks",
"packageName": "@fluentui/react-components",
"email": "martinhochel@microsoft.com",
"dependentChangeType": "none"
}
Original file line number Diff line number Diff line change
@@ -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"
}
Original file line number Diff line number Diff line change
@@ -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"]
}
}
}
Original file line number Diff line number Diff line change
@@ -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',
};
Original file line number Diff line number Diff line change
Expand Up @@ -607,7 +607,6 @@
},
"devDependencies": {
"@fluentui/scripts-cypress": "*",
"@fluentui/verify-bundle-isolation": "*",
"@oddbird/popover-polyfill": "^0.6.1"
},
"type": "module"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
}
}
}
32 changes: 7 additions & 25 deletions tools/verify-bundle-isolation/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 <project>: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
Expand Down
34 changes: 34 additions & 0 deletions tools/workspace-plugin/src/plugins/workspace-plugin.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 () => {
Expand Down
Loading
Loading