fix(cache-bust): close FE-024 gaps so every JS/CSS gets ?v=<sha>
Some checks failed
Some checks failed
The 2026-05-18 cache-busting system was only catching a fraction of
includes because:
1. FE-024 anti-pattern only matched `'<module>_static'` mount names
(e.g. `'core_static'`, `'billing_static'`). The bare `'static'`
mount — which is what every persona base.html uses for shared JS,
CSS, and Tailwind output — never matched.
2. The rule explicitly excluded `base.html` files, which are exactly
where most of the shared JS/CSS includes live.
User reported only a handful of files had `?v=` in their Network tab.
Swept 5 persona base.html + 15 standalone templates (login/register/
forgot/reset password, error pages, onboarding, invitation-accept,
admin module-info/config, etc.) — 53 url_for('static', ...) refs for
.js/.css converted to static_v(request, 'static', ...).
Then tightened FE-024:
- Added an anti-pattern for the bare `'static'` mount.
- Dropped `base.html` from exceptions (kept `partials/`).
Re-running the validator: same 126-warning baseline, 0 FE-024 hits.
Now every deploy flips the `?v=<sha>` query string on every shared
asset; browsers refetch automatically without a hard refresh.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1027,9 +1027,9 @@ frontend_component_rules:
|
||||
file_pattern: "app/**/templates/**/*.html"
|
||||
anti_patterns:
|
||||
- "url_for\\(\\s*['\"]\\w+_static['\"]\\s*,\\s*path=['\"][^'\"]+\\.(?:js|css)['\"]"
|
||||
- "url_for\\(\\s*['\"]static['\"]\\s*,\\s*path=['\"][^'\"]+\\.(?:js|css)['\"]"
|
||||
- "(?:src|href)=['\"]/static/[^'\"]+\\.(?:js|css)['\"]"
|
||||
exceptions:
|
||||
- "base.html"
|
||||
- "partials/"
|
||||
|
||||
# ============================================================================
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
</style>
|
||||
|
||||
{# Tailwind CSS v4 (built locally via standalone CLI) #}
|
||||
<link rel="stylesheet" href="{{ url_for('static', path='storefront/css/tailwind.output.css') }}">
|
||||
<link rel="stylesheet" href="{{ static_v(request, 'static', path='storefront/css/tailwind.output.css') }}">
|
||||
</head>
|
||||
<body>
|
||||
<div class="flex items-center min-h-screen p-6 bg-gray-50 dark:bg-gray-900" x-cloak>
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
</style>
|
||||
|
||||
{# Tailwind CSS v4 (built locally via standalone CLI) #}
|
||||
<link rel="stylesheet" href="{{ url_for('static', path='storefront/css/tailwind.output.css') }}">
|
||||
<link rel="stylesheet" href="{{ static_v(request, 'static', path='storefront/css/tailwind.output.css') }}">
|
||||
</head>
|
||||
<body>
|
||||
<div class="flex items-center min-h-screen p-6 bg-gray-50 dark:bg-gray-900" x-cloak>
|
||||
@@ -182,7 +182,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Icons (registers $icon magic helper for Alpine) -->
|
||||
<script defer src="{{ url_for('static', path='shared/js/icons.js') }}"></script>
|
||||
<script defer src="{{ static_v(request, 'static', path='shared/js/icons.js') }}"></script>
|
||||
|
||||
<!-- Alpine.js v3 -->
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.14.0/dist/cdn.min.js"></script>
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
</style>
|
||||
|
||||
{# Tailwind CSS v4 (built locally via standalone CLI) #}
|
||||
<link rel="stylesheet" href="{{ url_for('static', path='storefront/css/tailwind.output.css') }}">
|
||||
<link rel="stylesheet" href="{{ static_v(request, 'static', path='storefront/css/tailwind.output.css') }}">
|
||||
</head>
|
||||
<body>
|
||||
<div class="flex items-center min-h-screen p-6 bg-gray-50 dark:bg-gray-900" x-cloak>
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
</style>
|
||||
|
||||
{# Tailwind CSS v4 (built locally via standalone CLI) #}
|
||||
<link rel="stylesheet" href="{{ url_for('static', path='storefront/css/tailwind.output.css') }}">
|
||||
<link rel="stylesheet" href="{{ static_v(request, 'static', path='storefront/css/tailwind.output.css') }}">
|
||||
</head>
|
||||
<body>
|
||||
<div class="flex items-center min-h-screen p-6 bg-gray-50 dark:bg-gray-900" x-cloak>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<title>Welcome to Orion - Setup Your Account</title>
|
||||
<link href="{{ static_v(request, 'static', path='shared/fonts/inter.css') }}" rel="stylesheet" />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="{{ url_for('static', path='store/css/tailwind.output.css') }}" />
|
||||
<link rel="stylesheet" href="{{ static_v(request, 'static', path='store/css/tailwind.output.css') }}" />
|
||||
<style>
|
||||
[x-cloak] { display: none !important; }
|
||||
</style>
|
||||
@@ -373,10 +373,10 @@
|
||||
</div>
|
||||
|
||||
<!-- Scripts -->
|
||||
<script defer src="{{ url_for('static', path='shared/js/log-config.js') }}"></script>
|
||||
<script defer src="{{ url_for('static', path='shared/js/icons.js') }}"></script>
|
||||
<script defer src="{{ url_for('static', path='shared/js/utils.js') }}"></script>
|
||||
<script defer src="{{ url_for('static', path='shared/js/api-client.js') }}"></script>
|
||||
<script defer src="{{ static_v(request, 'static', path='shared/js/log-config.js') }}"></script>
|
||||
<script defer src="{{ static_v(request, 'static', path='shared/js/icons.js') }}"></script>
|
||||
<script defer src="{{ static_v(request, 'static', path='shared/js/utils.js') }}"></script>
|
||||
<script defer src="{{ static_v(request, 'static', path='shared/js/api-client.js') }}"></script>
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.14.0/dist/cdn.min.js"></script>
|
||||
<script defer src="{{ static_v(request, 'marketplace_static', path='store/js/onboarding.js') }}"></script>
|
||||
</body>
|
||||
|
||||
@@ -8,12 +8,12 @@
|
||||
<!-- Fonts: Local fallback + Google Fonts -->
|
||||
<link href="{{ static_v(request, 'static', path='shared/fonts/inter.css') }}" rel="stylesheet" />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="{{ url_for('static', path='admin/css/tailwind.output.css') }}" />
|
||||
<link rel="stylesheet" href="{{ static_v(request, 'static', path='admin/css/tailwind.output.css') }}" />
|
||||
<!-- Flag Icons CSS (for language selector) with local fallback -->
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/npm/flag-icons@7.2.3/css/flag-icons.min.css"
|
||||
onerror="this.onerror=null; this.href='{{ url_for('static', path='shared/css/store/flag-icons.min.css') }}';"
|
||||
onerror="this.onerror=null; this.href='{{ static_v(request, 'static', path='shared/css/store/flag-icons.min.css') }}';"
|
||||
/>
|
||||
<style>
|
||||
[x-cloak] { display: none !important; }
|
||||
@@ -181,16 +181,16 @@
|
||||
<script>window.FRONTEND_TYPE = '{{ frontend_type | default("admin") }}';</script>
|
||||
|
||||
<!-- 1. Log Configuration -->
|
||||
<script defer src="{{ url_for('static', path='shared/js/log-config.js') }}"></script>
|
||||
<script defer src="{{ static_v(request, 'static', path='shared/js/log-config.js') }}"></script>
|
||||
|
||||
<!-- 2. Icons -->
|
||||
<script defer src="{{ url_for('static', path='shared/js/icons.js') }}"></script>
|
||||
<script defer src="{{ static_v(request, 'static', path='shared/js/icons.js') }}"></script>
|
||||
|
||||
<!-- 3. Utils -->
|
||||
<script defer src="{{ url_for('static', path='shared/js/utils.js') }}"></script>
|
||||
<script defer src="{{ static_v(request, 'static', path='shared/js/utils.js') }}"></script>
|
||||
|
||||
<!-- 4. API Client -->
|
||||
<script defer src="{{ url_for('static', path='shared/js/api-client.js') }}"></script>
|
||||
<script defer src="{{ static_v(request, 'static', path='shared/js/api-client.js') }}"></script>
|
||||
|
||||
<!-- 5. Alpine.js v3 with CDN fallback -->
|
||||
<script>
|
||||
|
||||
@@ -148,5 +148,5 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_scripts %}
|
||||
<script defer src="{{ url_for('static', path='admin/js/module-config.js') }}"></script>
|
||||
<script defer src="{{ static_v(request, 'static', path='admin/js/module-config.js') }}"></script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -270,5 +270,5 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_scripts %}
|
||||
<script defer src="{{ url_for('static', path='admin/js/module-info.js') }}"></script>
|
||||
<script defer src="{{ static_v(request, 'static', path='admin/js/module-info.js') }}"></script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<title>Select Platform - Admin Panel</title>
|
||||
<link href="{{ static_v(request, 'static', path='shared/fonts/inter.css') }}" rel="stylesheet" />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="{{ url_for('static', path='admin/css/tailwind.output.css') }}" />
|
||||
<link rel="stylesheet" href="{{ static_v(request, 'static', path='admin/css/tailwind.output.css') }}" />
|
||||
<style>[x-cloak] { display: none !important; }</style>
|
||||
</head>
|
||||
<body x-cloak>
|
||||
@@ -173,10 +173,10 @@
|
||||
</div>
|
||||
|
||||
<!-- Scripts -->
|
||||
<script defer src="{{ url_for('static', path='shared/js/log-config.js') }}"></script>
|
||||
<script defer src="{{ url_for('static', path='shared/js/utils.js') }}"></script>
|
||||
<script defer src="{{ url_for('static', path='shared/js/api-client.js') }}"></script>
|
||||
<script defer src="{{ url_for('static', path='shared/js/icons.js') }}"></script>
|
||||
<script defer src="{{ static_v(request, 'static', path='shared/js/log-config.js') }}"></script>
|
||||
<script defer src="{{ static_v(request, 'static', path='shared/js/utils.js') }}"></script>
|
||||
<script defer src="{{ static_v(request, 'static', path='shared/js/api-client.js') }}"></script>
|
||||
<script defer src="{{ static_v(request, 'static', path='shared/js/icons.js') }}"></script>
|
||||
<script defer src="{{ static_v(request, 'tenancy_static', path='admin/js/select-platform.js') }}"></script>
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.13.3/dist/cdn.min.js"></script>
|
||||
</body>
|
||||
|
||||
@@ -9,12 +9,12 @@
|
||||
<!-- Fonts: Local fallback + Google Fonts -->
|
||||
<link href="{{ static_v(request, 'static', path='shared/fonts/inter.css') }}" rel="stylesheet" />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="{{ url_for('static', path='merchant/css/tailwind.output.css') }}" />
|
||||
<link rel="stylesheet" href="{{ static_v(request, 'static', path='merchant/css/tailwind.output.css') }}" />
|
||||
<!-- Flag Icons CSS (for language selector) with local fallback -->
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/npm/flag-icons@7.2.3/css/flag-icons.min.css"
|
||||
onerror="this.onerror=null; this.href='{{ url_for('static', path='shared/css/store/flag-icons.min.css') }}';"
|
||||
onerror="this.onerror=null; this.href='{{ static_v(request, 'static', path='shared/css/store/flag-icons.min.css') }}';"
|
||||
/>
|
||||
<style>
|
||||
[x-cloak] { display: none !important; }
|
||||
@@ -182,16 +182,16 @@
|
||||
<script>window.FRONTEND_TYPE = '{{ frontend_type | default("merchant") }}';</script>
|
||||
|
||||
<!-- 1. Log Configuration -->
|
||||
<script defer src="{{ url_for('static', path='shared/js/log-config.js') }}"></script>
|
||||
<script defer src="{{ static_v(request, 'static', path='shared/js/log-config.js') }}"></script>
|
||||
|
||||
<!-- 2. Icons -->
|
||||
<script defer src="{{ url_for('static', path='shared/js/icons.js') }}"></script>
|
||||
<script defer src="{{ static_v(request, 'static', path='shared/js/icons.js') }}"></script>
|
||||
|
||||
<!-- 3. Utils -->
|
||||
<script defer src="{{ url_for('static', path='shared/js/utils.js') }}"></script>
|
||||
<script defer src="{{ static_v(request, 'static', path='shared/js/utils.js') }}"></script>
|
||||
|
||||
<!-- 4. API Client -->
|
||||
<script defer src="{{ url_for('static', path='shared/js/api-client.js') }}"></script>
|
||||
<script defer src="{{ static_v(request, 'static', path='shared/js/api-client.js') }}"></script>
|
||||
|
||||
<!-- 5. Alpine.js v3 with CDN fallback -->
|
||||
<script>
|
||||
|
||||
@@ -8,11 +8,11 @@
|
||||
<title>Accept Invitation - {{ invitation.store_name if invitation else 'Store' }}</title>
|
||||
<link href="{{ static_v(request, 'static', path='shared/fonts/inter.css') }}" rel="stylesheet" />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="{{ url_for('static', path='store/css/tailwind.output.css') }}" />
|
||||
<link rel="stylesheet" href="{{ static_v(request, 'static', path='store/css/tailwind.output.css') }}" />
|
||||
<style>
|
||||
[x-cloak] { display: none !important; }
|
||||
</style>
|
||||
<script src="{{ url_for('static', path='shared/js/dev-toolbar.js') }}"></script>
|
||||
<script src="{{ static_v(request, 'static', path='shared/js/dev-toolbar.js') }}"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="flex items-center min-h-screen p-6 bg-gray-50 dark:bg-gray-900" x-cloak>
|
||||
@@ -140,9 +140,9 @@
|
||||
|
||||
<!-- Scripts -->
|
||||
<script>window.FRONTEND_TYPE = '{{ frontend_type | default("store") }}';</script>
|
||||
<script defer src="{{ url_for('static', path='shared/js/log-config.js') }}"></script>
|
||||
<script defer src="{{ url_for('static', path='shared/js/icons.js') }}"></script>
|
||||
<script defer src="{{ url_for('static', path='shared/js/api-client.js') }}"></script>
|
||||
<script defer src="{{ static_v(request, 'static', path='shared/js/log-config.js') }}"></script>
|
||||
<script defer src="{{ static_v(request, 'static', path='shared/js/icons.js') }}"></script>
|
||||
<script defer src="{{ static_v(request, 'static', path='shared/js/api-client.js') }}"></script>
|
||||
<script>
|
||||
(function() {
|
||||
var script = document.createElement('script');
|
||||
|
||||
@@ -8,13 +8,13 @@
|
||||
<!-- Fonts: Local fallback + Google Fonts -->
|
||||
<link href="{{ static_v(request, 'static', path='shared/fonts/inter.css') }}" rel="stylesheet" />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="{{ url_for('static', path='store/css/tailwind.output.css') }}" />
|
||||
<link rel="stylesheet" href="{{ static_v(request, 'static', path='store/css/tailwind.output.css') }}" />
|
||||
<style>
|
||||
[x-cloak] { display: none !important; }
|
||||
</style>
|
||||
|
||||
<!-- Dev debug toolbar (dev only — auto-hides in production, must load early for interceptors) -->
|
||||
<script src="{{ url_for('static', path='shared/js/dev-toolbar.js') }}"></script>
|
||||
<script src="{{ static_v(request, 'static', path='shared/js/dev-toolbar.js') }}"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="flex items-center min-h-screen p-6 bg-gray-50 dark:bg-gray-900" x-cloak>
|
||||
@@ -212,16 +212,16 @@
|
||||
<script>window.FRONTEND_TYPE = '{{ frontend_type | default("store") }}';</script>
|
||||
|
||||
<!-- 1. Log Configuration -->
|
||||
<script defer src="{{ url_for('static', path='shared/js/log-config.js') }}"></script>
|
||||
<script defer src="{{ static_v(request, 'static', path='shared/js/log-config.js') }}"></script>
|
||||
|
||||
<!-- 2. Icons -->
|
||||
<script defer src="{{ url_for('static', path='shared/js/icons.js') }}"></script>
|
||||
<script defer src="{{ static_v(request, 'static', path='shared/js/icons.js') }}"></script>
|
||||
|
||||
<!-- 3. Utils -->
|
||||
<script defer src="{{ url_for('static', path='shared/js/utils.js') }}"></script>
|
||||
<script defer src="{{ static_v(request, 'static', path='shared/js/utils.js') }}"></script>
|
||||
|
||||
<!-- 4. API Client -->
|
||||
<script defer src="{{ url_for('static', path='shared/js/api-client.js') }}"></script>
|
||||
<script defer src="{{ static_v(request, 'static', path='shared/js/api-client.js') }}"></script>
|
||||
|
||||
<!-- 5. Alpine.js v3 with CDN fallback -->
|
||||
<script>
|
||||
|
||||
@@ -11,13 +11,13 @@
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet" />
|
||||
|
||||
<!-- Tailwind CSS v4 (built locally via standalone CLI) -->
|
||||
<link rel="stylesheet" href="{{ url_for('static', path='admin/css/tailwind.output.css') }}" />
|
||||
<link rel="stylesheet" href="{{ static_v(request, 'static', path='admin/css/tailwind.output.css') }}" />
|
||||
|
||||
<!-- Flag Icons CSS (for language selector) with local fallback -->
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/npm/flag-icons@7.2.3/css/flag-icons.min.css"
|
||||
onerror="this.onerror=null; this.href='{{ url_for('static', path='shared/css/store/flag-icons.min.css') }}';"
|
||||
onerror="this.onerror=null; this.href='{{ static_v(request, 'static', path='shared/css/store/flag-icons.min.css') }}';"
|
||||
/>
|
||||
|
||||
<!-- Alpine Cloak -->
|
||||
@@ -29,7 +29,7 @@
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/npm/tom-select@2.4.1/dist/css/tom-select.default.min.css"
|
||||
onerror="this.onerror=null; this.href='{{ url_for('static', path='shared/css/store/tom-select.default.min.css') }}';"
|
||||
onerror="this.onerror=null; this.href='{{ static_v(request, 'static', path='shared/css/store/tom-select.default.min.css') }}';"
|
||||
/>
|
||||
<!-- Tom Select Dark Mode Overrides -->
|
||||
<style>
|
||||
@@ -76,7 +76,7 @@
|
||||
{% block quill_css %}{% endblock %}
|
||||
|
||||
<!-- Dev debug toolbar (dev only — auto-hides in production, must load early for interceptors) -->
|
||||
<script src="{{ url_for('static', path='shared/js/dev-toolbar.js') }}"></script>
|
||||
<script src="{{ static_v(request, 'static', path='shared/js/dev-toolbar.js') }}"></script>
|
||||
|
||||
{% block extra_head %}{% endblock %}
|
||||
</head>
|
||||
@@ -104,19 +104,19 @@
|
||||
<script>window.FRONTEND_TYPE = '{{ frontend_type | default("admin") }}';</script>
|
||||
|
||||
<!-- 1. FIRST: Log Configuration -->
|
||||
<script defer src="{{ url_for('static', path='shared/js/log-config.js') }}"></script>
|
||||
<script defer src="{{ static_v(request, 'static', path='shared/js/log-config.js') }}"></script>
|
||||
|
||||
<!-- 2. SECOND: Icons (before Alpine.js) -->
|
||||
<script defer src="{{ url_for('static', path='shared/js/icons.js') }}"></script>
|
||||
<script defer src="{{ static_v(request, 'static', path='shared/js/icons.js') }}"></script>
|
||||
|
||||
<!-- 3. THIRD: Alpine.js Base Data -->
|
||||
<script src="{{ static_v(request, 'core_static', path='admin/js/init-alpine.js') }}"></script>
|
||||
|
||||
<!-- 4. FOURTH: Utils (standalone utilities) -->
|
||||
<script defer src="{{ url_for('static', path='shared/js/utils.js') }}"></script>
|
||||
<script defer src="{{ static_v(request, 'static', path='shared/js/utils.js') }}"></script>
|
||||
|
||||
<!-- 4b. i18n Support -->
|
||||
<script defer src="{{ url_for('static', path='shared/js/i18n.js') }}"></script>
|
||||
<script defer src="{{ static_v(request, 'static', path='shared/js/i18n.js') }}"></script>
|
||||
<script>
|
||||
// Initialize i18n with current language and preload modules
|
||||
// Wrapped in DOMContentLoaded so deferred i18n.js has loaded
|
||||
@@ -127,7 +127,7 @@
|
||||
</script>
|
||||
|
||||
<!-- 5. FIFTH: API Client (depends on Utils) -->
|
||||
<script defer src="{{ url_for('static', path='shared/js/api-client.js') }}"></script>
|
||||
<script defer src="{{ static_v(request, 'static', path='shared/js/api-client.js') }}"></script>
|
||||
|
||||
<!-- 6. SIXTH: Tom Select with CDN fallback -->
|
||||
<script>
|
||||
@@ -167,6 +167,6 @@
|
||||
|
||||
<!-- 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>
|
||||
onerror="var s=document.createElement('script');s.defer=true;s.src='{{ static_v(request, 'static', path='shared/js/lib/alpine.min.js') }}';document.head.appendChild(s);"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -11,13 +11,13 @@
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet" />
|
||||
|
||||
<!-- Tailwind CSS v4 (built locally via standalone CLI) -->
|
||||
<link rel="stylesheet" href="{{ url_for('static', path='merchant/css/tailwind.output.css') }}" />
|
||||
<link rel="stylesheet" href="{{ static_v(request, 'static', path='merchant/css/tailwind.output.css') }}" />
|
||||
|
||||
<!-- Flag Icons CSS (for language selector) with local fallback -->
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/npm/flag-icons@7.2.3/css/flag-icons.min.css"
|
||||
onerror="this.onerror=null; this.href='{{ url_for('static', path='shared/css/store/flag-icons.min.css') }}';"
|
||||
onerror="this.onerror=null; this.href='{{ static_v(request, 'static', path='shared/css/store/flag-icons.min.css') }}';"
|
||||
/>
|
||||
|
||||
<!-- Alpine Cloak -->
|
||||
@@ -26,7 +26,7 @@
|
||||
</style>
|
||||
|
||||
<!-- Dev debug toolbar (dev only — auto-hides in production, must load early for interceptors) -->
|
||||
<script src="{{ url_for('static', path='shared/js/dev-toolbar.js') }}"></script>
|
||||
<script src="{{ static_v(request, 'static', path='shared/js/dev-toolbar.js') }}"></script>
|
||||
|
||||
{% block extra_head %}{% endblock %}
|
||||
</head>
|
||||
@@ -54,19 +54,19 @@
|
||||
<script>window.FRONTEND_TYPE = '{{ frontend_type | default("merchant") }}';</script>
|
||||
|
||||
<!-- 1. FIRST: Log Configuration -->
|
||||
<script defer src="{{ url_for('static', path='shared/js/log-config.js') }}"></script>
|
||||
<script defer src="{{ static_v(request, 'static', path='shared/js/log-config.js') }}"></script>
|
||||
|
||||
<!-- 2. SECOND: Icons (before Alpine.js) -->
|
||||
<script defer src="{{ url_for('static', path='shared/js/icons.js') }}"></script>
|
||||
<script defer src="{{ static_v(request, 'static', path='shared/js/icons.js') }}"></script>
|
||||
|
||||
<!-- 3. THIRD: Alpine.js Base Data -->
|
||||
<script src="{{ static_v(request, 'core_static', path='merchant/js/init-alpine.js') }}"></script>
|
||||
|
||||
<!-- 4. FOURTH: Utils (standalone utilities) -->
|
||||
<script defer src="{{ url_for('static', path='shared/js/utils.js') }}"></script>
|
||||
<script defer src="{{ static_v(request, 'static', path='shared/js/utils.js') }}"></script>
|
||||
|
||||
<!-- 4b. i18n Support -->
|
||||
<script defer src="{{ url_for('static', path='shared/js/i18n.js') }}"></script>
|
||||
<script defer src="{{ static_v(request, 'static', path='shared/js/i18n.js') }}"></script>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', async function() {
|
||||
const modules = {% block i18n_modules %}[]{% endblock %};
|
||||
@@ -75,13 +75,13 @@
|
||||
</script>
|
||||
|
||||
<!-- 5. FIFTH: API Client (depends on Utils) -->
|
||||
<script defer src="{{ url_for('static', path='shared/js/api-client.js') }}"></script>
|
||||
<script defer src="{{ static_v(request, 'static', path='shared/js/api-client.js') }}"></script>
|
||||
|
||||
<!-- 6. Page-specific scripts (MUST load before Alpine.js) -->
|
||||
{% 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>
|
||||
onerror="var s=document.createElement('script');s.defer=true;s.src='{{ static_v(request, 'static', path='shared/js/lib/alpine.min.js') }}';document.head.appendChild(s);"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet" />
|
||||
|
||||
{# Tailwind CSS v4 (built locally via standalone CLI) #}
|
||||
<link rel="stylesheet" href="{{ url_for('static', path='platform/css/tailwind.output.css') }}">
|
||||
<link rel="stylesheet" href="{{ static_v(request, 'static', path='platform/css/tailwind.output.css') }}">
|
||||
|
||||
{# Flag icons for language selector #}
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/lipis/flag-icons@7.0.0/css/flag-icons.min.css"/>
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/npm/flatpickr@4.6.13/dist/flatpickr.min.css"
|
||||
onerror="this.onerror=null; this.href='{{ url_for('static', path='shared/css/store/flatpickr.min.css') }}';"
|
||||
onerror="this.onerror=null; this.href='{{ static_v(request, 'static', path='shared/css/store/flatpickr.min.css') }}';"
|
||||
/>
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
@@ -12,13 +12,13 @@
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet" />
|
||||
|
||||
<!-- Tailwind CSS v4 (built locally via standalone CLI) -->
|
||||
<link rel="stylesheet" href="{{ url_for('static', path='store/css/tailwind.output.css') }}" />
|
||||
<link rel="stylesheet" href="{{ static_v(request, 'static', path='store/css/tailwind.output.css') }}" />
|
||||
|
||||
<!-- Flag Icons for Language Selector with local fallback -->
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/npm/flag-icons@7.2.3/css/flag-icons.min.css"
|
||||
onerror="this.onerror=null; this.href='{{ url_for('static', path='shared/css/store/flag-icons.min.css') }}';"
|
||||
onerror="this.onerror=null; this.href='{{ static_v(request, 'static', path='shared/css/store/flag-icons.min.css') }}';"
|
||||
/>
|
||||
|
||||
<!-- Alpine Cloak -->
|
||||
@@ -27,7 +27,7 @@
|
||||
</style>
|
||||
|
||||
<!-- Dev debug toolbar (dev only — auto-hides in production, must load early for interceptors) -->
|
||||
<script src="{{ url_for('static', path='shared/js/dev-toolbar.js') }}"></script>
|
||||
<script src="{{ static_v(request, 'static', path='shared/js/dev-toolbar.js') }}"></script>
|
||||
|
||||
{% block extra_head %}{% endblock %}
|
||||
</head>
|
||||
@@ -58,7 +58,7 @@
|
||||
<script>window.FRONTEND_TYPE = '{{ frontend_type | default("store") }}';</script>
|
||||
|
||||
<!-- 1. FIRST: Log Configuration -->
|
||||
<script defer src="{{ url_for('static', path='shared/js/log-config.js') }}"></script>
|
||||
<script defer src="{{ static_v(request, 'static', path='shared/js/log-config.js') }}"></script>
|
||||
|
||||
<!-- 1.5: Store Configuration (resolved via PlatformSettingsService) -->
|
||||
<script>
|
||||
@@ -72,16 +72,16 @@
|
||||
</script>
|
||||
|
||||
<!-- 2. SECOND: Icons (before Alpine.js) -->
|
||||
<script defer src="{{ url_for('static', path='shared/js/icons.js') }}"></script>
|
||||
<script defer src="{{ static_v(request, 'static', path='shared/js/icons.js') }}"></script>
|
||||
|
||||
<!-- 3. THIRD: Alpine.js Base Data -->
|
||||
<script src="{{ static_v(request, 'core_static', path='store/js/init-alpine.js') }}"></script>
|
||||
|
||||
<!-- 4. FOURTH: Utils (standalone utilities) -->
|
||||
<script defer src="{{ url_for('static', path='shared/js/utils.js') }}"></script>
|
||||
<script defer src="{{ static_v(request, 'static', path='shared/js/utils.js') }}"></script>
|
||||
|
||||
<!-- 4b. i18n Support -->
|
||||
<script defer src="{{ url_for('static', path='shared/js/i18n.js') }}"></script>
|
||||
<script defer src="{{ static_v(request, 'static', path='shared/js/i18n.js') }}"></script>
|
||||
<script>
|
||||
// Initialize i18n with dashboard language and preload modules
|
||||
// Wrapped in DOMContentLoaded so deferred i18n.js has loaded
|
||||
@@ -92,7 +92,7 @@
|
||||
</script>
|
||||
|
||||
<!-- 5. FIFTH: API Client (depends on Utils) -->
|
||||
<script defer src="{{ url_for('static', path='shared/js/api-client.js') }}"></script>
|
||||
<script defer src="{{ static_v(request, 'static', path='shared/js/api-client.js') }}"></script>
|
||||
|
||||
<!-- 6. SIXTH: Feature Store (depends on API Client, registers with Alpine) -->
|
||||
<script defer src="{{ static_v(request, 'billing_static', path='shared/js/feature-store.js') }}"></script>
|
||||
@@ -105,6 +105,6 @@
|
||||
|
||||
<!-- 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>
|
||||
onerror="var s=document.createElement('script');s.defer=true;s.src='{{ static_v(request, 'static', path='shared/js/lib/alpine.min.js') }}';document.head.appendChild(s);"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -37,20 +37,20 @@
|
||||
</style>
|
||||
|
||||
{# Tailwind CSS v4 (built locally via standalone CLI) #}
|
||||
<link rel="stylesheet" href="{{ url_for('static', path='storefront/css/tailwind.output.css') }}">
|
||||
<link rel="stylesheet" href="{{ static_v(request, 'static', path='storefront/css/tailwind.output.css') }}">
|
||||
|
||||
{# Flag Icons for Language Selector with local fallback #}
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/npm/flag-icons@7.2.3/css/flag-icons.min.css"
|
||||
onerror="this.onerror=null; this.href='{{ url_for('static', path='shared/css/store/flag-icons.min.css') }}';"
|
||||
onerror="this.onerror=null; this.href='{{ static_v(request, 'static', path='shared/css/store/flag-icons.min.css') }}';"
|
||||
/>
|
||||
|
||||
{# Base Shop Styles #}
|
||||
<link rel="stylesheet" href="{{ url_for('static', path='storefront/css/storefront.css') }}">
|
||||
<link rel="stylesheet" href="{{ static_v(request, 'static', path='storefront/css/storefront.css') }}">
|
||||
|
||||
{# Dev debug toolbar (dev only — auto-hides in production, must load early for interceptors) #}
|
||||
<script src="{{ url_for('static', path='shared/js/dev-toolbar.js') }}"></script>
|
||||
<script src="{{ static_v(request, 'static', path='shared/js/dev-toolbar.js') }}"></script>
|
||||
|
||||
{% block extra_head %}{% endblock %}
|
||||
</head>
|
||||
@@ -366,7 +366,7 @@
|
||||
<script>window.FRONTEND_TYPE = '{{ frontend_type | default("storefront") }}';</script>
|
||||
|
||||
{# 1. Log Configuration (must load first) #}
|
||||
<script defer src="{{ url_for('static', path='shared/js/log-config.js') }}"></script>
|
||||
<script defer src="{{ static_v(request, 'static', path='shared/js/log-config.js') }}"></script>
|
||||
|
||||
{# 2. Global Shop Configuration (resolved via PlatformSettingsService) #}
|
||||
<script>
|
||||
@@ -378,16 +378,16 @@
|
||||
</script>
|
||||
|
||||
{# 3. Icon System #}
|
||||
<script defer src="{{ url_for('static', path='shared/js/icons.js') }}"></script>
|
||||
<script defer src="{{ static_v(request, 'static', path='shared/js/icons.js') }}"></script>
|
||||
|
||||
{# 4. Base Shop Layout (Alpine.js component - must load before Alpine) #}
|
||||
<script defer src="{{ static_v(request, 'core_static', path='storefront/js/storefront-layout.js') }}"></script>
|
||||
|
||||
{# 5. Utilities #}
|
||||
<script defer src="{{ url_for('static', path='shared/js/utils.js') }}"></script>
|
||||
<script defer src="{{ static_v(request, 'static', path='shared/js/utils.js') }}"></script>
|
||||
|
||||
{# 5b. i18n Support #}
|
||||
<script defer src="{{ url_for('static', path='shared/js/i18n.js') }}"></script>
|
||||
<script defer src="{{ static_v(request, 'static', path='shared/js/i18n.js') }}"></script>
|
||||
<script>
|
||||
// Initialize i18n with storefront language and preload modules
|
||||
// Wrapped in DOMContentLoaded so deferred i18n.js has loaded
|
||||
@@ -398,14 +398,14 @@
|
||||
</script>
|
||||
|
||||
{# 6. API Client #}
|
||||
<script defer src="{{ url_for('static', path='shared/js/api-client.js') }}"></script>
|
||||
<script defer src="{{ static_v(request, 'static', path='shared/js/api-client.js') }}"></script>
|
||||
|
||||
{# 7. Page-specific JavaScript (MUST load before Alpine.js) #}
|
||||
{% 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>
|
||||
onerror="var s=document.createElement('script');s.defer=true;s.src='{{ static_v(request, 'static', path='shared/js/lib/alpine.min.js') }}';document.head.appendChild(s);"></script>
|
||||
|
||||
{# Toast notification container #}
|
||||
<div id="toast-container" class="fixed bottom-4 right-4 z-50"></div>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<title>{% block title %}{{ status_code }} - {{ status_name }}{% endblock %}{% if store %} | {{ store.name }}{% endif %}</title>
|
||||
|
||||
{# Tailwind CSS #}
|
||||
<link rel="stylesheet" href="{{ url_for('static', path='storefront/css/tailwind.output.css') }}">
|
||||
<link rel="stylesheet" href="{{ static_v(request, 'static', path='storefront/css/tailwind.output.css') }}">
|
||||
|
||||
{# Store theme colors via CSS variables #}
|
||||
<style>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<title>{{ title }}{% if store %} | {{ store.name }}{% endif %}</title>
|
||||
|
||||
{# Tailwind CSS #}
|
||||
<link rel="stylesheet" href="{{ url_for('static', path='storefront/css/tailwind.output.css') }}">
|
||||
<link rel="stylesheet" href="{{ static_v(request, 'static', path='storefront/css/tailwind.output.css') }}">
|
||||
|
||||
{# Theme colors (use store theme if available, fallback to purple gradient) #}
|
||||
<style>
|
||||
|
||||
Reference in New Issue
Block a user