88 lines
3.8 KiB
Markdown
88 lines
3.8 KiB
Markdown
# 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."
|