initial commit
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
# ShopProQuote JS Debugging Patterns
|
||||
|
||||
## Silent module load failure from SyntaxError
|
||||
|
||||
**Symptom:** A feature is "stuck loading" despite the HTML being correct and the backend responding. The page shows a permanent "Loading..." state.
|
||||
|
||||
**Root cause:** A syntax error in a `<script>`-loaded JS file prevents the ENTIRE module from executing. Common in ShopProQuote because JS files are loaded as regular scripts (not ES modules with isolated scopes).
|
||||
|
||||
**Example from dashboard briefing (June 2026):**
|
||||
```js
|
||||
// Line ~3926
|
||||
const briefingText = dsResult.choices?.[0]?.message?.content?.trim() || '';
|
||||
// ... later, line ~3944, same function scope:
|
||||
const briefingText = contentDiv.textContent || ''; // 💥 SyntaxError: redeclaration of const
|
||||
```
|
||||
|
||||
JavaScript refuses to parse the file, `window.generateDailyBriefing` is never defined, the inline fallback in `index.html` polls forever for it, and the user sees "Loading briefing..." permanently.
|
||||
|
||||
## Debugging steps
|
||||
|
||||
1. **Check if the function exists at all:**
|
||||
```js
|
||||
// In browser console
|
||||
typeof window.generateDailyBriefing // 'undefined' = module never loaded
|
||||
```
|
||||
|
||||
2. **Syntax-check the file (if Node.js available):**
|
||||
```bash
|
||||
node -c dashboard.js
|
||||
```
|
||||
|
||||
3. **Without Node.js, grep for duplicate declarations:**
|
||||
```bash
|
||||
# Find duplicate const declarations in the same function
|
||||
sed -n '/async function generateDailyBriefing/,/^ }/p' dashboard.js | grep -P "^\s*const \w+ =" | awk '{print $2}' | sort | uniq -d
|
||||
```
|
||||
|
||||
4. **Check browser console** — a SyntaxError appears but users often miss it.
|
||||
|
||||
## Proxy verification pattern
|
||||
|
||||
When an AI feature relies on an nginx proxy, verify the proxy works independently of the frontend:
|
||||
|
||||
```bash
|
||||
curl -k -X POST https://127.0.0.1/deepseek/v1/chat/completions \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"model":"deepseek-v4-flash","messages":[{"role":"user","content":"test"}],"max_tokens":10}'
|
||||
```
|
||||
|
||||
This separates "proxy broken" from "JS broken."
|
||||
|
||||
## "Button does nothing" — element existence guard pattern
|
||||
|
||||
When clicking a submit button produces literally zero visible effect (no spinner, no error, no console message beyond a hidden TypeError), the most likely cause is that one or more DOM elements the handler reads from are `null`. The form element exists in the HTML, but at the time the handler fires, it's not in the DOM (dynamic insertion timing, modal re-opening, or form.reset() clearing dynamic content).
|
||||
|
||||
### Defensive pattern
|
||||
|
||||
Instead of directly chaining `.value` on `document.getElementById()` calls, capture each element reference first, check for null, and log which ones are missing:
|
||||
|
||||
```js
|
||||
async function handleCreateTask() {
|
||||
console.log('🔍 handleCreateTask() called');
|
||||
const titleEl = document.getElementById('new-task-title');
|
||||
const dueDateEl = document.getElementById('new-task-due-date');
|
||||
const dueTimeEl = document.getElementById('new-task-due-time');
|
||||
|
||||
if (!titleEl || !dueDateEl || !dueTimeEl) {
|
||||
console.error('❌ Missing form elements:', {
|
||||
title: !!titleEl, dueDate: !!dueDateEl, dueTime: !!dueTimeEl
|
||||
});
|
||||
showNotification('Form elements not found. Please refresh the page.', true);
|
||||
return;
|
||||
}
|
||||
|
||||
const title = titleEl.value.trim();
|
||||
// ... rest of handler
|
||||
}
|
||||
```
|
||||
|
||||
This pattern accomplishes three things simultaneously:
|
||||
1. The `console.log` at line 1 proves the handler even fired (vs HTML5 validation blocking submit)
|
||||
2. The null checks pinpoint exactly which element is missing
|
||||
3. The early return with notification gives the user a visible message instead of silent failure
|
||||
|
||||
### Why this beats try/catch alone
|
||||
|
||||
A `try/catch` wrapping the handler body catches the TypeError, but you don't know WHICH element caused it without the logged boolean map. And you can't show a meaningful error message — just "something went wrong."
|
||||
Reference in New Issue
Block a user