feat(shared): add DevBuildBadge component and getBuildDefines() helper

- shared-vite-config: getBuildDefines() injects __BUILD_HASH__ and
  __BUILD_TIME__ as compile-time constants via Vite define
- shared-ui: DevBuildBadge component shows git hash + build timestamp
  in a small fixed badge at bottom-right (click to expand)
- Integrated into mukke-web for deployment verification

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Till JS 2026-03-20 19:34:21 +01:00
parent 511b51e372
commit 822e75368a
6 changed files with 105 additions and 2 deletions

2
apps/mukke/apps/web/src/app.d.ts vendored Normal file
View file

@ -0,0 +1,2 @@
declare const __BUILD_HASH__: string;
declare const __BUILD_TIME__: string;

View file

@ -2,7 +2,7 @@
import { goto } from '$app/navigation'; import { goto } from '$app/navigation';
import { page } from '$app/stores'; import { page } from '$app/stores';
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { PillNavigation } from '@manacore/shared-ui'; import { PillNavigation, DevBuildBadge } from '@manacore/shared-ui';
import type { PillNavItem, PillDropdownItem } from '@manacore/shared-ui'; import type { PillNavItem, PillDropdownItem } from '@manacore/shared-ui';
import { import {
SplitPaneContainer, SplitPaneContainer,
@ -166,6 +166,7 @@
<MiniPlayer /> <MiniPlayer />
<FullPlayer /> <FullPlayer />
<QueuePanel /> <QueuePanel />
<DevBuildBadge commitHash={__BUILD_HASH__} buildTime={__BUILD_TIME__} />
</div> </div>
</SplitPaneContainer> </SplitPaneContainer>
{/if} {/if}

View file

@ -3,7 +3,7 @@ import { defineConfig } from 'vite';
import tailwindcss from '@tailwindcss/vite'; import tailwindcss from '@tailwindcss/vite';
import { SvelteKitPWA } from '@vite-pwa/sveltekit'; import { SvelteKitPWA } from '@vite-pwa/sveltekit';
import { createPWAConfig } from '@manacore/shared-pwa'; import { createPWAConfig } from '@manacore/shared-pwa';
import { MANACORE_SHARED_PACKAGES } from '@manacore/shared-vite-config'; import { MANACORE_SHARED_PACKAGES, getBuildDefines } from '@manacore/shared-vite-config';
export default defineConfig({ export default defineConfig({
plugins: [ plugins: [
@ -28,4 +28,7 @@ export default defineConfig({
optimizeDeps: { optimizeDeps: {
exclude: [...MANACORE_SHARED_PACKAGES, '@mukke/shared'], exclude: [...MANACORE_SHARED_PACKAGES, '@mukke/shared'],
}, },
define: {
...getBuildDefines(),
},
}); });

View file

@ -0,0 +1,77 @@
<script lang="ts">
interface Props {
commitHash?: string;
buildTime?: string;
}
let { commitHash = 'unknown', buildTime = '' }: Props = $props();
let formattedTime = $derived.by(() => {
if (!buildTime) return '';
try {
const d = new Date(buildTime);
return d.toLocaleString('de-DE', {
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
});
} catch {
return buildTime;
}
});
let expanded = $state(false);
</script>
<button
class="dev-badge"
class:expanded
onclick={() => (expanded = !expanded)}
title="Build: {commitHash} | {buildTime}"
>
{#if expanded}
<span class="dev-badge-detail">{commitHash} &middot; {formattedTime}</span>
{:else}
<span class="dev-badge-hash">{commitHash}</span>
{/if}
</button>
<style>
.dev-badge {
position: fixed;
bottom: 8px;
right: 8px;
z-index: 9999;
font-family: ui-monospace, monospace;
font-size: 10px;
line-height: 1;
padding: 3px 6px;
border-radius: 4px;
border: none;
background: rgba(0, 0, 0, 0.4);
color: rgba(255, 255, 255, 0.7);
cursor: pointer;
pointer-events: auto;
opacity: 0.5;
transition: opacity 150ms ease;
backdrop-filter: blur(4px);
-webkit-backdrop-filter: blur(4px);
}
.dev-badge:hover {
opacity: 1;
}
.dev-badge.expanded {
opacity: 0.85;
}
.dev-badge-hash {
letter-spacing: 0.5px;
}
.dev-badge-detail {
white-space: nowrap;
}
</style>

View file

@ -200,6 +200,7 @@ export type {
// Immersive Mode // Immersive Mode
export { default as ImmersiveModeToggle } from './components/ImmersiveModeToggle.svelte'; export { default as ImmersiveModeToggle } from './components/ImmersiveModeToggle.svelte';
export { default as DevBuildBadge } from './components/DevBuildBadge.svelte';
// Toast & Global Error Handling // Toast & Global Error Handling
export { export {

View file

@ -3,6 +3,7 @@
* Provides consistent SSR and optimization settings. * Provides consistent SSR and optimization settings.
*/ */
import { execSync } from 'child_process';
import type { UserConfig, UserConfigExport } from 'vite'; import type { UserConfig, UserConfigExport } from 'vite';
/** /**
@ -34,6 +35,24 @@ export const MANACORE_SHARED_PACKAGES = [
'@manacore/shared-help-ui', '@manacore/shared-help-ui',
] as const; ] as const;
/**
* Get build-time defines for version tracking.
* Injects __BUILD_HASH__ and __BUILD_TIME__ as compile-time constants.
*/
export function getBuildDefines(): Record<string, string> {
let commitHash = 'dev';
try {
commitHash = execSync('git rev-parse --short HEAD').toString().trim();
} catch {
// fallback if not in a git repo
}
const buildTime = new Date().toISOString();
return {
__BUILD_HASH__: JSON.stringify(commitHash),
__BUILD_TIME__: JSON.stringify(buildTime),
};
}
export interface ViteConfigOptions { export interface ViteConfigOptions {
/** Server port */ /** Server port */
port: number; port: number;