docs: Archive obsolete Alpine.js and ESBuild migration plans
Archives 6 migration planning documents that are now complete or obsolete: Completed Migrations (Safe to Delete): - ALPINE_GLOBAL_FIX_PART1.md: Alpine.global() → Alpine.store() migration COMPLETE - ESBUILD_MIGRATION_PLAN.md: ESBuild bundling and ES modules migration COMPLETE - ESBUILD_IMPORT_FIXES.md: ESBuild import corrections APPLIED Obsolete Reference Documents (Safe to Delete): - ESBUILD_SETUP_OLD.md: Superseded by ESBUILD_MIGRATION_PLAN.md - ESBUILD_README.md: Quick reference for completed migration Future Work (Retained as Reference): - ALPINE_COMPLETION_GUIDE.md: Reactive Alpine.js migration (OPTIONAL, not started) Migration Status Summary: ✅ Alpine.store() migration: All 26 files converted, 25 stores registered ✅ ESBuild bundling: main.ts imports all modules, 168KB bundle working ✅ Template integration: All function calls verified and working ✅ Build system: TypeScript compiles cleanly, no errors All critical migrations complete. App is in stable working baseline. Future reactive migration (ALPINE_COMPLETION_GUIDE.md) is optional and can be pursued later for smoother animations and modern patterns.
This commit is contained in:
@@ -1,387 +0,0 @@
|
||||
# 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)**:
|
||||
```typescript
|
||||
Alpine.global("namespace", {
|
||||
function1: () => { ... },
|
||||
function2: () => { ... }
|
||||
});
|
||||
```
|
||||
|
||||
**New Pattern (Correct)**:
|
||||
```typescript
|
||||
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**:
|
||||
```html
|
||||
<div x-data="{}">
|
||||
<button @click="namespace.function()">Click</button>
|
||||
</div>
|
||||
```
|
||||
|
||||
**New Syntax**:
|
||||
```html
|
||||
<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
|
||||
```bash
|
||||
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
|
||||
```bash
|
||||
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`):
|
||||
```typescript
|
||||
// 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)**
|
||||
```bash
|
||||
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:
|
||||
```bash
|
||||
grep -rn "Alpine\.global" . # Should return nothing after replacement
|
||||
grep -rn "Alpine\.store" . # Should show all 26 occurrences
|
||||
```
|
||||
|
||||
#### Step 1.4: Verify Changes
|
||||
```bash
|
||||
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
|
||||
```bash
|
||||
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
|
||||
```bash
|
||||
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**:
|
||||
```bash
|
||||
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**:
|
||||
```templ
|
||||
@click="header.changeThemeTo('wood-light')"
|
||||
@click="header.logout()"
|
||||
```
|
||||
|
||||
**After**:
|
||||
```templ
|
||||
@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
|
||||
```bash
|
||||
cd /home/nymusicman/Code/bookhoard
|
||||
docker-compose build
|
||||
```
|
||||
|
||||
#### Step 3.2: Restart Container
|
||||
```bash
|
||||
docker-compose down
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
#### Step 3.3: Verify Bundle
|
||||
```bash
|
||||
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**:
|
||||
```javascript
|
||||
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
|
||||
|
||||
- [Alpine.js Stores Documentation](https://alpinejs.dev/globals/alpine_store.html)
|
||||
- [Alpine.js Magic Properties ($store)](https://alpinejs.dev/magics/$store.html)
|
||||
- [Migration from Alpine v2 to v3](https://alpinejs.dev/upgrade-guide)
|
||||
|
||||
---
|
||||
|
||||
**Created**: 2026-03-09
|
||||
**Alpine.js Version**: 3.15.8
|
||||
**Status**: Ready for Implementation
|
||||
@@ -1,97 +0,0 @@
|
||||
# Import Fixes Applied to Migration Plan
|
||||
|
||||
## Summary
|
||||
|
||||
All imports in the ESBUILD_MIGRATION_PLAN.md have been corrected to use individual function imports instead of namespace objects, matching your actual module exports.
|
||||
|
||||
## Changes Made
|
||||
|
||||
### 1. TypeScript Imports (Phase 1)
|
||||
Changed from namespace imports to individual function imports:
|
||||
|
||||
**Before** (WRONG):
|
||||
```typescript
|
||||
import { api } from "./api";
|
||||
import { dom } from "./dom";
|
||||
import { events } from "./events";
|
||||
```
|
||||
|
||||
**After** (CORRECT):
|
||||
```typescript
|
||||
import { apiGet, apiPost, apiPut, apiDelete, apiPatch, handleResponse, handleVoidResponse, handleError } from "./api";
|
||||
import { querySelector, querySelectorAll, getElementById, createElement, ... } from "./dom";
|
||||
import { onDelegatedClick, onDelegatedSubmit, onDelegatedChange, ... } from "./events";
|
||||
```
|
||||
|
||||
### 2. Function Calls in TypeScript
|
||||
Changed from namespaced calls to direct function calls:
|
||||
|
||||
**Before** (WRONG):
|
||||
```typescript
|
||||
const response = await api.get("/libraries");
|
||||
showToast.success("Loaded!");
|
||||
const el = dom.getElementById("id");
|
||||
```
|
||||
|
||||
**After** (CORRECT):
|
||||
```typescript
|
||||
const response = await apiGet("/libraries");
|
||||
showToast("Loaded!", "success");
|
||||
const el = getElementById("id");
|
||||
```
|
||||
|
||||
### 3. Alpine/Template Calls (Phase 3)
|
||||
Keep namespace objects (Alpine creates these):
|
||||
|
||||
**CORRECT for Templates**:
|
||||
```html
|
||||
<button @click="api.post('/api/save', data)">Save</button>
|
||||
<button @click="showToast.success('Saved!')">Save</button>
|
||||
```
|
||||
|
||||
## Key Distinction
|
||||
|
||||
### TypeScript Code
|
||||
- **Imports**: Individual functions
|
||||
- **Calls**: Direct function calls with arguments
|
||||
- **Example**: `import { apiGet }` → `apiGet("/url")`
|
||||
|
||||
### Template/Alpine Code
|
||||
- **Imports**: None (Alpine handles this)
|
||||
- **Calls**: Namespaced via Alpine.global()
|
||||
- **Example**: `@click="api.post()"` (Alpine namespace)
|
||||
|
||||
## Files Affected
|
||||
|
||||
All TypeScript file examples in Phase 1 now show correct imports:
|
||||
- ✅ dashboard.ts
|
||||
- ✅ analytics.ts
|
||||
- ✅ library.ts
|
||||
- ✅ collections.ts
|
||||
- ✅ bookshelf.ts
|
||||
- ✅ api-explorer.ts
|
||||
- ✅ All others
|
||||
|
||||
## Verification
|
||||
|
||||
```bash
|
||||
# Verify no namespace imports remain in TypeScript sections
|
||||
grep "import { api } from\|import { dom } from\|import { events } from" ESBUILD_MIGRATION_PLAN.md | grep -v "//" | wc -l
|
||||
# Result: 0 ✅
|
||||
|
||||
# Verify Alpine namespace calls in templates
|
||||
grep '@click="api\.' ESBUILD_MIGRATION_PLAN.md | wc -l
|
||||
# Result: 3 ✅
|
||||
|
||||
# Verify TypeScript individual imports
|
||||
grep "import { apiGet" ESBUILD_MIGRATION_PLAN.md | wc -l
|
||||
# Result: 9 ✅
|
||||
```
|
||||
|
||||
## Plan Status
|
||||
|
||||
✅ **Ready to execute** - All imports corrected
|
||||
✅ **Consistent throughout** - TypeScript vs Alpine distinction clear
|
||||
✅ **Matches your actual exports** - No namespace objects exported from modules
|
||||
|
||||
You can now start Phase 0 with confidence!
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,210 +0,0 @@
|
||||
# ESBuild Migration - Quick Reference
|
||||
|
||||
## Status: Ready to Execute
|
||||
|
||||
**Created**: Complete migration plan (ESBUILD_MIGRATION_PLAN.md)
|
||||
**Archived**: Old incomplete plan (ESBUILD_SETUP_OLD.md)
|
||||
|
||||
## The Problem
|
||||
|
||||
- **274 window global references** across 21 TypeScript files
|
||||
- **193+ internal TypeScript dependencies** using window instead of ES imports
|
||||
- **27 template files** with 150+ unique onclick handlers
|
||||
- **Function wrapping** creating tight coupling
|
||||
- **Individual .js files** instead of single bundle
|
||||
|
||||
## The Solution
|
||||
|
||||
**Incremental migration** with no legacy code:
|
||||
|
||||
1. **Phase 0**: Add ES exports (1-2 hours) - Can ship ✅
|
||||
2. **Phase 1**: Convert internal dependencies (4-6 hours) - Can ship ✅
|
||||
3. **Phase 2**: Alpine.js bridge (2-3 hours) - Can ship ✅
|
||||
4. **Phase 3**: Template migration (27-54 hours) - Can ship per template ✅
|
||||
5. **Phase 4**: Data injection (1-2 hours) - Can ship ✅
|
||||
6. **Phase 5**: Cleanup (1-2 hours) - Final step
|
||||
|
||||
**Total**: 36-69 hours over ~5 weeks
|
||||
|
||||
## Key Architecture Decisions
|
||||
|
||||
### 1. ES Modules for TypeScript → TypeScript
|
||||
```typescript
|
||||
// library.ts
|
||||
import { api } from "./api";
|
||||
import { showToast } from "./toast";
|
||||
|
||||
const response = await api.get("/libraries");
|
||||
showToast.success("Loaded!");
|
||||
```
|
||||
|
||||
### 2. Alpine.js for Templates → TypeScript ONLY
|
||||
```typescript
|
||||
// api.ts (bottom of file)
|
||||
import { Alpine } from "./alpine";
|
||||
|
||||
Alpine.global("api", {
|
||||
get: apiGet,
|
||||
post: apiPost,
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
```html
|
||||
<!-- template -->
|
||||
<button @click="api.post('/api/save', data)">Save</button>
|
||||
```
|
||||
|
||||
### 3. SSR-First with Progressive Enhancement
|
||||
- Server renders complete HTML with data
|
||||
- Client-side JavaScript only for interactivity
|
||||
- Data loaded via fetch() APIs
|
||||
- No window globals for data
|
||||
|
||||
## File Changes
|
||||
|
||||
### 21 TypeScript Files
|
||||
All will have:
|
||||
- ES module exports (`export { functions }`)
|
||||
- ES module imports (`import { functions } from "./module"`)
|
||||
- Alpine registration (`Alpine.global("namespace", { ... })`)
|
||||
- NO window exports (cleaned up in Phase 5)
|
||||
|
||||
### 27 Template Files
|
||||
All will have:
|
||||
- Single script tag: `<script src="/static/main.js"></script>`
|
||||
- Alpine directives: `@click` instead of `onclick`
|
||||
- Alpine state: `x-data` for modals/dropdowns
|
||||
- NO individual .js file loads
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Right Now: Start Phase 0
|
||||
|
||||
```bash
|
||||
# 1. Open web/src/api.ts
|
||||
# 2. Add at bottom (after Alpine.global block):
|
||||
export { apiGet, apiPost, apiPut, apiDelete, apiPatch, handleResponse, handleVoidResponse, handleError };
|
||||
|
||||
# 3. Repeat for other utility modules (toast.ts, events.ts, theme.ts, header.ts, woodPaneling.ts)
|
||||
|
||||
# 4. Build and test
|
||||
npm run build:ts
|
||||
go run .
|
||||
```
|
||||
|
||||
### After Phase 0 Complete
|
||||
|
||||
Move to Phase 1: Convert internal dependencies (see full plan)
|
||||
|
||||
## Critical Path
|
||||
|
||||
**Must complete in order**:
|
||||
1. Phase 0 (ES exports) - Enables Phase 1
|
||||
2. Phase 1 (Internal imports) - Enables Phase 2
|
||||
3. Phase 2 (Alpine registration) - Enables Phase 3
|
||||
4. Phase 3 (Template migration) - Can do incrementally
|
||||
5. Phase 4 (Data injection) - Verify pattern
|
||||
6. Phase 5 (Cleanup) - Final polish
|
||||
|
||||
## Safety Features
|
||||
|
||||
✅ **Incremental**: Each phase is complete and testable
|
||||
✅ **Ship anytime**: Can deploy after Phases 0-2, or during Phase 3
|
||||
✅ **Easy rollback**: Revert individual files if issues
|
||||
✅ **No legacy**: Each file fully migrated, no half-states
|
||||
✅ **Testing**: Clear verification criteria for each phase
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Before Migration
|
||||
```typescript
|
||||
// TypeScript
|
||||
function doWork() { ... }
|
||||
(window as any).doWork = doWork;
|
||||
|
||||
// Another file
|
||||
const result = (window as any).doWork();
|
||||
```
|
||||
|
||||
```html
|
||||
<!-- Template -->
|
||||
<button onclick="doWork()">Click</button>
|
||||
```
|
||||
|
||||
### After Migration
|
||||
```typescript
|
||||
// work.ts
|
||||
export function doWork() { ... }
|
||||
import { Alpine } from "./alpine";
|
||||
Alpine.global("work", { doWork });
|
||||
|
||||
// Another file
|
||||
import { doWork } from "./work";
|
||||
const result = doWork();
|
||||
```
|
||||
|
||||
```html
|
||||
<!-- Template -->
|
||||
<button @click="work.doWork()">Click</button>
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
### After Each Phase
|
||||
```bash
|
||||
# Build
|
||||
npm run build:ts
|
||||
|
||||
# Run
|
||||
go run .
|
||||
|
||||
# Test
|
||||
# - Homepage loads
|
||||
# - Login works
|
||||
# - Dashboard loads
|
||||
# - No console errors
|
||||
# - No 404s for .js files
|
||||
```
|
||||
|
||||
## Rollback
|
||||
|
||||
If any phase has issues:
|
||||
```bash
|
||||
# Revert changes
|
||||
git checkout web/src/ # For TypeScript issues
|
||||
git checkout templates/PROBLEM.templ # For template issues
|
||||
|
||||
# Rebuild
|
||||
npm run build:ts
|
||||
templ generate
|
||||
go run .
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. **Read** the full plan: `ESBUILD_MIGRATION_PLAN.md`
|
||||
2. **Start** Phase 0: Add ES exports (1-2 hours)
|
||||
3. **Test** thoroughly after each phase
|
||||
4. **Track** progress using checklist in plan
|
||||
5. **Ask** questions if anything is unclear
|
||||
|
||||
## Resources
|
||||
|
||||
- **Full Plan**: ESBUILD_MIGRATION_PLAN.md (this document)
|
||||
- **Old Plan**: ESBUILD_SETUP_OLD.md (archived, incomplete)
|
||||
- **Alpine Docs**: https://alpinejs.dev/
|
||||
- **ESBuild Docs**: https://esbuild.github.io/
|
||||
- **Templ Docs**: https://github.com/a-h/templ
|
||||
|
||||
## Support
|
||||
|
||||
If you encounter issues:
|
||||
1. Check the "Troubleshooting" section in the full plan
|
||||
2. Review the "Testing Checklist" for your phase
|
||||
3. Use the "Rollback Procedures" if needed
|
||||
4. Reference the "Quick Reference" patterns
|
||||
|
||||
---
|
||||
|
||||
**Remember**: This is an incremental migration with clear phases. Take it one phase at a time, test thoroughly, and you'll have a clean, modern codebase ready for launch.
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user