Add a cart and checkout to your application, on the payments provider it already uses.
Syntax
$ vela enable ecommerceOptions
--provider <provider>- Optional. The cart follows the project’s payments provider, so this only confirms it; a different provider is refused.
Run vela enable payments first. It adds the cart and nothing to sell: vela generate shop writes a product listing and product pages, or put <AddToCart> on pages of your own. It refuses to run twice; the cart’s files are yours to edit, and vela disable ecommerce starts over.
What you get
- A cart button in the navbar, left of the account menu when auth is enabled. It opens the cart in a sheet.
src/lib/cart.svelte.ts- The cart, a module-level store any component can import. It lives in the browser: the server renders an empty cart, and it fills in after the page loads.src/lib/components/cart/add-to-cart.svelte- Put<AddToCart>on the pages that sell things.
Each provider’s cart is the code you would write for that provider alone. Nothing in it is shared between them. Prices are formatted for the page’s language in the business’s country, and when the site offers other currencies the cart shows them as estimates marked ≈; the total is always charged in the business’s currency.
Stripe
Stripe has no cart object, so the cart is a list of Stripe prices kept in localStorage. <AddToCart> takes the price as the page selling it loaded it:
<AddToCart price={{ price: 'price_...', name: 'T-shirt', unitAmount: 2500, currency: 'usd' }} />Checkout is Stripe Checkout. The cart posts its prices and quantities to the checkout action of /cart, which creates a Checkout Session and redirects to it. Stripe prices the session itself, so nothing stored in the browser can change what is charged. The session allows promotion codes; payment methods, tax and shipping are set in your Stripe dashboard. With auth, a signed-in buyer checks out as their Stripe customer.
/cart- The full cart, and the checkout action./checkout/success- Where Stripe sends the buyer back. It shows the amount paid and empties the cart.
Shopify
Shopify has a cart of its own, so the browser keeps only its id, and the store holds the cart as the Storefront API returns it: lines, costs and checkoutUrl. <AddToCart> takes a product variant, and optionally line item properties:
<AddToCart merchandiseId="gid://shopify/ProductVariant/..." />Checkout is a link to the cart’s checkoutUrl, Shopify’s own checkout. There are no server routes, so the cart works on a static site.
The cart is a list of items kept in localStorage, and checkout is a WhatsApp chat with the business. <AddToCart> takes your own id for the item, its name and, optionally, a price in the business’s currency (site.currency, set when you enabled payments), written the way you would write it:
<AddToCart id="concha" name="Concha" price={12} />
<AddToCart id="birthday-cake" name="Birthday cake" />The sheet shows a subtotal when every item has a price. Otherwise it says the total will be confirmed in WhatsApp. To check out, the customer gives a name, a phone number and an optional note. The chat then opens with the order written out, using orderMessage from src/lib/order.ts, and the order is recorded to the hosted form in PUBLIC_WHATSAPP_ORDER_FORM (see payments). The sheet keeps the order’s reference and a link to open the chat again until the customer presses Done; adding an item starts the next order. There are no server routes, so the cart works on a static site.