Update cart/checkout usage of the @wordpress/components Slot Fill (#47105)

This commit is contained in:
Sam Seay 2024-05-16 17:46:24 +08:00 committed by GitHub
parent 5cd46f48ad
commit fcc421d550
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 133 additions and 76 deletions

View File

@ -1,11 +1,12 @@
# Base Components/Context/Hooks
Base components are designed to be used on the frontend of a store. Due to this, we need to avoid using heavy WordPress externals as dependencies (wp-components, wp-block-editor, etc). To get around this, import from a local package instead.
Base components are designed to be used on the frontend of a store. Due to this, we need to avoid using heavy WordPress externals as dependencies (`@wordpress/blocks`, `@wordpress/block-editor`, etc).
e.g. Instead of importing from `@wordpress/components`, use:
Note 2 exceptions, we do use the `Slot` and `Fill` which we [import and bundle](../../../packages/checkout/slot/index.js) from `@wordpress/components`. Otherwise you should avoid importing anything else from that package.
```js
import { Component } from 'wordpress-components';
```
The other exception is the `FormTokenField`, which is used in deprecated blocks and use of [that import](../base/components/form-token-field/) is also deprecated.
If you need primitive/low-level components to build components in this library, please use [Ariakit](https://ariakit.org/) to build them.
See [Button](components/button/index.tsx) for an example.
Check the built `*.assets.php` files to ensure extra dependencies aren't being added to the build.

View File

@ -43,11 +43,13 @@ In practice, that means the dependency version is:
[`@wordpress/dependency-extraction-webpack-plugin`](https://developer.wordpress.org/block-editor/packages/packages-dependency-extraction-webpack-plugin/) script is applied to each of the build processes: Core, Main, Frontend, Payments, Extensions.
### `wordpress-components` alias
### `wordpress-components` and `wordpress-components-slotfill` alias
`@wordpress/components` is one of the dependencies that gets externalized by the plugin. You can see the external `components.min.js` file being loaded on the Editor pages containing blocks that depend on the `@wordpress/components`, while the code is not bundled within WooCommerce Blocks files.
We have an alias to the 14.2.0 version of `@wordpress/components` called `wordpress-components`. This alias was used to import a limited set of components in front-end components. This alias is deprecated and **should no longer be used**. When the `FormTokenField` component is removed from the codebase, the alias will be removed as well.
For optimization purposes, there's a `wordpress-components` alias created, which is used in the frontend code. Thanks to that, the dependency omits the Dependency Extraction Plugin and behaves like any other dependency: it's tree-shaken and only the necessary code is bundled with the block. That allows us to avoid loading the whole `@wordpress/components` on the frontend pages.
We also have one other alias `wordpress-components-slotfill` which is used to import the `SlotFill` and `Fill` components from `@wordpress/components`. This alias **should not be used to import any other dependencies from `@wordpress/components`**. Note that it is tree-shaken so should only bundle the small amount of code directly needed to support slot fill functionality.
If you need to build front-end components in future, you should use Ariakit to build them. See examples like the [Button](../../assets/js/base/components/button/index.tsx) component for how to build components using Ariakit.
## Aliases
@ -84,4 +86,3 @@ Webpack config is split between several files:
🐞 Found a mistake, or have a suggestion? [Leave feedback about this document here.](https://github.com/woocommerce/woocommerce-blocks/issues/new?assignees=&labels=type%3A+documentation&template=--doc-feedback.md&title=Feedback%20on%20./docs/contributors/javascript-build-system.md)
<!-- /FEEDBACK -->

View File

@ -315,7 +315,8 @@
"trim-html": "0.1.9",
"use-debounce": "9.0.4",
"usehooks-ts": "^2.9.1",
"wordpress-components": "npm:@wordpress/components@14.2.0"
"wordpress-components": "npm:@wordpress/components@14.2.0",
"wordpress-components-slotfill": "npm:@wordpress/components@wp-6.5"
},
"peerDependencies": {
"react": "^18.3.0",

View File

@ -6,7 +6,7 @@ import classnames from 'classnames';
/**
* Internal dependencies
*/
import { createSlotFill, hasValidFills, useSlot } from '../../slot';
import { createSlotFill, hasValidFills, useSlotFills } from '../../slot';
import TotalsWrapper from '../../../components/totals-wrapper';
const slotName = '__experimentalDiscountsMeta';
@ -15,7 +15,7 @@ const { Fill: ExperimentalDiscountsMeta, Slot: DiscountsMetaSlot } =
createSlotFill( slotName );
const Slot = ( { className, extensions, cart, context } ) => {
const { fills } = useSlot( slotName );
const fills = useSlotFills( slotName );
return (
hasValidFills( fills ) && (
<TotalsWrapper slotWrapper={ true }>

View File

@ -6,7 +6,7 @@ import classnames from 'classnames';
/**
* Internal dependencies
*/
import { createSlotFill, hasValidFills, useSlot } from '../../slot';
import { createSlotFill, hasValidFills, useSlotFills } from '../../slot';
import TotalsWrapper from '../../../components/totals-wrapper';
const slotName = '__experimentalOrderMeta';
@ -15,7 +15,8 @@ const { Fill: ExperimentalOrderMeta, Slot: OrderMetaSlot } =
createSlotFill( slotName );
const Slot = ( { className, extensions, cart, context } ) => {
const { fills } = useSlot( slotName );
const fills = useSlotFills( slotName );
return (
hasValidFills( fills ) && (
<TotalsWrapper slotWrapper={ true }>

View File

@ -3,4 +3,7 @@ export * from './utils';
export * from './slot';
export * from './filter-registry';
export * from './blocks-registry';
export { SlotFillProvider } from 'wordpress-components';
// It is very important to export this directly from the build module to avoid introducing side-effects
// from importing the index of the @wordpress/components package.
export { Provider as SlotFillProvider } from 'wordpress-components-slotfill/build-module/slot-fill';

View File

@ -1,41 +1,22 @@
/**
* External dependencies
*/
import deprecated from '@wordpress/deprecated';
import { CURRENT_USER_IS_ADMIN } from '@woocommerce/settings';
import { Children, cloneElement } from '@wordpress/element';
// It is very important to export this directly from the build module to avoid introducing side-effects
// from importing the index of the @wordpress/components package.
// eslint-disable-next-line -- When adding comments to imports it breaks the external/internal dependencies lint.
import {
createSlotFill as baseCreateSlotFill,
__experimentalUseSlot,
useSlot as __useSlot, //eslint-disable-line
} from 'wordpress-components';
useSlot,
useSlotFills,
} from 'wordpress-components-slotfill/build-module/slot-fill';
/**
* Internal dependencies
*/
import BlockErrorBoundary from '../components/error-boundary';
/**
* This function is used in case __experimentalUseSlot is removed and useSlot is not released, it tries to mock
* the return value of that slot.
*
* @return {Object} The hook mocked return, currently:
* fills, a null array of length 2.
*/
const mockedUseSlot = () => {
/**
* If we're here, it means useSlot was never graduated and __experimentalUseSlot is removed, so we should change our code.
*
*/
deprecated( '__experimentalUseSlot', {
plugin: 'woocommerce-gutenberg-products-block',
} );
// We're going to mock its value
return {
fills: new Array( 2 ),
};
};
/**
* Checks if this slot has any valid fills. A valid fill is one that isn't falsy.
*
@ -45,23 +26,7 @@ const mockedUseSlot = () => {
export const hasValidFills = ( fills ) =>
Array.isArray( fills ) && fills.filter( Boolean ).length > 0;
/**
* A hook that is used inside a slotFillProvider to return information on the a slot.
*
* @param {string} slotName The slot name to be hooked into.
* @return {Object} slot data.
*/
let useSlot;
if ( typeof __useSlot === 'function' ) {
useSlot = __useSlot;
} else if ( typeof __experimentalUseSlot === 'function' ) {
useSlot = __experimentalUseSlot;
} else {
useSlot = mockedUseSlot;
}
export { useSlot };
export { useSlot, useSlotFills };
/**
* Abstracts @wordpress/components createSlotFill, wraps Fill in an error boundary and passes down fillProps.
@ -76,7 +41,7 @@ export const createSlotFill = ( slotName, onError = null ) => {
/**
* A Fill that will get rendered inside associate slot.
* If the code inside has a error, it would be caught ad removed.
* If the code inside has a error, it would be caught and removed.
* The error is only visible to admins.
*
* @param {Object} props Items props.

View File

@ -254,8 +254,13 @@ global.jQuery = () => ( {
global.IntersectionObserver = function () {
return {
root: null,
rootMargin: '',
thresholds: [],
observe: () => void null,
unobserve: () => void null,
disconnect: () => void null,
takeRecords: () => [],
};
};

View File

@ -0,0 +1,4 @@
Significance: minor
Type: dev
Update cart/checkout usage of the @wordpress/components Slot Fill

View File

@ -418,7 +418,6 @@
"node_modules/@woocommerce/e2e-core-tests/CHANGELOG.md",
"node_modules/@woocommerce/api/dist/",
"node_modules/@woocommerce/admin-e2e-tests/build",
"node_modules/@woocommerce/classic-assets/build",
"node_modules/@woocommerce/block-library/build",
"node_modules/@woocommerce/block-library/blocks.ini",
"node_modules/@woocommerce/admin-library/build",

View File

@ -3997,6 +3997,9 @@ importers:
wordpress-components:
specifier: npm:@wordpress/components@14.2.0
version: '@wordpress/components@14.2.0(@types/react@17.0.71)(react-dom@18.3.1(react@18.3.1))(react-with-direction@1.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(reakit-utils@0.15.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(redux@4.2.1)'
wordpress-components-slotfill:
specifier: npm:@wordpress/components@wp-6.5
version: '@wordpress/components@26.0.6(@babel/helper-module-imports@7.22.15)(@babel/types@7.23.6)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)'
optionalDependencies:
ndb:
specifier: 1.1.5
@ -10515,6 +10518,13 @@ packages:
react: ^18.0.0
react-dom: ^18.0.0
'@wordpress/components@26.0.6':
resolution: {integrity: sha512-1e3UY7OCrShVlC3VkX3oolADmQyrybIXNWYki1B0yQk/mBhJXiQTscYmR7UNW2MlOxMM+uOPIvtSfacur7TdWA==}
engines: {node: '>=12'}
peerDependencies:
react: ^18.0.0
react-dom: ^18.0.0
'@wordpress/components@27.5.0':
resolution: {integrity: sha512-RIF1RfBI/SsBYy6wB+DsEfTq24QCLO6Mz+cGTE0mOpiNim2Bi7g9ULlp/gBNRKRuMG3V6hcJklacoMH7gVWk7Q==}
engines: {node: '>=12'}
@ -11321,6 +11331,10 @@ packages:
resolution: {integrity: sha512-P7nxI/bGMDQhtlTfSe1Y2SDfrd20K5UMnTHbq+hmIkzBGRpNPbdGeNu2bZaZtIvmXk1OCR0Fkef+e6QqkOfYPg==}
engines: {node: '>=12'}
'@wordpress/private-apis@0.33.1':
resolution: {integrity: sha512-I7nxWUtZJ243vBC7cRRTId7FK0+c82RlIUZ1DVzutojJlg5a66RfFlMygWg/jVBWEmQqfcGSB4zPiGhi7JVBAg==}
engines: {node: '>=12'}
'@wordpress/private-apis@0.39.0':
resolution: {integrity: sha512-JGn7ngLHjbIWcaRNiZP2githQXcLRYS55UpnWa8WemM5vM/Lfql+mBwo1B9/GVvxiGgTy0K3Fv4SsGhZwMjCMg==}
engines: {node: '>=12'}
@ -25034,9 +25048,9 @@ snapshots:
'@automattic/puppeteer-utils@https://codeload.github.com/Automattic/puppeteer-utils/tar.gz/0f3ec50(react-native@0.73.0(@babel/core@7.23.5)(@babel/preset-env@7.23.6(@babel/core@7.23.5))(encoding@0.1.13)(react@18.3.1))':
dependencies:
'@babel/cli': 7.23.4(@babel/core@7.23.6)
'@babel/core': 7.23.6
'@babel/preset-env': 7.23.6(@babel/core@7.23.6)
'@babel/cli': 7.23.4(@babel/core@7.23.5)
'@babel/core': 7.23.5
'@babel/preset-env': 7.23.5(@babel/core@7.23.5)
'@slack/web-api': 5.15.0
'@wordpress/e2e-test-utils': 3.0.0(jest@24.9.0)(puppeteer@2.1.1)(react-native@0.73.0(@babel/core@7.23.5)(@babel/preset-env@7.23.6(@babel/core@7.23.5))(encoding@0.1.13)(react@18.3.1))
config: 3.3.7
@ -25140,20 +25154,6 @@ snapshots:
'@nicolo-ribaudo/chokidar-2': 2.1.8-no-fsevents.3
chokidar: 3.5.3
'@babel/cli@7.23.4(@babel/core@7.23.6)':
dependencies:
'@babel/core': 7.23.6
'@jridgewell/trace-mapping': 0.3.20
commander: 4.1.1
convert-source-map: 2.0.0
fs-readdir-recursive: 1.1.0
glob: 7.2.3
make-dir: 2.1.0
slash: 2.0.0
optionalDependencies:
'@nicolo-ribaudo/chokidar-2': 2.1.8-no-fsevents.3
chokidar: 3.5.3
'@babel/code-frame@7.12.11':
dependencies:
'@babel/highlight': 7.23.4
@ -29240,6 +29240,12 @@ snapshots:
react: 17.0.2
react-dom: 17.0.2(react@17.0.2)
'@floating-ui/react-dom@2.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
'@floating-ui/dom': 1.5.3
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
'@floating-ui/utils@0.1.6': {}
'@gar/promisify@1.1.3': {}
@ -38905,6 +38911,67 @@ snapshots:
- babel-plugin-macros
- vite
'@wordpress/components@26.0.6(@babel/helper-module-imports@7.22.15)(@babel/types@7.23.6)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
'@ariakit/react': 0.3.14(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@babel/runtime': 7.23.6
'@emotion/cache': 11.11.0
'@emotion/css': 11.11.2
'@emotion/react': 11.11.1(@types/react@17.0.71)(react@18.3.1)
'@emotion/serialize': 1.1.2
'@emotion/styled': 11.11.0(@emotion/react@11.11.1(@types/react@17.0.71)(react@18.3.1))(@types/react@17.0.71)(react@18.3.1)
'@emotion/utils': 1.2.1
'@floating-ui/react-dom': 2.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@types/gradient-parser': 0.1.3
'@types/highlight-words-core': 1.2.1
'@use-gesture/react': 10.3.0(react@18.3.1)
'@wordpress/a11y': 3.57.0
'@wordpress/compose': 6.34.0(react@18.3.1)
'@wordpress/date': 4.57.0
'@wordpress/deprecated': 3.57.0
'@wordpress/dom': 3.57.0
'@wordpress/element': 5.34.0
'@wordpress/escape-html': 2.57.0
'@wordpress/hooks': 3.57.0
'@wordpress/html-entities': 3.57.0
'@wordpress/i18n': 4.57.0
'@wordpress/icons': 9.48.0
'@wordpress/is-shallow-equal': 4.57.0
'@wordpress/keycodes': 3.57.0
'@wordpress/primitives': 3.55.0
'@wordpress/private-apis': 0.33.1
'@wordpress/rich-text': 6.34.0(react@18.3.1)
'@wordpress/warning': 2.57.0
change-case: 4.1.2
classnames: 2.3.2
colord: 2.9.3
date-fns: 2.30.0
deepmerge: 4.3.1
dom-scroll-into-view: 1.2.1
downshift: 6.1.12(react@18.3.1)
fast-deep-equal: 3.1.3
framer-motion: 10.16.16(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
gradient-parser: 0.1.5
highlight-words-core: 1.2.2
is-plain-object: 5.0.0
memize: 2.1.0
path-to-regexp: 6.2.1
re-resizable: 6.9.11(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
react: 18.3.1
react-colorful: 5.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
react-dom: 18.3.1(react@18.3.1)
remove-accents: 0.5.0
use-lilius: 2.0.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
uuid: 9.0.1
valtio: 1.7.0(@babel/helper-module-imports@7.22.15)(@babel/types@7.23.6)(babel-plugin-macros@3.1.0)(react@18.3.1)
transitivePeerDependencies:
- '@babel/helper-module-imports'
- '@babel/types'
- '@types/react'
- aslemammad-vite-plugin-macro
- babel-plugin-macros
- vite
'@wordpress/components@27.5.0(@types/react@17.0.71)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)':
dependencies:
'@ariakit/react': 0.3.14(react-dom@17.0.2(react@17.0.2))(react@17.0.2)
@ -41126,6 +41193,10 @@ snapshots:
dependencies:
'@babel/runtime': 7.23.6
'@wordpress/private-apis@0.33.1':
dependencies:
'@babel/runtime': 7.23.6
'@wordpress/private-apis@0.39.0':
dependencies:
'@babel/runtime': 7.23.6
@ -60493,6 +60564,12 @@ snapshots:
react: 17.0.2
react-dom: 17.0.2(react@17.0.2)
use-lilius@2.0.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
date-fns: 3.6.0
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
use-memo-one@1.1.3(react@17.0.2):
dependencies:
react: 17.0.2