Files
bookhoard/ALPINE_GLOBAL_FIX_PART1.md
T
john-okeefe 0a5042e130 docs: add Alpine.js migration guide for global() → store() API
Add comprehensive migration documentation for transitioning from the invalid
Alpine.global() API to the correct Alpine.store() API.

This guide addresses:
- Critical issue: Alpine.global() does not exist in Alpine.js v3.15.8
- 26 TypeScript files requiring updates
- Step-by-step migration instructions
- Template syntax changes (namespace.function() → $store.namespace.function())
- Testing checklist and troubleshooting guide

The migration will fix the "p.global is not a function" error currently
breaking the theme switcher and all Alpine namespaces.

Part 1 of 2 - covers TypeScript and template file updates.
2026-03-09 21:23:07 -04:00

12 KiB

Alpine.js Alpine.global()Alpine.store() Migration Guide - Part 1

🔴 Critical Issue Identified

Problem: Your codebase uses Alpine.global() which DOES NOT EXIST in Alpine.js v3.15.8. This is causing the error:

Uncaught TypeError: p.global is not a function

📋 Root Cause Analysis

  1. Invalid API Usage: Alpine.global() is not a valid Alpine.js v3 method
  2. 26 Occurrences: Found across 26 TypeScript files
  3. Breaking Impact: Theme switcher and all Alpine namespaces are broken

Solution Overview

Replace all Alpine.global() calls with Alpine.store(), the correct Alpine.js v3 API for registering global utilities.

Current Pattern (Broken):

Alpine.global("namespace", {
  function1: () => { ... },
  function2: () => { ... }
});

New Pattern (Correct):

Alpine.store("namespace", {
  function1: () => { ... },
  function2: () => { ... }
});

Template Usage Changes:

  • Old: @click="namespace.function()"@click="$store.namespace.function()"

📁 Files Requiring Changes (26 TypeScript files)

Step 1: Update TypeScript Files

For each file, replace Alpine.global() with Alpine.store():

File Line Namespace Action
admin.ts 399 admin Replace Alpine.global with Alpine.store
api.ts 102 api Replace Alpine.global with Alpine.store
api-explorer-docs.ts 135 apiExplorerDoc Replace Alpine.global with Alpine.store
bookshelf.ts 199 bookshelf Replace Alpine.global with Alpine.store
collection-rules.ts 411 collectionRules Replace Alpine.global with Alpine.store
collections.ts 917 collections Replace Alpine.global with Alpine.store
conflicts.ts 219 conflicts Replace Alpine.global with Alpine.store
device-management.ts 559 devices Replace Alpine.global with Alpine.store
docs.ts 96, 103 docs Replace Alpine.global with Alpine.store (2 occurrences)
header.ts 35 header Replace Alpine.global with Alpine.store
index.ts 46 index Replace Alpine.global with Alpine.store
library.ts 683 library Replace Alpine.global with Alpine.store
linking.ts 204 linking Replace Alpine.global with Alpine.store
login.ts 25 login Replace Alpine.global with Alpine.store
password_validation.ts 192 validation Replace Alpine.global with Alpine.store
profile.ts 44 profile Replace Alpine.global with Alpine.store
profile-modal.ts 29 profileModal Replace Alpine.global with Alpine.store
queue.ts 167 queue Replace Alpine.global with Alpine.store
register.ts 14 register Replace Alpine.global with Alpine.store
search.ts 310 search Replace Alpine.global with Alpine.store
themeDropdown.ts 24 themeDropdown Replace Alpine.global with Alpine.store
toast.ts 229 showToast Replace Alpine.global with Alpine.store
toast-error.ts 33 toastError Replace Alpine.global with Alpine.store
unlinked_books.ts 430 unlinkedBooks Replace Alpine.global with Alpine.store
woodPaneling.ts 85 woodPaneling Replace Alpine.global with Alpine.store

Step 2: Update Template Files

For each .templ file that uses Alpine namespaces, update the syntax:

Old Syntax:

<div x-data="{}">
  <button @click="namespace.function()">Click</button>
