-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Description
Background
We are building a Vendure storefront that is both flexible and developer-friendly.
Our goal is to provide a solid foundation that developers can easily build upon, while drastically reducing the starting friction and the time it takes to go from concept to minimum viable product (MVP).
This would also provide a fully functional demo that can be installed using 1 create command.
But to do that, we need to make the right choices about how we distribute the UI components.
The goal is to ensure we’re building something that works for both developers who want simplicity and provide reasonable flexibility when it comes to customization.
With our current proposals that would have certain trade-offs and ultimately result in either something that is requires less maintenance overhead but is more opinionated and would require more effort while customizing components, or something that will require more maintenance but wouldn’t force you into any “defaults”.
Proposals:
We have two options that we that we would like to propose.
Both of these approaches would include an SDK, similar to the one proposed by @michaelbromley in this issue: #2621
The component distribution is where these 2 approaches differ.
Option 1: NPM Package Distribution
Traditional npm package that developers install and import.
This is the more opinionated and lower maintenance approach.
Pros:
- Familiar workflow - standard npm install
- Automatic updates - bug fixes delivered through package updates
- Smaller bundle size - external dependencies
- Version management with semantic versioning
Cons:
- Less customization - harder to modify internals
- Dependency management overhead
- Breaking changes require migration
- May need separate packages for different frameworks
- Component internals "hidden" from developers
Example Workflow
1. Install the Starter Storefront
Create a new Vite-based storefront that includes the pre-built components and hooks:
npx @vendure/create my-shop --with-vite-storefront
cd my-shop
npm run dev
File structure:
my-shop
└─ apps
└─ vendure
└─ storefront/
├── package.json # @vendure/storefront-ui dependency
├── src/
│ ├── pages/ # Uses imported components, custom or prebuilt
│ ├── components/ # Only custom components - made by user
│ └── lib/
└── node_modules/
└── @vendure/storefront-ui/ # Pre-built components live here
2. Modify Components
Since the components are imported from the NPM package, customization is limited to props or Tailwind classes.
// src/pages/all-products.tsx
const products = // fetch from Vendure
const page = 1
function handlePageChange(page: string) {
// refetch products with new page
}
// all of the props would have to be "hard-coded" in the NPM component package
<ProductGrid page={page} onPageChange={(page) => handlePageChange(page)}>
{products.map((product) => (
<ProductCard product={product} />
))}
</ProductGrid>;
3. Update Components
To get the latest updates or bug fixes, update the NPM package:
npm update @vendure/storefront-ui
# or update your package.json
This would require no further maintenance, unless it would be a version with breaking changes.
4. No Internal Modifications
Developers cannot modify the internal logic or structure of the components. They can only use the exposed props and Tailwind classes for customization.
Option 2: shadcn Registry Distribution
Components distributed through shadcn-style registry - copies code directly into your project.
This would require more maintenance but offers infinite customizability of already built components.
Pros:
- Full customization - complete source code access
- No external dependencies - components in your codebase
- Framework agnostic - same components work across React-based meta frameworks
- Familiar to developers - shadcn/ui has widespread adoption
- Gradual adoption - install only needed components
- No version conflicts
Cons:
- Manual updates - developers must sync improvements manually
- Maintenance burden on developers
- Code duplication across projects
- Consistency challenges
Example Workflow
1. Install the Starter Storefront
Create a new Vite-based storefront that includes the components copied from the shadcn registry:
npx @vendure/create my-shop --with-vite-storefront
cd my-shop
npm run dev
File structure:
my-shop
└─ apps
└─ vendure
└─ storefront/
├── package.json # No vendure *component* dependencies
└── src/
├── pages/ # Uses local components
├── components/
│ └── vendure/ # Vendure components (copied from registry)
├── hooks/ # All hooks (copied from registry)
└── lib/
2. Modify Components (Full Control)
Since the components are copied directly into the project, developers have full access to the source code and can modify them as needed.
Example: Adding pagination functionality
A developer can open the ProductGrid
component file and add new props and UI elements for pagination. This level of direct modification is the key benefit of this approach.
// src/components/vendure/product-grid.tsx
export function ProductGrid({
children,
page,
onPageChange,
}: ProductGridParams) {
return (
<div>
{/* The developer has complete freedom to change the component. */}
<div className="grid grid-cols-3 gap-6">{children}</div>
{/* They can add pagination controls directly into the component */}
<div className="mt-4 flex justify-center gap-2">
<button onClick={() => onPageChange(page - 1)}>Previous</button>
<span>Page {page}</span>
<button onClick={() => onPageChange(page + 1)}>Next</button>
</div>
</div>
);
}
This modified component is then used on the page. The usage looks identical to the NPM example, but the components are now local and not part of the node_modules
and fully controlled by the developer.
// src/pages/all-products.tsx
const products = []; // fetch from Vendure
const page = 1
function handlePageChange(page: number) {
// refetch products with new page
}
<ProductGrid page={page} onPageChange={(page) => handlePageChange(page)}>
{products.map((product) => (
<ProductCard product={product} />
))}
</ProductGrid>;
3. Manual Updates
To sync updates from the registry, re-install the component:
npx shadcn@latest add http://storefront-registry.vendure.io/r/product-grid.json
This would completely overwrite your components, then you would have to compare the updated components with the git diff
of what was overwritten and re-add your custom code.
4. Full-access to customization
Developers have full control over the component internals, including logic, structure, and styling. They can rewrite or extend components as needed.
Feedback questions:
- Which distribution method would you prefer?
- NPM package for easy installation and updates.
- shadcn registry for full customization control but a bit more involved updating process.
- What level of customization do you typically need?
- Basic theming and styling
- Component behavior modifications
- Complete component rewrites
- How important are automatic updates vs. stability?
Metadata
Metadata
Assignees
Labels
Type
Projects
Status