build(editor): blog editor JS build and drift gate

- Private ESM package with exact pins: @tiptap/core, pm, starter-kit,
  extension-table and extension-image 3.31.4; vite 7.3.5, vitest 3.2.7,
  happy-dom 20.11.6 and typescript 5.9.3, the admin SPA toolchain
- vite.config.ts builds assets/src/blogeditor/index.ts into fixed-name
  assets/dist/blogeditor.js and blogeditor.css, minified, and runs vitest
  on happy-dom
- scripts/check-dist.sh rebuilds into a temp dir and fails when assets/dist
  is stale; node_modules is ignored
This commit is contained in:
2026-10-10 11:35:44 +02:00
parent c60abc6d62
commit 234e6169cc
6 changed files with 2445 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
node_modules/

2340
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

26
package.json Normal file
View File

@@ -0,0 +1,26 @@
{
"name": "golem15-journal-blogeditor",
"private": true,
"type": "module",
"engines": {
"node": ">=22.6"
},
"scripts": {
"typecheck": "tsc --noEmit",
"build": "tsc --noEmit && vite build",
"test": "vitest run"
},
"dependencies": {
"@tiptap/core": "3.31.4",
"@tiptap/extension-image": "3.31.4",
"@tiptap/extension-table": "3.31.4",
"@tiptap/pm": "3.31.4",
"@tiptap/starter-kit": "3.31.4"
},
"devDependencies": {
"happy-dom": "20.11.6",
"typescript": "5.9.3",
"vite": "7.3.5",
"vitest": "3.2.7"
}
}

26
scripts/check-dist.sh Executable file
View File

@@ -0,0 +1,26 @@
#!/usr/bin/env bash
# Drift gate for the committed Blog Editor bundle (D-16). Rebuilds the element
# from the committed lockfile into a temporary directory and fails when the
# result differs from assets/dist, the files admin.go embeds. After changing
# assets/src, rebuild with `npm run build` and commit assets/dist.
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$ROOT"
if [[ ! -d node_modules ]]; then
npm ci
fi
npm run typecheck
TMP="$(mktemp -d)"
trap 'rm -rf "$TMP"' EXIT
node_modules/.bin/vite build --outDir "$TMP/dist" --emptyOutDir --logLevel warn
if ! diff -r "$TMP/dist" assets/dist; then
echo "check-dist: assets/dist is stale; run npm run build and commit assets/dist" >&2
exit 1
fi
echo "check-dist: assets/dist matches a fresh build"

17
tsconfig.json Normal file
View File

@@ -0,0 +1,17 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"lib": ["ES2022", "DOM", "DOM.Iterable"],
"strict": true,
"noEmit": true,
"isolatedModules": true,
"skipLibCheck": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"types": ["vite/client", "node"]
},
"include": ["assets/src", "tests", "vite.config.ts"]
}

35
vite.config.ts Normal file
View File

@@ -0,0 +1,35 @@
import { defineConfig } from 'vitest/config'
// Build of the Blog Editor custom element (D-16): one ES module entry,
// assets/src/blogeditor/index.ts, loaded by the admin SPA as a module script.
// It is built like a library entry (exports kept, fixed output names with no
// content hash; cabana appends ?v=<sha256 prefix> itself) but through the
// application pipeline, because Vite's library mode never minifies
// whitespace in ES output. The bundle and its stylesheet are committed under
// assets/dist and embedded through admin.go; scripts/check-dist.sh fails
// when they are stale.
export default defineConfig({
build: {
outDir: 'assets/dist',
emptyOutDir: true,
target: 'es2022',
modulePreload: false,
copyPublicDir: false,
reportCompressedSize: true,
rollupOptions: {
input: 'assets/src/blogeditor/index.ts',
preserveEntrySignatures: 'exports-only',
output: {
format: 'es',
entryFileNames: 'blogeditor.js',
chunkFileNames: 'blogeditor-[name].js',
assetFileNames: 'blogeditor[extname]',
inlineDynamicImports: true,
},
},
},
test: {
environment: 'happy-dom',
include: ['tests/**/*.test.ts'],
},
})