Skip to main content

Vendure Plugin Configs

Framework for creating and sharing plugin configurations for Vendure-based storefronts. Plugin configs allow you to extend the Vendure SDK with new features, queries, and type-safe entity augmentations—only when you import the plugin.

Note: These plugin configurations only work if you have the corresponding Vendure plugins installed on your backend. The plugin configs provided here are client-side configurations that enable integration with existing Vendure plugins. If you need help setting up Vendure plugins or have questions about plugin compatibility, please contact the Haus Tech Team for more information.

Purpose

This library provides pre-configured plugin setups for the Vendure e-commerce platform, including badge management, campaign handling, elastic search integration, package size features, product popularity tracking, product variant specifications, and purchase order payment. It simplifies the integration of Vendure plugins with the Haus Storefront Components ecosystem. Plugin configs encapsulate feature functions, query/request extensions, and optional type augmentation for Vendure entities.

Features

  • Plugin Management: Easy configuration and initialization of Vendure plugins
  • Feature Toggles: Dynamic enabling/disabling of plugin features
  • Query Updates: Automatic GraphQL query updates for plugin data
  • Settings Management: Centralized plugin settings configuration
  • Provider Integration: Support for custom providers and components
  • Type Augmentation: Opt-in type extensions for Vendure entities (only active when plugin is imported)
  • Pre-configured Plugins: Badge, Campaign, Elastic Search, Package Size, Related Products, Product Popularity, Product Variant Specifications, and Purchase Order Payment plugins

Installation

npm install @haus-storefront-react/vendure-plugin-configs

Note: This is not a public package. Contact the Haus Tech Team for access.

API Reference

Products by SKU

Plugin config that adds productVariantsBySkus to the Vendure SDK, enabling lookup of product variants by SKU. Use with the Quick Order component to resolve identifiers (e.g. SKUs) to variant IDs before adding to the order.

Exports

ExportTypeDescription
VendureProductsBySkuPluginVendurePluginConfigPlugin config to add to DataProvider pluginConfigs
quickOrderVariantSkuValidationStrategy() => QuickOrderVariantValidationStrategyCreates a validation strategy for QuickOrder CSV/Manual modes. Resolves SKUs to variant IDs via productVariantsBySkus. Use with QuickOrder.CSV.Root or QuickOrder.Manual.Root when the plugin is enabled.
ProductVariantBySkuResulttypeResult type for productVariantsBySkus (variant IDs and error results)
SdkWithProductsBySkuinterfaceSDK with productVariantsBySkus: (skus: string[]) => Promise<ProductVariantBySkuResult>

ProductVariantSpecification

Key-value pair for product variant specifications (e.g. "Weight: 2.5 kg"). Matches the struct custom field defined by ProductVariantSpecificationsPlugin on the Vendure backend. Access via productVariant.customFields.specifications.

Interface

interface ProductVariantSpecification {
key: string
value: string
}

VendureProductVariantSpecificationsPlugin

Storefront plugin config for ProductVariantSpecificationsPlugin. Adds specifications (key-value pairs) to product variant queries. Add to pluginConfigs without calling init()—it has no features to configure.

VendurePluginConfig

The base class for all Vendure plugin configurations. Manages plugin state, features, query updates, requests, providers, and settings.

Signature

class VendurePluginConfig<
Features extends PluginFeatures = PluginFeatures,
R extends Record<string, (...args: any[]) => any> = Record<string, (...args: any[]) => any>,
S extends PluginSettings = PluginSettings,
T extends IGraphQLSDK = IGraphQLSDK
> implements IVendurePluginConfig<Features, R, S, T>

Constructor

constructor(config: VendurePluginConfigInput<Features, R, S>)

Constructor Parameters

ParameterTypeRequiredDescription
config.namestringYesThe plugin name identifier
config.enabledbooleanNoWhether the plugin is enabled (default: true)
config.enableFeaturesPartial<Record<keyof Features, boolean>> | Partial<Features>NoFeature configuration object
config.queryUpdatesBuilderQueryUpdatesYesGraphQL query field updates
config.requestsRNoCustom request methods
config.providersProviderDataMapNoCustom providers array
config.settingsSNoPlugin-specific settings

Methods

