Skip to content

Development Guide

Anthony Baggett edited this page Nov 21, 2025 · 1 revision

Development Guide

Complete guide to working with VAST's development environment and tools.

NPM Scripts

Command Description
npm run dev Recommended: Start Vite build watch + Shopify CLI with live reload. Assets written to disk, theme editor & preview URLs work.
npm run dev:vite-server Alternative: Start Vite dev server + Shopify CLI. Faster HMR but theme editor/preview URLs won't have styling/JS (memory-only assets).
npm run build Build assets and compile schemas
npm run deploy Build and push to production environment (interactive)
npm run deploy:dev Build and push to development environment
npm run deploy:staging Build and push to staging environment
npm run deploy:new Build and publish as new theme on Shopify

Development Mode Comparison

npm run dev (build watch):

  • Assets written to disk → Shopify CLI uploads them
  • Theme editor & preview URLs work ✅
  • Best for general development and theme customization

npm run dev:vite-server (dev server):

  • Assets served from memory → Not uploaded to Shopify
  • Theme editor & preview URLs won't show styles/JS ❌
  • Faster rebuilds for rapid iteration on code
  • Best when working only with local preview (127.0.0.1:9292)

For all Shopify CLI commands, see Shopify CLI documentation.


Working with Schematic

Schematic eliminates JSON duplication by letting you define section schemas in JavaScript.

Schema Files Location

All schema files are located in src/schema/:

  • Section schemas: src/schema/*.cjs (e.g., header.cjs, footer.cjs)
  • Settings schema: src/schema/settings_schema.cjs
  • Locale schemas: src/schema/locales/*.cjs

Example Schema

File: src/schema/header.cjs

const { app } = require('@anchovie/schematic');

module.exports = {
    ...app.section("header", {
        class: "section-header sticky top-0 z-20 shadow-md",
        tag: "header"
    }),
    "settings": [
        app.paragraph("t:sections.header.settings.paragraph"),
    ]
}

Compiling Schemas

npx schematic

This compiles all .cjs files in src/schema/ to their corresponding Liquid section files, injecting the JSON schema.

Note: The build and deploy scripts automatically run Schematic, so manual compilation is only needed during development when you want to see changes immediately.

Learn more: @anchovie/schematic documentation


Working with AlpineJS

VAST uses extracted components organized in src/js/alpine/components/ for better maintainability and code reuse.

Component Structure

Components are defined as module exports and auto-registered at startup:

// src/js/alpine/components/product/productGallery.js
export default function productGallery() {
  return {
    currentImageIndex: 0,
    images: [],

    init() {
      // Read configuration from data attributes
      const el = this.$el
      this.images = JSON.parse(el.dataset.images || '[]')
      this.galleryLayout = el.dataset.galleryLayout || 'bottom'
    },

    selectImage(index) {
      this.currentImageIndex = index
    }
  }
}

Usage in Liquid Templates

Pass server-side data to Alpine components via data attributes:

<div x-data="productGallery"
     data-images='{{ product.images | json }}'
     data-gallery-layout="{{ section.settings.gallery_layout }}">
  <div class="gallery-main">
    <img :src="images[currentImageIndex]" alt="Product image">
  </div>
</div>

Event-Driven Architecture

The theme uses custom events for component communication:

  • Product components listen to variant:change events to update gallery and pricing
  • Modal components respond to show-modal and close-modal events
  • Cart components listen to liquid-ajax-cart:* events for state updates

This decoupled approach keeps components modular and easier to maintain.

Variant Management

The variantPicker component provides sophisticated variant handling:

  • Tracks all possible variant combinations and availability
  • Disables unavailable options based on current selection
  • Updates URL parameters for shareable variant links
  • Dispatches events when variants change for other components to react

Component Organization

Components are organized by usage area:

src/js/alpine/
├── components/
│   ├── product/         # Product page components
│   ├── collection/      # Collection page components
│   ├── blog/           # Blog page components
│   └── shared/         # Shared across multiple pages
└── stores/             # Global Alpine stores (auto-registered)

CSS and Tailwind

Tailwind v4 is configured via the @tailwindcss/vite plugin.

Entry Point

Main CSS entry: src/entrypoints/theme.css

This file imports all CSS layers:

  • Base styles (src/css/base.css)
  • Component styles (src/css/components.css)
  • Utility styles (src/css/utilities.css)
  • Global styles (src/css/global.css)

Global Styles

File: src/css/global.css

Styles in this file are not tree-shaken and will always be included in the final bundle. This file supports:

  • CSS nesting via @tailwindcss/nesting
  • @apply directive for Tailwind utilities
  • Custom global styles that don't fit into Tailwind's utility model

CSS Architecture

Tailwind v4 Layers:

  • src/css/base.css - Base element styles
  • src/css/components.css - Reusable component classes (.btn, .input-select, .pill-button)
  • src/css/utilities.css - Custom utility classes
  • src/css/global.css - Non-tree-shaken global styles

For more information on Tailwind v4's features and syntax, see the Tailwind v4 documentation.


JavaScript Entry Points

Main Entry

File: src/entrypoints/theme.js

This is the main JavaScript entrypoint loaded on all pages. It includes:

  • Alpine.js core and plugins
  • Global stores (menu, cart, scroll)
  • Helper utilities
  • Liquid Ajax Cart initialization

Additional Entry Points

Additional entry points can be added in vite.config.js:

shopify({
  additionalEntrypoints: [
    'src/js/custom-module.js'
  ]
})

Dynamic Imports

Use dynamic imports for code-splitting and lazy-loading features that aren't needed immediately:

// Load feature only when needed
document.querySelector('.trigger')?.addEventListener('click', async () => {
  const { initFeature } = await import('./feature.js')
  initFeature()
}, { once: true })

Public Directory

Static assets in the public/ directory are automatically copied to assets/ on build. This is a Vite convention.

What to put in public/:

  • Images (product placeholders, icons, logos)
  • Fonts (if not loaded via CSS @font-face from src/fonts/)
  • Static JavaScript files (like predictive-search.js)
  • Any other static assets that don't need processing

During development, a custom Vite plugin watches public/ and syncs changes to assets/ in real-time, so you'll see updates immediately without restarting the dev server.


Next Steps


← Back to Home