Skip to content

JavaScript

Entry Point

src/js/scripts.js is the main entry. It imports styles and creates the App instance on DOMContentLoaded.

The App class is the root of the JS framework. It initializes core services, resolves the Tailwind config for runtime access, and starts the component loading system.

Core Services

The App creates singleton services accessible via app.instances.get('name'):

ServiceKeyPurpose
ResizeManagerresizeManagerCentralized resize handling with debounce
DevicedeviceInput detection (touch vs pointer via detect-it)
DataLayerdataLayerGTM dataLayer management
ScrollscrollerLenis smooth scroll (pointer) or native scroll (touch) + GSAP ScrollTrigger
PagepageComponent lifecycle for main#app content
CartcartCart AJAX operations

Accessing Services

javascript
import app from '../core/app'

export default class MyComponent {
  constructor(element) {
    this.element = element
    this.init()
  }

  init = () => {
    const cart = app.instances.get('cart')
    const scroller = app.instances.get('scroller')
  }
}

Module Resolution

The getModule() helper in src/js/core/utils/helpers.js uses import.meta.glob('components/**/*.js') to build a map of all available JS modules. When a data-component attribute is found, the matching module is dynamically imported and instantiated.

This means adding a new interactive component is as simple as:

  1. Create components/blocks/my_feature/index.js with a default export class
  2. Add data-component="blocks/my_feature" to the HTML element

No manual registration or import is needed.

Component Lifecycle

App-Level Components

Located outside main#app — loaded once by App.loadAppInstances() and persist for the entire session.

Available lifecycle method:

  • tick() — called every frame via requestAnimationFrame

Page-Level Components

Located inside main#app — managed by the Page service.

Available lifecycle methods:

  • load() — called after instantiation, awaited (use for async setup)
  • resize() — called on window resize via Page.triggerEvent

Page-level components are destroyed when the user navigates to a new page.

Style Loading

Component-scoped SCSS files (style.scss) are eagerly imported via src/js/styles.js:

javascript
import.meta.glob([
  '../../components/sections/**/style.scss',
  '../../components/blocks/**/style.scss',
  '../../components/parts/**/style.scss'
], { eager: true })

This ensures Vite includes all component styles in the CSS bundle without manual imports.

Shop-Specific Modules

The src/js/shop/ directory contains commerce-specific logic:

ModulePurpose
cart.jsCart AJAX operations (add, update, remove)
wishlist.jsWishlist integration with the companion app
proxy.jsHTTP client for App Proxy requests
bundle-cart.jsBundle add-to-cart logic

Runtime Tailwind Config

The resolved Tailwind configuration is available at runtime via app.theme. This is made possible by a Vite resolve alias for tailwind.config.js, allowing JS components to read breakpoints, colors, and other design tokens.

Internal developer documentation