Repository navigation
Architecture
Understanding VAST's project structure, file organization, and architectural decisions.
vast-shopify-theme/
├── src/ # Source files (compiled by Vite)
│ ├── entrypoints/ # Vite entry points
│ │ ├── theme.js # Main JavaScript entry (all pages)
│ │ └── theme.css # Main CSS entry (all pages)
│ ├── js/
│ │ ├── alpine/ # Alpine.js components and stores
│ │ │ ├── components/ # Extracted Alpine components
│ │ │ │ ├── product/ # Product page components
│ │ │ │ ├── collection/ # Collection page components
│ │ │ │ ├── blog/ # Blog page components
│ │ │ │ └── shared/ # Shared components
│ │ │ ├── stores/ # Global Alpine stores
│ │ │ │ ├── global.js # Global state (menu, cart, scroll)
│ │ │ │ ├── recentlyViewed.js # Recently viewed tracking
│ │ │ │ └── debug.js # Debug utilities
│ │ │ └── index.js # Auto-registration system
│ │ └── helpers.js # Utility functions (window.vast.helpers)
│ ├── css/
│ │ ├── base.css # Base layer styles
│ │ ├── components.css # Component layer styles
│ │ ├── utilities.css # Utility layer styles
│ │ └── global.css # Non-tree-shaken global styles
│ ├── schema/ # Schematic schema definitions
│ │ ├── *.cjs # Section schemas
│ │ ├── settings_schema.cjs # Global settings schema
│ │ └── locales/ # Locale schemas
│ │ └── *.cjs # Translation files
│ ├── fonts/ # Custom font files
│ └── images/ # Image assets
├── public/ # Static assets (copied to assets/)
│ ├── predictive-search.js # Web component for search
│ └── *.svg, *.png, etc. # Static images/icons
├── sections/ # Shopify section files (30+)
├── snippets/ # Shopify snippet files (35+)
├── templates/ # Shopify template files (12+)
│ ├── *.json # Main templates
│ └── customers/ # Customer account templates
│ └── *.liquid
├── layout/
│ └── theme.liquid # Main layout file
├── config/
│ ├── settings_schema.json # Theme settings (generated)
│ └── settings_data.json # Theme setting values
├── locales/ # Translation files (generated)
│ └── *.json
├── assets/ # Built assets (generated by Vite)
│ ├── *.min.js # Compiled JavaScript
│ ├── *.min.css # Compiled CSS
│ └── * # Static files from public/
├── docs/ # Contributor documentation
│ ├── ROADMAP.md # Project roadmap
│ └── STYLING-GUIDE.md # Styling standards
├── vite.config.js # Vite configuration
├── tailwind.config.js # Tailwind configuration
├── package.json # NPM dependencies and scripts
├── shopify.theme.toml # Shopify CLI config (gitignored)
├── README.md # Project README
└── CLAUDE.md # Claude Code instructions
All source files that require compilation live in src/:
JavaScript:
- Entry points:
src/entrypoints/*.js - Alpine components:
src/js/alpine/components/**/*.js - Alpine stores:
src/js/alpine/stores/*.js - Utilities:
src/js/helpers.js
CSS:
- Entry point:
src/entrypoints/theme.css - Layer files:
src/css/{base,components,utilities,global}.css
Schemas:
- Section schemas:
src/schema/*.cjs - Locale schemas:
src/schema/locales/*.cjs
Static files that don't need processing go in public/:
- Web components (
predictive-search.js) - Static images and icons
- Font files (if not using
@font-facefromsrc/fonts/)
Important: Files in public/ are copied to assets/ as-is during build.
These files are auto-generated and should not be edited directly:
-
assets/*.min.js- Compiled JavaScript from Vite -
assets/*.min.css- Compiled CSS from Vite -
snippets/vite.liquid- Auto-generated by vite-plugin-shopify (gitignored) -
config/settings_schema.json- Generated by Schematic fromsrc/schema/settings_schema.cjs -
locales/*.json- Generated by Schematic fromsrc/schema/locales/*.cjs - Schema in sections - Schematic injects JSON schema into section files
Key plugins (vite.config.js):
-
vite-plugin-shopify- Core Shopify integration- Compiles entrypoints to hashed assets
- Generates
snippets/vite.liquidfor asset references - Configured with
sourceCodeDir: 'src'andentrypointsDir: 'src/entrypoints'
-
@tailwindcss/vite- Tailwind CSS v4 processing- Processes CSS layers
- Tree-shakes unused styles
- Generates optimized CSS bundles
-
@vitejs/plugin-basic-ssl- Local HTTPS- Generates self-signed SSL certificate
- Enables HTTPS at https://127.0.0.1:3000
-
vite-plugin-page-reload- Liquid file watching- Watches
/tmp/theme.updatefor Shopify CLI reload triggers - Triggers page reload when Liquid files change
- Watches
-
Custom
copyPublicToAssetsPlugin- Static file syncing- Watches
public/directory in dev mode - Copies files to
assets/in real-time
- Watches
Development (npm run dev):
- Vite runs in
build --watchmode - Compiles source files on change
- Writes to
assets/directory - Shopify CLI uploads to development store
- Page reload plugin watches for Liquid changes
Production (npm run build):
- Vite builds and minifies all assets
- Schematic compiles all schema files
- Output written to
assets/directory - Ready for deployment
VAST uses a single-entrypoint architecture where all components are registered automatically at startup.
Auto-registration system (src/js/alpine/index.js):
// Automatically imports all stores
const storeModules = import.meta.glob('./stores/*.js', { eager: true })
// Register each store
for (const path in storeModules) {
const storeName = path.match(/\.\/stores\/(.+)\.js$/)[1]
Alpine.store(storeName, storeModules[path].default)
}
// Automatically imports all components
const componentModules = import.meta.glob('./components/**/*.js', { eager: true })
// Register each component
for (const path in componentModules) {
const componentName = path.match(/\/([^/]+)\.js$/)[1]
Alpine.data(componentName, componentModules[path].default)
}Benefits:
- No manual registration needed
- Components initialize only when used in DOM
- Easy to add new components (just create file)
- Centralized component management
Standard component pattern:
// src/js/alpine/components/product/productGallery.js
export default function productGallery() {
return {
// State
currentImageIndex: 0,
images: [],
// Lifecycle
init() {
// Read config from data attributes
const el = this.$el
this.images = JSON.parse(el.dataset.images || '[]')
this.galleryLayout = el.dataset.galleryLayout || 'bottom'
},
// Methods
selectImage(index) {
this.currentImageIndex = index
}
}
}Usage in Liquid:
<div x-data="productGallery"
data-images='{{ product.images | json }}'
data-gallery-layout="{{ section.settings.gallery_layout }}">
<!-- Component markup -->
</div>Global stores (src/js/alpine/stores/):
Stores provide cross-component state management:
// src/js/alpine/stores/global.js
export default {
mobileMenuOpen: false,
minicartOpen: false,
searchOpen: false,
scrolled: false,
cartData: {},
openMinicart() {
this.minicartOpen = true
},
closeMinicart() {
this.minicartOpen = false
}
}Access stores anywhere:
<div x-show="$store.global.minicartOpen">
<!-- Minicart content -->
</div>
<button @click="$store.global.openMinicart()">
Open Cart
</button>Layer files:
-
src/css/base.css- Base layer (@layer base)- Element defaults (typography, links, buttons)
- Normalizations
-
src/css/components.css- Component layer (@layer components)- Reusable component classes (
.btn,.input-select,.pill-button) - Complex multi-property utilities
- Reusable component classes (
-
src/css/utilities.css- Utility layer (@layer utilities)- Custom utility classes
- Variants and modifiers
-
src/css/global.css- No layer (always included)- Styles that should never be tree-shaken
-
@applydirectives - CSS nesting support via
@tailwindcss/nesting
Defined in vite.config.js:
{
variants: {
scrolled: '[data-scrolled="true"] &',
'mobile-menu-visible': '[data-mobile-menu-visible="true"] &'
}
}Usage:
<body
:data-scrolled="$store.global.scrolled"
:data-mobile-menu-visible="$store.global.mobileMenuOpen">
<header class="scrolled:shadow-lg mobile-menu-visible:bg-white">
<!-- Header content -->
</header>
</body>Shopify sections require JSON schema, which leads to duplication when defining settings, presets, and localization keys. Schematic solves this by:
-
JavaScript-based schemas - Write schemas in
.cjsfiles instead of JSON - DRY principles - Reuse common settings and patterns
- Compilation - Generates JSON and injects into section files
- Type safety - Better IDE support and validation
Section schema (src/schema/header.cjs):
const { app } = require('@anchovie/schematic');
module.exports = {
...app.section("header", {
class: "section-header sticky top-0 z-20",
tag: "header"
}),
"settings": [
app.paragraph("t:sections.header.settings.paragraph"),
app.image("logo", {
label: "Logo Image"
}),
app.range("logo_width", {
label: "Logo Width",
min: 50,
max: 300,
step: 10,
default: 150,
unit: "px"
})
],
"presets": [
{
name: "Header",
category: "Layout"
}
]
}Compilation:
npx schematicThis injects the JSON schema into sections/header.liquid between schema tags:
{% schema %}
{
"name": "Header",
"class": "section-header sticky top-0 z-20",
"tag": "header",
"settings": [...]
}
{% endschema %}Components communicate via custom events:
Dispatching events:
// src/js/helpers.js
export function emitEvent(eventName, detail = {}) {
window.dispatchEvent(new CustomEvent(eventName, { detail }))
}
// Usage in component
emitEvent('variant:change', {
variant: selectedVariant,
product: this.product
})Listening for events:
// In another component
init() {
window.addEventListener('variant:change', (e) => {
this.updatePrice(e.detail.variant)
this.updateGallery(e.detail.variant)
})
}Product events:
-
variant:change- Product variant selection changed
Cart events (from Liquid AJAX Cart):
-
liquid-ajax-cart:request-start- Cart operation started -
liquid-ajax-cart:request-end- Cart operation completed -
liquid-ajax-cart:cart-update- Cart state updated
Modal events:
-
show-modal- Open modal dialog -
close-modal- Close modal dialog
- Prefix with purpose:
main-*(page content),featured-*(homepage), etc. - Use kebab-case:
main-product.liquid,featured-collection.liquid
- Descriptive names:
product-card.liquid,article-navigation.liquid - Icon snippets:
icon-{name}.liquid(e.g.,icon-cart.liquid) - Utility snippets:
head-meta.liquid,font-face.liquid
- camelCase JavaScript files:
productGallery.js,quickViewModal.js - Match
x-dataname:x-data="productGallery"→productGallery.js
- Match section filename:
header.liquid→header.cjs - CommonJS format:
module.exports = {...}
- Development Guide - Development workflow and tools
- What's Included - Complete reference of all files
- Features Reference - Detailed feature documentation