</div>

New Syntax:

<div x-data="{}">
  <button @click="$store.namespace.function()">Click</button>
</div>

Templates Requiring Updates (to be identified by searching for namespace usage):

  • All templates using @click="admin."
  • All templates using @click="api."
  • All templates using @click="header."
  • All templates using @click="showToast."
  • All templates using any other namespace from the list above

🔧 Detailed Step-by-Step Instructions

Phase 1: Update TypeScript Source Files

Step 1.1: Backup Current State

cd /home/nymusicman/Code/bookhoard
git add -A
git commit -m "Backup before Alpine.global() → Alpine.store() migration"

Step 1.2: Find All Alpine.global Occurrences

cd /home/nymusicman/Code/bookhoard/web/src
grep -rn "Alpine\.global" . | tee alpine-global-occurrences.txt

Expected output: 26 occurrences across 26 files

Step 1.3: Replace All Alpine.global with Alpine.store

Option A: Manual Replacement (Recommended for Understanding) For each file in the table above:

  1. Open the file
  2. Find the Alpine.global() call
  3. Replace Alpine.global with Alpine.store
  4. Save the file

Example (web/src/toast.ts:229):

// BEFORE (Line 229):
Alpine.global("showToast", {
  error: (message: string, duration?: number) =>
    showToast(message, "error", duration),
  success: (message: string, duration?: number) =>
    showToast(message, "success", duration),
  info: (message: string, duration?: number) =>
    showToast(message, "info", duration),
});

// AFTER (Line 229):
Alpine.store("showToast", {
  error: (message: string, duration?: number) =>
    showToast(message, "error", duration),
  success: (message: string, duration?: number) =>
    showToast(message, "success", duration),
  info: (message: string, duration?: number) =>
    showToast(message, "info", duration),
});

Option B: Automated Replacement (Faster)

cd /home/nymusicman/Code/bookhoard/web/src
find . -name "*.ts" -type f -exec sed -i 's/Alpine\.global(/Alpine.store(/g' {} \;

⚠️ Warning: Automated replacement will change all 26 occurrences at once. Verify with grep first:

grep -rn "Alpine\.global" .  # Should return nothing after replacement
grep -rn "Alpine\.store" .   # Should show all 26 occurrences

Step 1.4: Verify Changes

cd /home/nymusicman/Code/bookhoard/web/src
grep -c "Alpine\.store" *.ts | grep -v ":0"

Expected: Each of the 26 files should show 1 occurrence (except docs.ts which should show 2)

Step 1.5: Rebuild TypeScript

cd /home/nymusicman/Code/bookhoard/web
npm run build:ts

Expected output:

> bookhoard@1.0.0 build:ts
> cp node_modules/htmx.org/dist/htmx.min.js web/static/htmx.min.js && esbuild web/src/main.ts --bundle --outfile=web/static/main.js --sourcemap --target=es2020 --minify

  web/static/main.js      167.9kb
  web/static/main.js.map  538.7kb
⚡ Done in 18ms

Phase 2: Update Template Files

Step 2.1: Find All Namespace Usage in Templates

cd /home/nymusicman/Code/bookhoard/templates
grep -rn '@click="' .

This will show all click handlers that use namespaces. Look for patterns like:

  • @click="admin.deleteConfirm"
  • @click="api.getUrl"
  • @click="header.changeThemeTo"
  • @click="showToast.error"
  • etc.

Step 2.2: Create Mapping Document

Create a text file with the old → new namespace mappings:

admin.function() → $store.admin.function()
api.function() → $store.api.function()
apiExplorerDoc.function() → $store.apiExplorerDoc.function()
bookshelf.function() → $store.bookshelf.function()
collectionRules.function() → $store.collectionRules.function()
collections.function() → $store.collections.function()
conflicts.function() → $store.conflicts.function()
devices.function() → $store.devices.function()
docs.function() → $store.docs.function()
header.function() → $store.header.function()
index.function() → $store.index.function()
library.function() → $store.library.function()
linking.function() → $store.linking.function()
login.function() → $store.login.function()
validation.function() → $store.validation.function()
profile.function() → $store.profile.function()
profileModal.function() → $store.profileModal.function()
queue.function() → $store.queue.function()
register.function() → $store.register.function()
search.function() → $store.search.function()
themeDropdown.function() → $store.themeDropdown.function()
showToast.function() → $store.showToast.function()
toastError.function() → $store.toastError.function()
unlinkedBooks.function() → $store.unlinkedBooks.function()
woodPaneling.function() → $store.woodPaneling.function()

