fix: Alpine.js defer race condition — blank pages on first load
Dynamic script creation (document.createElement) ignores the defer attribute per HTML spec — scripts are async regardless. Alpine.js CDN loaded fast and auto-initialized before page scripts had executed, causing ReferenceError for x-data functions (adminStores, dark, isSideMenuOpen, etc.) and blank pages. Fix: Replace dynamic script creation with static <script defer> tags and move extra_scripts block BEFORE Alpine.js in all 4 base templates (admin, store, merchant, storefront). Alpine.js is now always the last deferred script, ensuring all page functions are defined before it auto-initializes. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -144,35 +144,20 @@
|
|||||||
<!-- 8a. Alpine.js Collapse Plugin (must load before Alpine) -->
|
<!-- 8a. Alpine.js Collapse Plugin (must load before Alpine) -->
|
||||||
<script defer src="https://cdn.jsdelivr.net/npm/@alpinejs/collapse@3.13.3/dist/cdn.min.js"></script>
|
<script defer src="https://cdn.jsdelivr.net/npm/@alpinejs/collapse@3.13.3/dist/cdn.min.js"></script>
|
||||||
|
|
||||||
<!-- 8b. Alpine.js v3 with CDN fallback (with defer) -->
|
<!-- 8b. OPTIONAL: Chart.js with CDN fallback (loaded on demand via block) -->
|
||||||
<script>
|
|
||||||
(function() {
|
|
||||||
var script = document.createElement('script');
|
|
||||||
script.defer = true;
|
|
||||||
script.src = 'https://cdn.jsdelivr.net/npm/alpinejs@3.13.3/dist/cdn.min.js';
|
|
||||||
|
|
||||||
script.onerror = function() {
|
|
||||||
console.warn('Alpine.js CDN failed, loading local copy...');
|
|
||||||
var fallbackScript = document.createElement('script');
|
|
||||||
fallbackScript.defer = true;
|
|
||||||
fallbackScript.src = '{{ url_for("static", path="shared/js/lib/alpine.min.js") }}';
|
|
||||||
document.head.appendChild(fallbackScript);
|
|
||||||
};
|
|
||||||
|
|
||||||
document.head.appendChild(script);
|
|
||||||
})();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- 9. OPTIONAL: Chart.js with CDN fallback (loaded on demand via block) -->
|
|
||||||
{% block chartjs_script %}{% endblock %}
|
{% block chartjs_script %}{% endblock %}
|
||||||
|
|
||||||
<!-- 10. OPTIONAL: Flatpickr with CDN fallback (loaded on demand via block) -->
|
<!-- 8c. OPTIONAL: Flatpickr with CDN fallback (loaded on demand via block) -->
|
||||||
{% block flatpickr_script %}{% endblock %}
|
{% block flatpickr_script %}{% endblock %}
|
||||||
|
|
||||||
<!-- 11. OPTIONAL: Quill with CDN fallback (loaded on demand via block) -->
|
<!-- 8d. OPTIONAL: Quill with CDN fallback (loaded on demand via block) -->
|
||||||
{% block quill_script %}{% endblock %}
|
{% block quill_script %}{% endblock %}
|
||||||
|
|
||||||
<!-- 12. LAST: Page-specific scripts -->
|
<!-- 9. Page-specific scripts (MUST load before Alpine.js) -->
|
||||||
{% block extra_scripts %}{% endblock %}
|
{% block extra_scripts %}{% endblock %}
|
||||||
|
|
||||||
|
<!-- 10. LAST: Alpine.js v3 (must be last defer script — auto-initializes on load) -->
|
||||||
|
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.13.3/dist/cdn.min.js"
|
||||||
|
onerror="var s=document.createElement('script');s.defer=true;s.src='{{ url_for('static', path='shared/js/lib/alpine.min.js') }}';document.head.appendChild(s);"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -71,26 +71,11 @@
|
|||||||
<!-- 5. FIFTH: API Client (depends on Utils) -->
|
<!-- 5. FIFTH: API Client (depends on Utils) -->
|
||||||
<script defer src="{{ url_for('static', path='shared/js/api-client.js') }}"></script>
|
<script defer src="{{ url_for('static', path='shared/js/api-client.js') }}"></script>
|
||||||
|
|
||||||
<!-- 6. SIXTH: Alpine.js v3 with CDN fallback (with defer) -->
|
<!-- 6. Page-specific scripts (MUST load before Alpine.js) -->
|
||||||
<script>
|
|
||||||
(function() {
|
|
||||||
var script = document.createElement('script');
|
|
||||||
script.defer = true;
|
|
||||||
script.src = 'https://cdn.jsdelivr.net/npm/alpinejs@3.13.3/dist/cdn.min.js';
|
|
||||||
|
|
||||||
script.onerror = function() {
|
|
||||||
console.warn('Alpine.js CDN failed, loading local copy...');
|
|
||||||
var fallbackScript = document.createElement('script');
|
|
||||||
fallbackScript.defer = true;
|
|
||||||
fallbackScript.src = '{{ url_for("static", path="shared/js/lib/alpine.min.js") }}';
|
|
||||||
document.head.appendChild(fallbackScript);
|
|
||||||
};
|
|
||||||
|
|
||||||
document.head.appendChild(script);
|
|
||||||
})();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- 7. LAST: Page-specific scripts -->
|
|
||||||
{% block extra_scripts %}{% endblock %}
|
{% block extra_scripts %}{% endblock %}
|
||||||
|
|
||||||
|
<!-- 7. LAST: Alpine.js v3 (must be last defer script — auto-initializes on load) -->
|
||||||
|
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.13.3/dist/cdn.min.js"
|
||||||
|
onerror="var s=document.createElement('script');s.defer=true;s.src='{{ url_for('static', path='shared/js/lib/alpine.min.js') }}';document.head.appendChild(s);"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -94,26 +94,11 @@
|
|||||||
<!-- 7. SEVENTH: Upgrade Prompts (depends on API Client, registers with Alpine) -->
|
<!-- 7. SEVENTH: Upgrade Prompts (depends on API Client, registers with Alpine) -->
|
||||||
<script defer src="{{ url_for('billing_static', path='shared/js/upgrade-prompts.js') }}"></script>
|
<script defer src="{{ url_for('billing_static', path='shared/js/upgrade-prompts.js') }}"></script>
|
||||||
|
|
||||||
<!-- 8. EIGHTH: Alpine.js v3 with CDN fallback (with defer) -->
|
<!-- 8. Page-specific scripts (MUST load before Alpine.js) -->
|
||||||
<script>
|
|
||||||
(function() {
|
|
||||||
var script = document.createElement('script');
|
|
||||||
script.defer = true;
|
|
||||||
script.src = 'https://cdn.jsdelivr.net/npm/alpinejs@3.13.3/dist/cdn.min.js';
|
|
||||||
|
|
||||||
script.onerror = function() {
|
|
||||||
console.warn('Alpine.js CDN failed, loading local copy...');
|
|
||||||
var fallbackScript = document.createElement('script');
|
|
||||||
fallbackScript.defer = true;
|
|
||||||
fallbackScript.src = '{{ url_for("static", path="shared/js/lib/alpine.min.js") }}';
|
|
||||||
document.head.appendChild(fallbackScript);
|
|
||||||
};
|
|
||||||
|
|
||||||
document.head.appendChild(script);
|
|
||||||
})();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- 9. LAST: Page-specific scripts -->
|
|
||||||
{% block extra_scripts %}{% endblock %}
|
{% block extra_scripts %}{% endblock %}
|
||||||
|
|
||||||
|
<!-- 9. LAST: Alpine.js v3 (must be last defer script — auto-initializes on load) -->
|
||||||
|
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.13.3/dist/cdn.min.js"
|
||||||
|
onerror="var s=document.createElement('script');s.defer=true;s.src='{{ url_for('static', path='shared/js/lib/alpine.min.js') }}';document.head.appendChild(s);"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -380,28 +380,13 @@
|
|||||||
{# 6. API Client #}
|
{# 6. API Client #}
|
||||||
<script defer src="{{ url_for('static', path='shared/js/api-client.js') }}"></script>
|
<script defer src="{{ url_for('static', path='shared/js/api-client.js') }}"></script>
|
||||||
|
|
||||||
{# 7. Alpine.js with CDN fallback (deferred - loads last) #}
|
{# 7. Page-specific JavaScript (MUST load before Alpine.js) #}
|
||||||
<script>
|
|
||||||
(function() {
|
|
||||||
var script = document.createElement('script');
|
|
||||||
script.defer = true;
|
|
||||||
script.src = 'https://cdn.jsdelivr.net/npm/alpinejs@3.13.3/dist/cdn.min.js';
|
|
||||||
|
|
||||||
script.onerror = function() {
|
|
||||||
console.warn('Alpine.js CDN failed, loading local copy...');
|
|
||||||
var fallbackScript = document.createElement('script');
|
|
||||||
fallbackScript.defer = true;
|
|
||||||
fallbackScript.src = '{{ url_for("static", path="shared/js/lib/alpine.min.js") }}';
|
|
||||||
document.head.appendChild(fallbackScript);
|
|
||||||
};
|
|
||||||
|
|
||||||
document.head.appendChild(script);
|
|
||||||
})();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
{# 8. Page-specific JavaScript #}
|
|
||||||
{% block extra_scripts %}{% endblock %}
|
{% block extra_scripts %}{% endblock %}
|
||||||
|
|
||||||
|
{# 8. LAST: Alpine.js (must be last defer script — auto-initializes on load) #}
|
||||||
|
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.13.3/dist/cdn.min.js"
|
||||||
|
onerror="var s=document.createElement('script');s.defer=true;s.src='{{ url_for('static', path='shared/js/lib/alpine.min.js') }}';document.head.appendChild(s);"></script>
|
||||||
|
|
||||||
{# Toast notification container #}
|
{# Toast notification container #}
|
||||||
<div id="toast-container" class="fixed bottom-4 right-4 z-50"></div>
|
<div id="toast-container" class="fixed bottom-4 right-4 z-50"></div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user