GraphCommerce's plugin system allows you to extend GraphCommerce's built-in components or functions with your own logic.
A plugin is a way to modify React Components or a Function by wrapping them, without having to modify the code directly.
For the M2 people: Think of around plugins, but without configuration files and no performance penalty.
GraphCommerce has two kinds of plugins, React Component plugins and Function
React Component plugins, which can be used to:
Function plugins, which can be used to:
In this example we're going to add some text to list items, just like the text ‘BY GC’ that can seen in the demo on category pages.
Create a new file in /plugins/ProductListItemByGC.tsx
with the following
contents:
import type { ProductListItem } from '@graphcommerce/magento-product'
import type { ReactPlugin } from '@graphcommerce/next-config'
import { Typography } from '@mui/material'
export const component = 'ProductListItem' // Component to extend, required
export const exported = '@graphcommerce/magento-product' // Location where the component is exported, required
const ListPlugin: ReactPlugin<typeof ProductListItem> = (props) => {
// Prev in this case is ProductListItem, you should be able to see this if you log it.
const { Prev, ...rest } = props
return (
<Prev
{...rest}
subTitle={
<Typography component='span' variant='caption'>
Plugin!
</Typography>
}
/>
)
}
export const Plugin = ListPlugin // An export with the name Plugin, required
Trigger the 'interceptor generation' so GraphCommerce knows of the existence
of your plugin. To enable: Modify the page that you expect the plugin to
occur on. In this case modify pages/[...url].tsx
by adding a few linebreaks
and save the file
If everything went as expected you should see Plugin!
below the product
name. If that doesn't work try restarting the dev server.
Happy programming!
You can enable debug mode in your graphcommerce.config.js:
const config = {
debug: {
pluginStatus: true,
},
}
After the creation of the plugin file GraphCommerce will create an interceptor
file to load you plugin. To see what has happened, open the
node_modules/@graphcommerce/magento-product/index.interceptor.tsx
and you
should see something like:
export * from '.'
import { Plugin as AwesomeProductListItem } from '../../examples/magento-graphcms/plugins/AwesomeProductListItem'
import { ComponentProps } from 'react'
import { ProductListItem as ProductListItemBase } from '.'
/**
* Interceptor for `<ProductListItem/>` with these plugins:
*
* - `../../examples/magento-graphcms/plugins/AwesomeProductListItem`
*/
type ProductListItemProps = ComponentProps<typeof ProductListItemBase>
function AwesomeProductListItemInterceptor(props: ProductListItemProps) {
return <AwesomeProductListItem {...props} Prev={ProductListItemBase} />
}
export const ProductListItem = AwesomeProductListItemInterceptor
If you read the interceptor file from the bottom up, you see:
ProductListItem
is replaced with
AwesomeProductListItemInterceptor
AwesomeProductListItemInterceptor
is a react component which renders
AwesomeProductListItem
with a Prev
prop.AwesomeProductListItem
is the plugin you just created.Prev
is the original ProductListItem
(renamed to ProductListItemBase
)ProductListItemProps
are the props of the original ProductListItem
and
thus your plugin is automatically validated by TypeScript.So in conclusion, a plugin is a react component that renders the original
component with a Prev
prop. The Prev
prop is the original component.
When opening the React debugger you can see the plugin wrapped.
GraphCommerce uses a custom Webpack plugin to load the plugins. The plugin does
a glob search for plugin folders in each GraphCommerce related pacakge:
${packageLocation}/plugins/**/*.{ts|tsx}
Package locations are the root and all packages with graphcommerce
in the name
(This means all @graphcommerce/*
packages and
@your-company/graphcommerce-plugin-name
)
The Webpack plugin statically analyses the plugin file to find component
,
exported
and ifConfig
and extracts that information.
In the examples above we've extended the product list items, but it should also work for other things such as:
Provide an ifConfig export in the plugin that will only include the plugin if a configuration value is truthy.
import type { IfConfig } from '@graphcommerce/next-config'
export const ifConfig: IfConfig = 'googleAnalytics'
A plugin is injected later than the dependencies of the package. So if a plugin is loaded to early, make sure the package has a dependency on the other package.