MethodSignatureDescription
init(config: { enableFeatures?: Partial<Record<keyof Features, boolean>> | Partial<Features> | Array<keyof Features>; settings?: S }) => VendurePluginConfig<Features, R, S, T>Initializes the plugin configuration with a specified set of features. Allows dynamically setting features that should be enabled. Returns the current instance enabling method chaining.
setSdk(sdk: T) => voidSets the GraphQL SDK instance
getSdk() => TGets the GraphQL SDK instance
getName() => stringGets the plugin name
isEnabled() => booleanChecks if the plugin is enabled
getEnabled() => booleanGets the enabled state
setEnabled(enabled: boolean) => voidSets the enabled state
setEnableFeatures(enableFeatures: Partial<Record<keyof Features, boolean>> | Partial<Features>) => voidSets the enabled features
getEnabledFeatures() => Partial<Record<keyof Features, boolean>>Gets the enabled features
setQueryUpdates(queryUpdates: BuilderQueryUpdates) => voidSets the query updates
getQueryUpdates() => BuilderQueryUpdatesGets the query updates
setRequests(requests: R) => voidSets the custom requests
getRequests() => RGets the custom requests
setProviders(providers: ProviderDataMap) => voidSets the custom providers
getProviders() => ProviderDataMapGets the custom providers array
setSettings(settings: S) => voidSets the plugin settings
getSettings() => SGets the plugin settings
onSdkReady(sdk: T) => void | Promise<void>Optional callback function that is called when the SDK is set. Use this to perform initialization that requires SDK access, such as dynamically building query updates based on SDK data.

useRelatedProducts

React Query hook for loading related products for a product. The hook calls sdk.relatedProducts(input) and is enabled when input.id is present.

Signature

useRelatedProducts(input: RelatedProductsInput)

Parameters

ParameterTypeRequiredDescription
inputRelatedProductsInputYesRequest payload containing the source product id and optional filters

RelatedProductsInput

FieldTypeRequiredDescription
idstringYesProduct id used to load related products
takenumberNoMaximum number of related products to return
facetIdsstring[]NoOptional facet ids used to further filter related results

VendureRelatedProductsPlugin

Pre-configured plugin that extends the product query with relatedProductIds and registers the relatedProducts(input) SDK request.

Adds to Product

FieldTypeDescription
relatedProductIdsstring[]Related product ids returned on product data

Adds to SDK

MethodSignatureDescription
relatedProducts(input: RelatedProductsInput) => Promise<Product[]>Fetches related products for a product

Basic Usage

Using a Pre-configured Plugin

import { VendureBadgePlugin } from '@haus-storefront-react/vendure-plugin-configs/badge'
import { DataProvider } from '@haus-storefront-react/core'

function App() {
return (
<DataProvider
provider='vendure'
options={{
apiUrl: 'https://your-vendure-instance.com/shop-api',
vendureToken: 'your-channel-token',
pluginConfigs: [
VendureBadgePlugin.init({
enableFeatures: ['showBadges'],
}),
],
}}
>
{/* Your app components */}
</DataProvider>
)
}

Using Products by SKU with Quick Order

Add VendureProductsBySkuPlugin to your DataProvider and use quickOrderVariantSkuValidationStrategy() with Quick Order to resolve SKUs to variant IDs. The strategy uses the plugin's SDK internally (no need to pass the SDK).

import { VendureProductsBySkuPlugin, quickOrderVariantSkuValidationStrategy } from '@haus-storefront-react/vendure-plugin-configs/products-by-sku'
import { QuickOrder } from '@haus-storefront-react/quick-order'
import { DataProvider } from '@haus-storefront-react/core'

const skuStrategy = quickOrderVariantSkuValidationStrategy()

function App() {
return (
<DataProvider
provider='vendure'
options={{
apiUrl: 'https://your-vendure-instance.com/shop-api',
vendureToken: 'your-channel-token',
pluginConfigs: [VendureProductsBySkuPlugin],
}}
>
<QuickOrderPage />
</DataProvider>
)
}

function QuickOrderPage() {
return (
<QuickOrder.Root onSuccess={(r) => console.log(r)} onError={(e) => console.error(e)}>
{({ isLoading }) => (
<QuickOrder.Manual.Root validationStrategy={skuStrategy} initialRows={1}>
{({ rows, getValidRows }) => (
<>
{rows.map((row) => (
<QuickOrder.Manual.Row key={row.id} row={row}>
<div>
<QuickOrder.Manual.Row.IdentifierInput placeholder="SKU" />
<QuickOrder.Manual.Row.QuantityInput type="number" min={1} />
<QuickOrder.Manual.Row.RemoveButton>Remove</QuickOrder.Manual.Row.RemoveButton>
</div>
</QuickOrder.Manual.Row>
))}
<QuickOrder.Manual.AddRowButton>Add row</QuickOrder.Manual.AddRowButton>
<QuickOrder.Manual.SubmitButton>
{isLoading ? 'Adding...' : `Add ${getValidRows().length} item(s)`}
</QuickOrder.Manual.SubmitButton>
</>
)}
</QuickOrder.Manual.Root>
)}
</QuickOrder.Root>
)
}

Using Product Variant Specifications Plugin

The Product Variant Specifications plugin extends product variants with key-value specifications (e.g. "Weight: 2.5 kg"). Requires ProductVariantSpecificationsPlugin on the Vendure backend. Specifications are available at productVariant.customFields.specifications.

