WWW JavaScript Architecture

This document describes the organization and architecture of the WWW JavaScript codebase.

Directory Structure

client/js/www/
├── www.index.js              # Main entry point - orchestrates imports
├── application.js            # Legacy app init (minimal, being phased out)
├── contactFormInit.js        # Contact form dropdown handling
├── smart_services.js         # Smart services checkout flow
│
├── setup/                    # Core initialization modules
│   ├── turbo.js              # Turbo Drive configuration
│   ├── stimulus.js           # Stimulus controller registration
│   ├── bootstrap.js          # Bootstrap component initialization
│   ├── csrf.js               # CSRF token handling
│   ├── intl_tel_input.js     # International phone input
│   ├── features.js           # Declarative feature loader
│   └── app_init.js           # Core app setup, phone tracking
│
├── include/                  # External integrations
│   ├── externalScripts.js    # CallRail loading
│   └── crispChatWrapper.js   # Crisp chat integration
│
├── home/                     # Home page specific
│   └── wwwHome.js            # Home page initialization
│
├── euc/                      # DEPRECATED - Energy Usage Calculator (React)
│   └── (migrated to ViewComponent: Www::FloorHeatingCalculatorComponent)
│
├── smeuc/                    # DEPRECATED - Snow Melting EUC (React)
│   └── (migrated to ViewComponent: Www::SnowMeltingCalculatorComponent)
│
├── quotes/                   # Quote Builder (React)
│   └── quoteBuilder.index.js # Entry point
│
└── rp/                       # Room Planner (React)
    └── rpEdit.index.js       # Entry point

Entry Point: www.index.js

The main entry point orchestrates all JavaScript initialization:

// Setup modules (order matters)
import { initTurbo } from './setup/turbo';
import { initStimulus } from './setup/stimulus';
import { initBootstrap } from './setup/bootstrap';
import { initCsrf } from './setup/csrf';
import { initializeIntlTelInput } from './setup/intl_tel_input';
import { loadDeclaredFeatures } from './setup/features';
import { initApp, initWww } from './setup/app_init';

Setup Modules

turbo.js

Configures Turbo Drive for SPA-like navigation:

  • Enables Turbo Drive
  • Sets up cache key differentiation for user sessions
  • Handles session changes (login/logout)

stimulus.js

Registers Stimulus controllers:

  • Lazy-loads controllers from app/javascript/controllers
  • Handles controller namespacing

bootstrap.js

Initializes Bootstrap components:

  • Popovers with sanitization
  • Modals
  • Lightbox (@fancyapps/ui Fancybox)
  • Re-initializes on Turbo navigation

csrf.js

Manages CSRF tokens:

  • Updates tokens from globals.json
  • Sets up Turbo CSRF integration

intl_tel_input.js

International phone input formatting:

  • Initializes intl-tel-input library
  • Re-initializes on Turbo navigation
  • Handles hidden field sync

Video players

HLS/DASH video playback (Shaka Player) is initialized solely by the Stimulus
video-player controller (app/javascript/controllers/video_player_controller.js),
attached to every player <video> via data-controller="video-player". It picks
the core build or the Shaka-UI build (controls + chapter markers) based on
data-video-player-shaka-ui-value. There is no separate setup/video.js
auto-scanner — it was removed because it raced the controller and broke the
watch-page UI player.

features.js

Declarative feature loading:

  • Reads window.features or data-features attributes
  • Dynamically imports feature modules

app_init.js

Core application setup:

  • Phone tracking (CallRail)
  • Mobile detection
  • Legacy wwwAppInit() integration

React Applications

React apps use a WeakMap pattern to prevent createRoot warnings during Turbo navigation:

const reactRoots = new WeakMap();

function mount(element) {
  if (reactRoots.has(element)) {
    return reactRoots.get(element);
  }
  const root = createRoot(element);
  reactRoots.set(element, root);
  return root;
}

Turbo Integration

All JavaScript is Turbo-aware:

  • Event handlers use turbo:load instead of DOMContentLoaded
  • Components re-initialize on navigation
  • State resets on cache restoration

Global Exports

For backward compatibility, some functions are exported to window:

window.app = app;
window.mobileCheck = mobileCheck;
window.contactFormInit = contactFormInit;
window.isMobile = mobileCheck();

Adding New Features

  1. Stimulus Controller: Preferred for DOM interactions

    // app/javascript/controllers/my_feature_controller.js
    import { Controller } from "@hotwired/stimulus"
    export default class extends Controller {
      connect() { /* ... */ }
    }
    
  2. Setup Module: For global initialization

    // client/js/www/setup/my_feature.js
    export function initMyFeature() { /* ... */ }
    

    Then import in www.index.js

  3. React App: For complex interactive features

    // client/js/www/my_feature/myFeature.index.js
    import { createRoot } from 'react-dom/client';
    

Architecture Notes

No jQuery or Rails UJS

jQuery and Rails UJS have been fully removed. All code uses:

  • Stimulus controllers for DOM interactions
  • Vanilla JS for simple cases
  • Native fetch for AJAX

RJS (.js.erb files)

Legacy RJS responses are being replaced with:

  • Turbo Streams for partial updates
  • Turbo Frame responses
  • JSON API responses

Related Documentation