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 | Modern Stack (2025) | Legacy Stack (2015-2020) |
|---|---|---|
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 impactasync function ProductCatalog({ collectionId }: { collectionId: string }) {// Data fetching happens on serverlet [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 clientreturn (<FilterPanelfilters={filters}onFilterChange={(newFilters) => {startTransition(() => {setFilters(newFilters)// Trigger server-side re-render})}}/>)}// Weaverse schema for visual editingexport 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 Featuresimport { useOptimistic, useTransition, use } from 'react'import { addToCart, removeFromCart } from '~/lib/cart-actions'function ShoppingCart() {let [isPending, startTransition] = useTransition()// Optimistic updates - show changes immediatelylet [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 immediatelyaddOptimistic({ type: 'add', product, quantity })// Perform actual update in backgroundstartTransition(async () => {await addToCart(product.id, quantity)})}return (<div className="shopping-cart">{optimisticCart.map(item => (<CartItemkey={item.id}item={item}onRemove={() => handleRemove(item)}isPending={isPending}/>))}<CartTotalitems={optimisticCart}isCalculating={isPending}/></div>)}// React Compiler automatically optimizes:// - No useMemo needed for expensive calculations// - No useCallback needed for event handlers// - Automatic dependency tracking for effects
TypeScript for Ecommerce: Type Safety at Scale
Product Type System
// types/ecommerce.ts - Complete type safetyinterface Product {id: stringtitle: stringdescription: stringvendor: stringproductType: stringhandle: stringfeaturedImage: ProductImageimages: ProductImage[]variants: ProductVariant[]options: ProductOption[]priceRange: PriceRangecompareAtPriceRange: PriceRangeavailableForSale: booleantags: string[]createdAt: stringupdatedAt: string}interface ProductVariant {id: stringtitle: stringprice: MoneycompareAtPrice?: MoneyavailableForSale: booleanselectedOptions: SelectedOption[]image?: ProductImageweight?: numberweightUnit: WeightUnitsku?: stringbarcode?: string}interface ShoppingCartLine {id: stringquantity: numbermerchandise: ProductVariantcost: {totalAmount: MoneyamountPerQuantity: MoneycompareAtAmountPerQuantity?: Money}attributes: CartLineAttribute[]}// Strict typing for cart operationstype 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 reducerfunction 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 handleddefault:return state}}// Component props with strict typinginterface ProductCardProps {product: Productvariant?: 'default' | 'featured' | 'compact'showQuickView?: booleanonAddToCart: (variant: ProductVariant, quantity: number) => Promise<void>className?: string}// Weaverse schema with TypeScript integrationexport 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 safetyinterface Collection<T = Product> {id: stringtitle: stringdescription?: stringhandle: stringitems: T[]totalCount: number}// Type-safe collection componentfunction CollectionGrid<T extends Product>({collection,renderItem,columns = 3}: {collection: Collection<T>renderItem: (item: T) => React.ReactNodecolumns?: number}) {return (<divclassName="grid gap-6"style={{ gridTemplateColumns: `repeat(${columns}, 1fr)` }}>{collection.items.map(renderItem)}</div>)}// Usage with full type safety<CollectionGridcollection={productCollection}renderItem={(product) => (// product is fully typed as Product<ProductCardkey={product.id}product={product}onAddToCart={handleAddToCart}/>)}/>// Conditional types for dynamic componentstype ComponentProps<T extends string> = T extends 'product-card'? ProductCardProps: T extends 'collection-grid'? CollectionGridProps: T extends 'search-bar'? SearchBarProps: never// Type-safe dynamic component renderingfunction 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 reachedreturn null}}// Template literal types for CSS classestype Size = 'sm' | 'md' | 'lg' | 'xl'type Variant = 'primary' | 'secondary' | 'outline'type ButtonClass = `btn-${Size}-${Variant}`// Compile-time CSS class validationfunction Button({size,variant,children}: {size: Sizevariant: Variantchildren: 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 setupimport { 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 optimizationfuture: {v3_fetcherPersist: true,v3_relativeSplatPath: true,v3_throwAbortReason: true,},}),],build: {// Automatic code splitting at route levelrollupOptions: {output: {manualChunks: {// Vendor chunks for better cachingreact: ['react', 'react-dom'],shopify: ['@shopify/hydrogen'],weaverse: ['@weaverse/hydrogen'],},},},},optimizeDeps: {// Pre-bundle dependencies for faster dev serverinclude: ['react','react-dom','@shopify/hydrogen','@weaverse/hydrogen',],},// React Compiler for automatic optimizationbabel: {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 resources
Performance Monitoring Integration
// performance/monitoring.ts - Web Vitals trackingimport { getCLS, getFID, getFCP, getLCP, getTTFB } from 'web-vitals'// Track Core Web Vitalsfunction 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 metricsfunction trackEcommerceMetrics() {// Time to first product visiblelet 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 trackingfunction trackCartPerformance() {let cartOpenTime = 0document.addEventListener('cart-open', () => {cartOpenTime = performance.now()})document.addEventListener('cart-ready', () => {let cartRenderTime = performance.now() - cartOpenTimereportMetric('CartRenderTime', {value: cartRenderTime,rating: cartRenderTime < 100 ? 'good' : 'needs-improvement'})})}// Integration with React Router v7 navigationfunction trackNavigationPerformance() {// Track route change performancewindow.addEventListener('routechange', (event) => {let { from, to, duration } = event.detailreportMetric('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 managementimport { signal } from '@preact/signals-react'import { useOptimistic, useTransition } from 'react'// Global cart state with signalsexport let cartState = signal<CartState>({lines: [],cost: { totalAmount: { amount: '0', currencyCode: 'USD' } },totalQuantity: 0,isOpen: false})// Cart operations with optimistic updatesexport 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 updateupdateOptimistic({ type: 'ADD_LINE', merchandise, quantity })// Background server updatestartTransition(async () => {try {let result = await addToCartMutation(merchandise.id, quantity)cartState.value = result.cart} catch (error) {// Optimistic update will be reverted automaticallyconsole.error('Failed to add to cart:', error)}})}return {cart: optimisticCart,addLine,removeLine,updateLine,isPending}}// User preferences with localStorage syncexport let userPreferences = signal({currency: 'USD',language: 'en',theme: 'light' as 'light' | 'dark',notifications: true})// Automatic localStorage persistenceuserPreferences.subscribe((prefs) => {localStorage.setItem('userPreferences', JSON.stringify(prefs))})// Hydrate from localStorageif (typeof window !== 'undefined') {let stored = localStorage.getItem('userPreferences')if (stored) {userPreferences.value = { ...userPreferences.value, ...JSON.parse(stored) }}}// Product search state with debouncingexport let searchState = signal({query: '',results: [] as Product[],isLoading: false,filters: {} as SearchFilters})// Debounced search effectimport { 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 functionexport function search(query: string, filters: SearchFilters = {}) {searchState.value = { ...searchState.value, query, filters }debouncedSearch(query, filters)}
Real-World Performance Metrics
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 | Technical Excellence | Business Practicality |
|---|---|---|
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 implementationimport { 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: stringmaxProducts?: numbershowFilters?: booleanlayout?: 'grid' | 'list' | 'carousel'}// Server Component for data fetchingasync function ProductShowcase({collectionId,maxProducts = 12,showFilters = true,layout = 'grid'}: ProductShowcaseProps) {// Server-side data fetchinglet 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 logicreturn processProducts(state, action)})let handleSort = (sortBy: string) => {updateProducts({ type: 'sort', data: sortBy })startTransition(async () => {// Actual server-side sortingawait 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 => (<ProductCardkey={product.id}product={product}layout={layout}isPending={isPending}/>))}</div>)}// Weaverse schema for complete visual editingexport 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 minimization
Getting 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.