import { VendureProductVariantSpecificationsPlugin } from '@haus-storefront-react/vendure-plugin-configs/product-variant-specifications'
import { DataProvider } from '@haus-storefront-react/core'

function App() {
return (
<DataProvider
provider='vendure'
options={{
apiUrl: 'https://your-vendure-instance.com/shop-api',
vendureToken: 'your-channel-token',
pluginConfigs: [
VendureProductVariantSpecificationsPlugin,
],
}}
>
{/* Your app components */}
</DataProvider>
)
}

Accessing specifications in your components:

import type { ProductVariantSpecification } from '@haus-storefront-react/vendure-plugin-configs/product-variant-specifications'
import { Product } from '@haus-storefront-react/shared-types'

function VariantSpecs({ variant }: { variant: Product['variants'][number] }) {
const specs = variant?.customFields?.specifications as ProductVariantSpecification[] | undefined
if (!specs?.length) return null

return (
<dl>
{specs.map(({ key, value }) => (
<div key={key}>
<dt>{key}</dt>
<dd>{value}</dd>
</div>
))}
</dl>
)
}

Using ProductBadge Component

import { ProductBadge } from '@haus-storefront-react/vendure-plugin-configs/badge'
import { Product } from '@haus-storefront-react/shared-types'

function ProductCard({ product }: { product: Product }) {
return (
<div className='product-card'>
<img src={product.featuredAsset?.preview} alt={product.name} />

<ProductBadge.Root product={product}>
{({ groupedBadges }) => (
<ProductBadge.Group position='top-left'>
{({ badges }) => (
<>
{badges.map((badge) => (
<ProductBadge.Item key={badge.id}>
<ProductBadge.Image badge={badge} />
</ProductBadge.Item>
))}
</>
)}
</ProductBadge.Group>
)}
</ProductBadge.Root>

<h3>{product.name}</h3>
</div>
)
}
import { DataProvider } from '@haus-storefront-react/core'
import { VendureRelatedProductsPlugin } from '@haus-storefront-react/vendure-plugin-configs/related-products'

function App() {
return (
<DataProvider
provider='vendure'
options={{
apiUrl: 'https://your-vendure-instance.com/shop-api',
vendureToken: 'your-channel-token',
pluginConfigs: [VendureRelatedProductsPlugin.init({})],
}}
>
{/* Your app components */}
</DataProvider>
)
}
import { useRelatedProducts } from '@haus-storefront-react/vendure-plugin-configs/related-products'

function RelatedProducts({ productId }: { productId: string }) {
const { data: products, isLoading, error } = useRelatedProducts({
id: productId,
take: 4,
})

if (isLoading) return <p>Loading related products...</p>
if (error) return <p>Failed to load related products.</p>
if (!products?.length) return null

return (
<ul>
{products.map((product) => (
<li key={product.id}>{product.name}</li>
))}
</ul>
)
}

Accessing relatedProductIds on Product Data

When VendureRelatedProductsPlugin is registered, the product query is extended with relatedProductIds, and the Product type is augmented accordingly.

import { Product } from '@haus-storefront-react/shared-types'

function ProductDebug({ product }: { product: Product }) {
return <pre>{JSON.stringify(product.relatedProductIds ?? [], null, 2)}</pre>
}

Advanced Usage

Dynamic Plugin Management

import { useState, useEffect } from 'react'
import { VendurePluginConfig } from '@haus-storefront-react/vendure-plugin-configs'
import { VendureBadgePlugin } from '@haus-storefront-react/vendure-plugin-configs/badge'
import { VendureCampaignPlugin } from '@haus-storefront-react/vendure-plugin-configs/campaign'

function PluginManager() {
const [plugins, setPlugins] = useState<VendurePluginConfig[]>([])

useEffect(() => {
const badgePlugin = VendureBadgePlugin.init({
enableFeatures: ['showBadges'],
})

const campaignPlugin = VendureCampaignPlugin.init({
enableFeatures: ['showCampaignPrices'],
})

setPlugins([badgePlugin, campaignPlugin])
}, [])

const togglePlugin = (pluginName: string) => {
setPlugins((prev) =>
prev.map((plugin) => {
if (plugin.getName() === pluginName) {
plugin.setEnabled(!plugin.isEnabled())
}
return plugin
}),
)
}

return (
<div className='plugin-manager'>
<h2>Plugin Management</h2>
{plugins.map((plugin) => (
<div key={plugin.getName()} className='plugin-item'>
<h3>{plugin.getName()}</h3>
<label>
<input
type='checkbox'
checked={plugin.isEnabled()}
onChange={() => togglePlugin(plugin.getName())}
/>
Enabled
</label>
</div>
))}
</div>
)
}

Custom Plugin with Requests and Settings

