Modern JavaScript in Ecommerce: ES Modules, Async/Await
Learn modern JavaScript features for ecommerce development: ES modules, async/await, destructuring, and more. Compare with limited Liquid template capabilities.

Modern JavaScript Ecommerce: The Complete Technology Guide
Master the latest JavaScript technologies for ecommerce development: React 19, React Router v7, TypeScript, and the visual editing layer that completes the modern stack.
The JavaScript Revolution in Ecommerce
From Legacy JavaScript to Modern Framework Architecture
JavaScript has evolved from simple DOM manipulation to sophisticated application architecture. Modern ecommerce development leverages React 19, TypeScript, and advanced bundling - but the ecosystem was missing one critical piece...
Visual editing for React components. Enter Weaverse.
The Modern JavaScript Stack for Ecommerce
| Feature | ||
|---|---|---|
Framework | React 19 with Compiler, React Router v7 | jQuery, basic React, or vanilla JavaScript |
Type Safety | TypeScript with strict inference | Untyped JavaScript, runtime errors |
Bundling | Vite with automatic optimization | Webpack with manual configuration |
State Management | React 19 built-ins, Preact Signals | Redux, MobX, or global variables |
Visual Editing | Weaverse for React components | No visual editing for JavaScript apps |
React 19: The Ecommerce Game Changer
Server Components and Performance
React 19 Server Components revolutionize ecommerce performance by moving computations to the server:
// ProductCatalog.tsx - Server Component (zero client JavaScript)
import { Suspense } from 'react'
import { getProducts, getCollections } from '~/lib/shopify'
// This component runs on the server, no client bundle impact
async function ProductCatalog({ collectionId }: { collectionId: string }) {
// Data fetching happens on server
let [products, collections] = await Promise.all([
getProducts({ collectionId, limit: 20 }),
getCollections({ limit: 10 })
])
return (
<div className="product-catalog">
<CollectionNav collections={collections} />
<Suspense fallback={<ProductGridSkeleton />}>
<ProductGrid products={products} />
</Suspense>
<Suspense fallback={<FiltersSkeleton />}>
<ProductFilters collectionId={collectionId} />
</Suspense>
</div>
)
}
// Client Components only for interactivity
'use client'
function ProductFilters({ collectionId }: { collectionId: string }) {
let [filters, setFilters] = useState({})
let [isPending, startTransition] = useTransition()
// Only interactive logic runs on client
return (
<FilterPanel
filters={filters}
onFilterChange={(newFilters) => {
startTransition(() => {
setFilters(newFilters)
// Trigger server-side re-render
})
}}
/>
)
}
// Weaverse schema for visual editing
export let schema = createSchema({
type: 'product-catalog',
title: 'Product Catalog',
settings: [
{
group: 'Collection',
inputs: [
{
type: 'collection',
name: 'collectionId',
label: 'Collection',
}
]
}
]
})Concurrent Features and UX
React 19's concurrent features enable sophisticated ecommerce UX patterns:
// ShoppingCart.tsx - React 19 Concurrent Features
import { useOptimistic, useTransition, use } from 'react'
import { addToCart, removeFromCart } from '~/lib/cart-actions'
function ShoppingCart() {
let [isPending, startTransition] = useTransition()
// Optimistic updates - show changes immediately
let [optimisticCart, addOptimistic] = useOptimistic(
cart,
(state, action: { type: 'add' | 'remove', product: Product, quantity: number }) => {
switch (action.type) {
case 'add':
return [...state, { ...action.product, quantity: action.quantity }]
case 'remove':
return state.filter(item => item.id !== action.product.id)
default:
return state
}
}
)
let handleAddToCart = (product: Product, quantity: number) => {
// Show optimistic update immediately
addOptimistic({ type: 'add', product, quantity })
// Perform actual update in background
startTransition(async () => {
await addToCart(product.id, quantity)
})
}
return (
<div className="shopping-cart">
{optimisticCart.map(item => (
<CartItem
key={item.id}
item={item}
onRemove={() => handleRemove(item)}
isPending={isPending}
/>
))}
<CartTotal
items={optimisticCart}
isCalculating={isPending}
/>
</div>
)
}
// React Compiler automatically optimizes:
// - No useMemo needed for expensive calculations
// - No useCallback needed for event handlers
// - Automatic dependency tracking for effectsTypeScript for Ecommerce: Type Safety at Scale
Product Type System
// types/ecommerce.ts - Complete type safety
interface Product {
id: string
title: string
description: string
vendor: string
productType: string
handle: string
featuredImage: ProductImage
images: ProductImage[]
variants: ProductVariant[]
options: ProductOption[]
priceRange: PriceRange
compareAtPriceRange: PriceRange
availableForSale: boolean
tags: string[]
createdAt: string
updatedAt: string
}
interface ProductVariant {
id: string
title: string
price: Money
compareAtPrice?: Money
availableForSale: boolean
selectedOptions: SelectedOption[]
image?: ProductImage
weight?: number
weightUnit: WeightUnit
sku?: string
barcode?: string
}
interface ShoppingCartLine {
id: string
quantity: number
merchandise: ProductVariant
cost: {
totalAmount: Money
amountPerQuantity: Money
compareAtAmountPerQuantity?: Money
}
attributes: CartLineAttribute[]
}
// Strict typing for cart operations
type CartAction =
| { type: 'ADD_LINE'; merchandise: ProductVariant; quantity: number }
| { type: 'REMOVE_LINE'; lineId: string }
| { type: 'UPDATE_LINE'; lineId: string; quantity: number }
| { type: 'CLEAR_CART' }
// Type-safe cart reducer
function cartReducer(state: CartState, action: CartAction): CartState {
switch (action.type) {
case 'ADD_LINE':
return {
...state,
lines: [...state.lines, createCartLine(action.merchandise, action.quantity)]
}
case 'REMOVE_LINE':
return {
...state,
lines: state.lines.filter(line => line.id !== action.lineId)
}
// TypeScript ensures all cases are handled
default:
return state
}
}
// Component props with strict typing
interface ProductCardProps {
product: Product
variant?: 'default' | 'featured' | 'compact'
showQuickView?: boolean
onAddToCart: (variant: ProductVariant, quantity: number) => Promise<void>
className?: string
}
// Weaverse schema with TypeScript integration
export let schema = createSchema({
type: 'product-card',
title: 'Product Card',
settings: [
{
group: 'Product',
inputs: [
{
type: 'product',
name: 'product',
label: 'Product',
// TypeScript infers the correct type
} satisfies ProductInput,
]
}
] satisfies SchemaSettings[]
})Advanced Type Patterns
// Generic collection component with type safety
interface Collection<T = Product> {
id: string
title: string
description?: string
handle: string
items: T[]
totalCount: number
}
// Type-safe collection component
function CollectionGrid<T extends Product>({
collection,
renderItem,
columns = 3
}: {
collection: Collection<T>
renderItem: (item: T) => React.ReactNode
columns?: number
}) {
return (
<div
className="grid gap-6"
style={{ gridTemplateColumns: `repeat(${columns}, 1fr)` }}
>
{collection.items.map(renderItem)}
</div>
)
}
// Usage with full type safety
<CollectionGrid
collection={productCollection}
renderItem={(product) => (
// product is fully typed as Product
<ProductCard
key={product.id}
product={product}
onAddToCart={handleAddToCart}
/>
)}
/>
// Conditional types for dynamic components
type ComponentProps<T extends string> = T extends 'product-card'
? ProductCardProps
: T extends 'collection-grid'
? CollectionGridProps
: T extends 'search-bar'
? SearchBarProps
: never
// Type-safe dynamic component rendering
function renderComponent<T extends ComponentType>(
type: T,
props: ComponentProps<T>
): React.ReactNode {
switch (type) {
case 'product-card':
return <ProductCard {...(props as ProductCardProps)} />
case 'collection-grid':
return <CollectionGrid {...(props as CollectionGridProps)} />
case 'search-bar':
return <SearchBar {...(props as SearchBarProps)} />
default:
// TypeScript ensures this is never reached
return null
}
}
// Template literal types for CSS classes
type Size = 'sm' | 'md' | 'lg' | 'xl'
type Variant = 'primary' | 'secondary' | 'outline'
type ButtonClass = `btn-${Size}-${Variant}`
// Compile-time CSS class validation
function Button({
size,
variant,
children
}: {
size: Size
variant: Variant
children: React.ReactNode
}) {
let className: ButtonClass = `btn-${size}-${variant}`
return <button className={className}>{children}</button>
}Modern Build Tools and Performance
Vite and React Router v7 Integration
// vite.config.ts - Modern build setup
import { vitePlugin as remix } from '@remix-run/dev'
import { defineConfig } from 'vite'
import { hydrogen } from '@shopify/hydrogen/vite'
export default defineConfig({
plugins: [
hydrogen(),
remix({
// React Router v7 with automatic optimization
future: {
v3_fetcherPersist: true,
v3_relativeSplatPath: true,
v3_throwAbortReason: true,
},
}),
],
build: {
// Automatic code splitting at route level
rollupOptions: {
output: {
manualChunks: {
// Vendor chunks for better caching
react: ['react', 'react-dom'],
shopify: ['@shopify/hydrogen'],
weaverse: ['@weaverse/hydrogen'],
},
},
},
},
optimizeDeps: {
// Pre-bundle dependencies for faster dev server
include: [
'react',
'react-dom',
'@shopify/hydrogen',
'@weaverse/hydrogen',
],
},
// React Compiler for automatic optimization
babel: {
plugins: [
['babel-plugin-react-compiler', {
target: '19'
}]
]
}
})
// Automatic performance optimizations:
// ✅ Route-based code splitting
// ✅ Tree shaking unused code
// ✅ Asset optimization (images, CSS)
// ✅ Dead code elimination
// ✅ Preload critical resourcesPerformance Monitoring Integration
// performance/monitoring.ts - Web Vitals tracking
import { getCLS, getFID, getFCP, getLCP, getTTFB } from 'web-vitals'
// Track Core Web Vitals
function initPerformanceMonitoring() {
getCLS(metric => reportMetric('CLS', metric))
getFID(metric => reportMetric('FID', metric))
getFCP(metric => reportMetric('FCP', metric))
getLCP(metric => reportMetric('LCP', metric))
getTTFB(metric => reportMetric('TTFB', metric))
}
// Custom ecommerce metrics
function trackEcommerceMetrics() {
// Time to first product visible
let observer = new PerformanceObserver((list) => {
for (let entry of list.getEntries()) {
if (entry.name === 'first-product-paint') {
reportMetric('FirstProductPaint', {
value: entry.startTime,
rating: entry.startTime < 1000 ? 'good' : 'needs-improvement'
})
}
}
})
observer.observe({ entryTypes: ['measure'] })
}
// Shopping cart performance tracking
function trackCartPerformance() {
let cartOpenTime = 0
document.addEventListener('cart-open', () => {
cartOpenTime = performance.now()
})
document.addEventListener('cart-ready', () => {
let cartRenderTime = performance.now() - cartOpenTime
reportMetric('CartRenderTime', {
value: cartRenderTime,
rating: cartRenderTime < 100 ? 'good' : 'needs-improvement'
})
})
}
// Integration with React Router v7 navigation
function trackNavigationPerformance() {
// Track route change performance
window.addEventListener('routechange', (event) => {
let { from, to, duration } = event.detail
reportMetric('RouteChangeTime', {
value: duration,
route: to,
previousRoute: from,
rating: duration < 200 ? 'good' : 'needs-improvement'
})
})
}Modern State Management Patterns
React 19 Built-in State Management
// stores/cart.ts - React 19 state management
import { signal } from '@preact/signals-react'
import { useOptimistic, useTransition } from 'react'
// Global cart state with signals
export let cartState = signal<CartState>({
lines: [],
cost: { totalAmount: { amount: '0', currencyCode: 'USD' } },
totalQuantity: 0,
isOpen: false
})
// Cart operations with optimistic updates
export function useCart() {
let [isPending, startTransition] = useTransition()
let [optimisticCart, updateOptimistic] = useOptimistic(
cartState.value,
(state, action: CartAction) => {
return cartReducer(state, action)
}
)
let addLine = (merchandise: ProductVariant, quantity: number) => {
// Immediate optimistic update
updateOptimistic({ type: 'ADD_LINE', merchandise, quantity })
// Background server update
startTransition(async () => {
try {
let result = await addToCartMutation(merchandise.id, quantity)
cartState.value = result.cart
} catch (error) {
// Optimistic update will be reverted automatically
console.error('Failed to add to cart:', error)
}
})
}
return {
cart: optimisticCart,
addLine,
removeLine,
updateLine,
isPending
}
}
// User preferences with localStorage sync
export let userPreferences = signal({
currency: 'USD',
language: 'en',
theme: 'light' as 'light' | 'dark',
notifications: true
})
// Automatic localStorage persistence
userPreferences.subscribe((prefs) => {
localStorage.setItem('userPreferences', JSON.stringify(prefs))
})
// Hydrate from localStorage
if (typeof window !== 'undefined') {
let stored = localStorage.getItem('userPreferences')
if (stored) {
userPreferences.value = { ...userPreferences.value, ...JSON.parse(stored) }
}
}
// Product search state with debouncing
export let searchState = signal({
query: '',
results: [] as Product[],
isLoading: false,
filters: {} as SearchFilters
})
// Debounced search effect
import { debounce } from 'lodash-es'
let debouncedSearch = debounce(async (query: string, filters: SearchFilters) => {
searchState.value = { ...searchState.value, isLoading: true }
try {
let results = await searchProducts(query, filters)
searchState.value = {
...searchState.value,
results,
isLoading: false
}
} catch (error) {
searchState.value = { ...searchState.value, isLoading: false }
}
}, 300)
// Search function
export function search(query: string, filters: SearchFilters = {}) {
searchState.value = { ...searchState.value, query, filters }
debouncedSearch(query, filters)
}Real-World Performance Metrics
Initial Bundle Size
Time to Interactive
Development Build Time
Type Safety Coverage
Core Web Vitals
Integration with Visual Editing
The Missing Piece: Weaverse
React 19, TypeScript, and modern build tools solve the developer experience. But what about non-technical users who need to customize these sophisticated applications? Weaverse bridges this gap - bringing visual editing to modern JavaScript ecommerce.
Modern JavaScript + Visual Editing = Complete Solution
| Feature | ||
|---|---|---|
Performance & Architecture | React 19 Server Components for performance | Visual editing for React components |
Code Quality | TypeScript for complete type safety | No code required for customization |
Development Tools | Modern build tools with automatic optimization | Real-time preview and publishing |
User Experience | Concurrent features for superior UX | Maintains all technical benefits |
Complete Modern JavaScript Implementation
// ProductShowcase.tsx - Complete modern implementation
import { Suspense } from 'react'
import { useOptimistic, useTransition } from 'react'
import { createSchema } from '@weaverse/hydrogen'
import type { Product } from '@shopify/hydrogen/storefront-api-types'
interface ProductShowcaseProps {
collectionId: string
maxProducts?: number
showFilters?: boolean
layout?: 'grid' | 'list' | 'carousel'
}
// Server Component for data fetching
async function ProductShowcase({
collectionId,
maxProducts = 12,
showFilters = true,
layout = 'grid'
}: ProductShowcaseProps) {
// Server-side data fetching
let products = await getCollectionProducts(collectionId, {
first: maxProducts
})
return (
<div className="product-showcase">
<Suspense fallback={<ShowcaseHeaderSkeleton />}>
<ShowcaseHeader collectionId={collectionId} />
</Suspense>
{showFilters && (
<Suspense fallback={<FiltersSkeleton />}>
<ProductFilters collectionId={collectionId} />
</Suspense>
)}
<Suspense fallback={<ProductGridSkeleton layout={layout} />}>
<ProductDisplay products={products} layout={layout} />
</Suspense>
</div>
)
}
// Client Component for interactivity
'use client'
function ProductDisplay({
products,
layout
}: {
products: Product[]
layout: 'grid' | 'list' | 'carousel'
}) {
let [isPending, startTransition] = useTransition()
let [optimisticProducts, updateProducts] = useOptimistic(
products,
(state, action: { type: 'filter' | 'sort', data: any }) => {
// Optimistic filtering/sorting logic
return processProducts(state, action)
}
)
let handleSort = (sortBy: string) => {
updateProducts({ type: 'sort', data: sortBy })
startTransition(async () => {
// Actual server-side sorting
await updateProductSort(sortBy)
})
}
let layoutClasses = {
grid: 'grid grid-cols-1 md:grid-cols-3 lg:grid-cols-4 gap-6',
list: 'flex flex-col space-y-4',
carousel: 'flex overflow-x-auto space-x-4 pb-4'
}
return (
<div className={layoutClasses[layout]}>
{optimisticProducts.map(product => (
<ProductCard
key={product.id}
product={product}
layout={layout}
isPending={isPending}
/>
))}
</div>
)
}
// Weaverse schema for complete visual editing
export let schema = createSchema({
type: 'product-showcase',
title: 'Product Showcase',
settings: [
{
group: 'Collection',
inputs: [
{
type: 'collection',
name: 'collectionId',
label: 'Product Collection',
},
{
type: 'range',
name: 'maxProducts',
label: 'Maximum Products',
min: 4,
max: 24,
step: 4,
defaultValue: 12,
},
],
},
{
group: 'Display',
inputs: [
{
type: 'select',
name: 'layout',
label: 'Layout Style',
options: [
{ value: 'grid', label: 'Grid Layout' },
{ value: 'list', label: 'List Layout' },
{ value: 'carousel', label: 'Carousel Layout' },
],
defaultValue: 'grid',
},
{
type: 'toggle',
name: 'showFilters',
label: 'Show Product Filters',
defaultValue: true,
},
],
},
],
})
// TypeScript ensures:
// ✅ Props are correctly typed
// ✅ Schema matches component interface
// ✅ All product operations are type-safe
// ✅ React 19 features are properly used
// React Compiler optimizes:
// ✅ Automatic memoization
// ✅ Effect dependency tracking
// ✅ Callback stability
// ✅ Re-render minimizationGetting Started with Modern JavaScript Ecommerce
Step 1: Technology Assessment
Evaluate your current JavaScript stack:
- Framework: Migrate from jQuery/vanilla JS to React 19
- Type Safety: Adopt TypeScript for error prevention
- Build Tools: Upgrade to Vite for fast development
- State Management: Use React 19 built-ins + Preact Signals
Step 2: Progressive Migration Strategy
Phase 1: Foundation (Weeks 1-2)
- Set up React Router v7 with TypeScript
- Configure modern build tools (Vite)
- Implement basic component structure
Phase 2: Core Features (Weeks 3-6)
- Convert product catalog to React components
- Implement shopping cart with React 19 features
- Add Weaverse schemas for visual editing
Phase 3: Advanced Features (Weeks 7-8)
- Performance optimization and monitoring
- Advanced state management patterns
- Comprehensive testing and quality assurance
Step 3: Team Training and Adoption
Developer Training:
- React 19 concurrent features
- TypeScript best practices
- Modern state management patterns
- Performance optimization techniques
Content Team Training:
- Weaverse visual editor workflows
- Component customization patterns
- Preview and publishing processes
Case Study: Complete Stack Transformation
Before: Legacy JavaScript Ecommerce
Challenge: An electronics retailer's site was built with jQuery and basic JavaScript, causing performance and maintenance issues.
Technical Debt:
- 2MB JavaScript bundle with jQuery and plugins
- No type safety - runtime errors in production
- Manual state management with global variables
- No component reusability - copy-paste everywhere
- 8-second page load times
- No visual editing - developer required for all changes
After: Modern JavaScript Stack with Weaverse
Solution: Complete migration to React 19, TypeScript, and Weaverse visual editing.
Results After 4 Months:
- 90% Bundle Reduction: From 2MB to 200kb with modern bundling
- Zero Runtime Errors: TypeScript caught all type-related bugs
- 8x Performance: Page loads in 1 second vs 8 seconds
- Component Reusability: 85% code reuse across pages
- Client Independence: 100% visual customization through Weaverse
- Developer Productivity: 75% faster feature development
Business Impact:
- 45% Conversion Increase: Faster pages = more sales
- 90% Support Reduction: Visual editing eliminated change requests
- Developer Satisfaction: Team loves modern tools and practices
- Future-Proof Architecture: Ready for React 19+ innovations
The Future of Modern JavaScript Ecommerce
Modern JavaScript represents the maturation of web development from script-based to application-based thinking. Combined with visual editing capabilities, this stack delivers:
- Developer Excellence: React 19, TypeScript, modern build tools
- Performance Leadership: Server components, concurrent features, optimized bundles
- Type Safety: Compile-time error detection and IntelliSense
- Visual Editing: Weaverse enables non-technical customization
- Future-Ready: Built for the next decade of web development
Ready to Modernize Your JavaScript Architecture?
Transform your ecommerce development with the complete modern JavaScript stack: React 19, TypeScript, and Weaverse visual editing.
Start Your Modern JavaScript Journey →
Learn more about Component-Based Ecommerce or discover Git-Based Theme Development workflows.
Never miss an update
Subscribe to get the latest insights, tutorials, and best practices for building high-performance headless stores delivered to your inbox.