feat(site-builder): stamp git sha + date into the editor bundle
package.json's version is hand-maintained and never changes between builds, so a bug report can't identify which bundle produced it. Vite's `define` injects __EDITOR_BUILD__ (short git SHA + build date) at compile time; editorBuild() in build-stamp.ts is the only safe way to read it, falling back to 'dev' since vitest does not apply Vite's `define` and the identifier is otherwise undeclared. The execSync call falls back to 'nogit' when building outside a git checkout (release tarballs), verified by building from a directory with no git ancestry at all. Also wires editorBuild() into a startup console.log in main.tsx -- without any reference to it, Vite tree-shakes the unused module out of the bundle entirely and __EDITOR_BUILD__ never gets substituted, silently leaving every bug report saying 'dev'. Task 19 will add the real call site when it assembles the report payload. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -3,12 +3,19 @@ import ReactDOM from 'react-dom/client';
|
|||||||
import { App } from './App';
|
import { App } from './App';
|
||||||
import { WhpConfig } from './types';
|
import { WhpConfig } from './types';
|
||||||
import { installConsoleErrorBuffer } from './utils/console-buffer';
|
import { installConsoleErrorBuffer } from './utils/console-buffer';
|
||||||
|
import { editorBuild } from './utils/build-stamp';
|
||||||
import './styles/editor.css';
|
import './styles/editor.css';
|
||||||
|
|
||||||
// Installed before React mounts so errors thrown during the first render are
|
// Installed before React mounts so errors thrown during the first render are
|
||||||
// captured too.
|
// captured too.
|
||||||
installConsoleErrorBuffer();
|
installConsoleErrorBuffer();
|
||||||
|
|
||||||
|
// Logged so the build that produced a given session is visible in the
|
||||||
|
// browser console; also the only current reference to `editorBuild()`,
|
||||||
|
// which keeps the __EDITOR_BUILD__-reading module from being tree-shaken
|
||||||
|
// out of the bundle before Task 19 wires it into the report payload.
|
||||||
|
console.log(`[site-builder] build ${editorBuild()}`);
|
||||||
|
|
||||||
// Read WHP_CONFIG injected by PHP wrapper (or null for standalone dev)
|
// Read WHP_CONFIG injected by PHP wrapper (or null for standalone dev)
|
||||||
const whpConfig: WhpConfig | null = (window as any).WHP_CONFIG || null;
|
const whpConfig: WhpConfig | null = (window as any).WHP_CONFIG || null;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
/**
|
||||||
|
* Reads the compile-time `__EDITOR_BUILD__` define.
|
||||||
|
*
|
||||||
|
* vitest does not apply Vite's `define`, and `npm run dev` in a non-git
|
||||||
|
* checkout may not either, so every read goes through here. `typeof` on an
|
||||||
|
* undeclared identifier is safe in JS -- it does not throw.
|
||||||
|
*/
|
||||||
|
export function editorBuild(): string {
|
||||||
|
return typeof __EDITOR_BUILD__ !== 'undefined' ? __EDITOR_BUILD__ : 'dev';
|
||||||
|
}
|
||||||
Vendored
+5
@@ -0,0 +1,5 @@
|
|||||||
|
/// <reference types="vite/client" />
|
||||||
|
|
||||||
|
/** Injected by vite.config.ts `define`. Absent under vitest -- always read
|
||||||
|
* it through `utils/build-stamp.ts`'s `editorBuild()`, never directly. */
|
||||||
|
declare const __EDITOR_BUILD__: string;
|
||||||
@@ -1,6 +1,20 @@
|
|||||||
import { defineConfig } from 'vite'
|
import { defineConfig } from 'vite'
|
||||||
import react from '@vitejs/plugin-react'
|
import react from '@vitejs/plugin-react'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
|
import { execSync } from 'child_process'
|
||||||
|
|
||||||
|
/** Short git SHA + build date, injected as __EDITOR_BUILD__ so an issue
|
||||||
|
* report identifies exactly which bundle produced it. package.json's
|
||||||
|
* version is hand-maintained and never changes between builds. */
|
||||||
|
const editorBuild = (() => {
|
||||||
|
let sha = 'nogit'
|
||||||
|
try {
|
||||||
|
sha = execSync('git rev-parse --short HEAD', { cwd: __dirname }).toString().trim()
|
||||||
|
} catch {
|
||||||
|
// Building outside a git checkout (release tarball) -- keep 'nogit'.
|
||||||
|
}
|
||||||
|
return `${sha}-${new Date().toISOString().slice(0, 10)}`
|
||||||
|
})()
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [react()],
|
plugins: [react()],
|
||||||
@@ -10,6 +24,9 @@ export default defineConfig({
|
|||||||
'@': path.resolve(__dirname, './src'),
|
'@': path.resolve(__dirname, './src'),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
define: {
|
||||||
|
__EDITOR_BUILD__: JSON.stringify(editorBuild),
|
||||||
|
},
|
||||||
build: {
|
build: {
|
||||||
outDir: 'dist',
|
outDir: 'dist',
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
|
|||||||
Reference in New Issue
Block a user