import { VendurePluginConfig } from '@haus-storefront-react/vendure-plugin-configs'
import { PaginatedList, ErrorResult } from '@haus-storefront-react/shared-types'

interface CustomFeatures {
processData: (props: { data: string }) => string
}

interface CustomRequests {
fetchCustomData: () => Promise<PaginatedList<any> | ErrorResult>
}

interface CustomSettings {
apiEndpoint: string
timeout: number
retries: number
}

const CustomPlugin = new VendurePluginConfig<
CustomFeatures,
CustomRequests,
CustomSettings
>({
name: 'custom',
enabled: true,
enableFeatures: {
processData: ({ data }) => `Processed: ${data}`,
},
queryUpdates: {
products: {
fields: ['id', 'name'],
},
},
requests: {
fetchCustomData: async () => {
const sdk = CustomPlugin.getSdk()
// Use SDK to fetch data
return {
items: [],
totalItems: 0,
}
},
},
settings: {
apiEndpoint: 'https://api.example.com',
timeout: 5000,
retries: 3,
},
// onSdkReady callback is called when SDK is set by DataProvider
// Use this to perform initialization that requires SDK access
onSdkReady: async (sdk) => {
// Example: Fetch custom fields from API and update query updates dynamically
// const customFields = await sdk.createRequest(...)
// CustomPlugin.setQueryUpdates({ ... })

// Example: Set up requests that depend on SDK after it's ready
// CustomPlugin.setRequests({ ... })
},
})

// Update settings dynamically
CustomPlugin.setSettings({
apiEndpoint: 'https://new-api.example.com',
timeout: 10000,
retries: 5,
})

Conditional Rendering with Plugin Features

import { ProductBadge } from '@haus-storefront-react/vendure-plugin-configs/badge'
import { Product } from '@haus-storefront-react/shared-types'
import { VendureBadgePlugin } from '@haus-storefront-react/vendure-plugin-configs/badge'

function ProductDisplay({ product }: { product: Product }) {
const badgePlugin = VendureBadgePlugin.init({
enableFeatures: ['showBadges'],
})

if (!badgePlugin.isEnabled()) {
return (
<div className='product'>
<img src={product.featuredAsset?.preview} alt={product.name} />
<h3>{product.name}</h3>
</div>
)
}

return (
<div className='product'>
<img src={product.featuredAsset?.preview} alt={product.name} />

{product.badges && product.badges.length > 0 && (
<ProductBadge.Root product={product}>
{({ groupedBadges, positions }) => (
<div className='badges'>
{positions.map((position) => (
<ProductBadge.Group key={position} position={position}>
{({ badges }) => (
<>
{badges.map((badge) => (
<ProductBadge.Item key={badge.id}>
<ProductBadge.Image badge={badge} />
</ProductBadge.Item>
))}
</>
)}
</ProductBadge.Group>
))}
</div>
)}
</ProductBadge.Root>
)}

<h3>{product.name}</h3>
</div>
)
}

Using onSdkReady Callback

The onSdkReady callback is called automatically when the SDK is set by the DataProvider. Use this to perform initialization that requires SDK access, such as dynamically building query updates based on SDK data or setting up requests that depend on the SDK.

import { VendurePluginConfig } from '@haus-storefront-react/vendure-plugin-configs'
import type { BuilderQueryUpdates } from '@haus-storefront-react/shared-types'

// Example: Plugin that dynamically builds query updates based on custom fields
// from window.hausStorefront.customFields (loaded after plugin initialization)
const CustomFieldsPlugin = new VendurePluginConfig({
name: 'custom-fields',
queryUpdates: {}, // Empty initially, will be populated in onSdkReady
onSdkReady: async (sdk) => {
// Access window data that may not be available at plugin creation time
const customFields = window.hausStorefront?.customFields || {}

// Build query updates dynamically based on available custom fields
const queryUpdates: BuilderQueryUpdates = {}

if (customFields.Product?.length > 0) {
queryUpdates.product = {
fields: [
{ customFields: customFields.Product.map(f => f.name) }
]
}
}

// Update the plugin's query updates
CustomFieldsPlugin.setQueryUpdates(queryUpdates)
},
})

// Example: Plugin that fetches configuration from API and updates queries
const DynamicConfigPlugin = new VendurePluginConfig({
name: 'dynamic-config',
queryUpdates: {},
onSdkReady: async (sdk) => {
try {
// Fetch configuration from API using SDK
const config = await sdk.createRequest(
{
operation: 'getPluginConfig',
fields: ['customFields', 'enabledFeatures'],
},
{},
false
)

// Update query updates based on API response
if (config.data?.customFields) {
DynamicConfigPlugin.setQueryUpdates({
product: {
fields: config.data.customFields,
},
})
}
} catch (error) {
console.error('Failed to load plugin configuration:', error)
}
},
})

Made with ❤️ by Haus Tech Team