Step 2.3: Update Templates (Iterative Approach)

For each namespace found in templates:

  1. Search for all usages:

    cd /home/nymusicman/Code/bookhoard/templates
    grep -rn 'namespace\.' . | grep "@click"
    

    Replace namespace with the actual namespace name (e.g., admin, header, etc.)

  2. Replace in each file manually or using find/replace:

    • Find: @click="namespace.functionName"
    • Replace: @click="$store.namespace.functionName"

Example for header.templ:

Before:

@click="header.changeThemeTo('wood-light')"
@click="header.logout()"

After:

@click="$store.header.changeThemeTo('wood-light')"
@click="$store.header.logout()"

Step 2.4: Critical Template Priority

Update templates in this order (most critical first):

  1. header.templ - Theme switcher (currently broken)
  2. index.templ - Main page
  3. library.templ - Core functionality
  4. collections.templ - Collection management
  5. bookshelf.templ - Book display
  6. api_explorer.templ - API testing
  7. admin.templ - Admin panel
  8. profile.templ - User profile
  9. login.templ - Authentication
  10. register.templ - Registration
  11. All other templates with namespace usage

Phase 3: Test the Migration

Step 3.1: Rebuild Container

cd /home/nymusicman/Code/bookhoard
docker-compose build

Step 3.2: Restart Container

docker-compose down
docker-compose up -d

Step 3.3: Verify Bundle

podman exec bookhoard grep -c "\.store(" /root/web/static/main.js

Expected: Should show all Alpine.store() calls (not Alpine.global())

Step 3.4: Test Theme Switcher (Critical)

  1. Open http://localhost:8765 in browser
  2. Hard refresh: Ctrl+Shift+R
  3. Open browser console (F12)
  4. Click theme dropdown
  5. Select a theme
  6. Expected: Theme changes without error
  7. Expected Console:
    Alpine.store('showToast')  // Should return object, not undefined
    Alpine.store('header')     // Should return object, not undefined
    

Step 3.5: Verify No Errors

Check browser console for:

  • No p.global is not a function errors
  • No Uncaught TypeError messages
  • Alpine version shows: 3.15.8
  • Stores are accessible via $store

📊 Testing Checklist

After completing the migration, verify:

  • No Alpine.global in any .ts file
  • All 26 Alpine.store registrations present
  • Bundle size approximately 168KB
  • Browser console shows no errors
  • Theme switcher works correctly
  • All dropdown menus open/close properly
  • Toast notifications display correctly
  • All forms submit without errors
  • All click handlers work as expected
  • Alpine directives (x-show, @click, etc.) work correctly

🐛 Troubleshooting

Error: "Cannot read property 'function' of undefined"

Cause: Template still using old syntax namespace.function()
Fix: Change to $store.namespace.function()

Error: "Alpine.store is not a function"

Cause: TypeScript build didn't complete or using cached main.js
Fix: Run npm run build:ts and rebuild container

Error: "p.global is not a function" (still)

Cause: Some files still have Alpine.global()
Fix: Run grep -rn "Alpine\.global" web/src to find remaining occurrences

Theme switcher still broken

Cause: header.templ not updated with new syntax
Fix: Update all @click="header." to @click="$store.header."


📝 Next Steps (After This Guide)

Part 2 will cover:

  1. Advanced Alpine store patterns
  2. Reactive state management with stores
  3. Testing strategies for all templates
  4. Performance optimization
  5. Rollback plan if needed

🔗 References


Created: 2026-03-09
Alpine.js Version: 3.15.8
Status: Ready for Implementation