All checks were successful
CI / lint (push) Successful in 1m37s
Deploy / notebooks (push) Has been skipped
Deploy / zotero (push) Has been skipped
Deploy / docs (push) Has been skipped
Deploy / api (push) Has been skipped
Deploy / mc (push) Has been skipped
Infra CI / notebooks (push) Successful in 6m15s
Infra CI / zotero (push) Successful in 23s
Infra CI / docs (push) Successful in 22s
Infra CI / api (push) Successful in 13s
Infra CI / mc (push) Successful in 13s
Deploy / report (push) Successful in 13s
CI / test (push) Successful in 17m9s
Package Supply Chain / pkg-supply-chain (push) Successful in 59s
The overlay deleted marimo's pnpm-lock.yaml before 'pnpm install --no-frozen-lockfile', so every image build re-resolved the entire dependency graph (devDeps included — rolldown-vite beta among them) to latest-of-the-day. The 0.23.13 rebuild on 2026-07-08 produced a bundle that compiled clean but crashed the editor at runtime on every notebook open: 'TypeError: d is not a constructor' in the @codemirror/merge chunk (new StyleModule(...) receiving a non-constructor after bad bundler interop). The home page still rendered and the container reported healthy, so nothing caught it. Keep the lockfile: --no-frozen-lockfile already re-resolves only what the overlay actually changes (@tabler/icons-react + the two overrides); everything else stays at the versions upstream tested and shipped. Verified: rebuilt image, headless-browser probe of the editor on a throwaway container (0 console errors, cells render), then recreated the production container and re-probed — clean. Frontend smoke gate in CI to prevent recurrence is designed and pending approval.
136 lines
5.8 KiB
Bash
Executable File
136 lines
5.8 KiB
Bash
Executable File
#!/bin/sh
|
|
# Apply fhirworx overlay onto a vanilla marimo source tree.
|
|
# Idempotent: safe to run multiple times during iterative development.
|
|
#
|
|
# Invoked by the Dockerfile after `git clone`, before `pnpm install`.
|
|
# Run from the marimo source root (same dir as frontend/ and pyproject.toml).
|
|
|
|
set -eu
|
|
|
|
SRC="${1:?usage: apply-overlay.sh <marimo-source-root> <overlay-root>}"
|
|
OVR="${2:?}"
|
|
|
|
echo "== fhirworx overlay → $SRC"
|
|
|
|
# 1. Drop new files in place (lucide-shim, fhirworx.css, asset overrides).
|
|
cp -R "$OVR/frontend/." "$SRC/frontend/"
|
|
|
|
# 2. Add @tabler/icons-react to frontend dependencies via jq (idempotent).
|
|
# Pinned to a known-good major that matches our shim's export names.
|
|
jq '.dependencies["@tabler/icons-react"] = "^3.26.0"' \
|
|
"$SRC/frontend/package.json" > "$SRC/frontend/package.json.new"
|
|
mv "$SRC/frontend/package.json.new" "$SRC/frontend/package.json"
|
|
|
|
# 2b. Pin two transitive deps in marimo's pnpm-workspace.yaml `overrides` —
|
|
# the location marimo actually reads (package.json `pnpm.overrides` is
|
|
# ignored once a workspace file defines overrides). We build with
|
|
# `pnpm install --no-frozen-lockfile`, so both otherwise float within
|
|
# their ranges and break the build:
|
|
# jotai `^2.17` floats to 2.20+, which dropped the
|
|
# INTERNAL_getBuildingBlocksRev2 / INTERNAL_buildStoreRev2
|
|
# exports marimo imports → frontend dies with MISSING_EXPORT.
|
|
# tailwind-merge `^2.6.0` floats to 2.6.1 — a legit dcastil backport onto
|
|
# the 2.x line (real git tag) but published WITHOUT npm
|
|
# trusted-publisher provenance, so pnpm 10.28+'s default
|
|
# trust policy rejects it as a downgrade. Pin to 2.6.0, the
|
|
# last provenance-backed 2.x. This keeps pnpm's supply-chain
|
|
# trust check ON for every other dependency — we resolve the
|
|
# flag by using a trusted version, not by disabling it.
|
|
WS="$SRC/pnpm-workspace.yaml"
|
|
if [ -f "$WS" ] && grep -q '^overrides:' "$WS"; then
|
|
awk '/^overrides:/{print; print " jotai: \"2.17.0\""; print " tailwind-merge: \"2.6.0\""; next} {print}' "$WS" > "$WS.new"
|
|
mv "$WS.new" "$WS"
|
|
else
|
|
printf '\noverrides:\n jotai: "2.17.0"\n tailwind-merge: "2.6.0"\n' >> "$WS"
|
|
fi
|
|
|
|
# 3. KEEP upstream's pnpm-lock.yaml. We install with --no-frozen-lockfile,
|
|
# which re-resolves only what the overlay changed (the @tabler dep and
|
|
# the overrides above) and keeps every other transitive dep — including
|
|
# devDeps like rolldown-vite — at the versions upstream tested and
|
|
# shipped. Deleting the lock floated the whole graph to latest-of-the-day
|
|
# and produced a bundle that built fine but crashed the editor at runtime
|
|
# ("d is not a constructor" in @codemirror/merge, 2026-07-09).
|
|
|
|
# 4. Inject our CSS import into globals.css.
|
|
# `@import` must precede all other statements (postcss/CSS spec), so
|
|
# append-at-EOF would get rejected with a warning + dropped. Instead,
|
|
# insert our @import right after the last existing top-level @import.
|
|
if ! grep -q 'fhirworx.css' "$SRC/frontend/src/css/globals.css"; then
|
|
python3 - "$SRC/frontend/src/css/globals.css" <<'PY'
|
|
import sys, re
|
|
p = sys.argv[1]
|
|
s = open(p).read()
|
|
# Find the index right after the last top-level @import line.
|
|
matches = list(re.finditer(r'^@import[^;]*;\s*\n', s, flags=re.M))
|
|
if not matches:
|
|
sys.exit(f"overlay: no existing @import in {p}")
|
|
pos = matches[-1].end()
|
|
insert = '@import "./fhirworx.css";\n'
|
|
open(p, "w").write(s[:pos] + insert + s[pos:])
|
|
PY
|
|
fi
|
|
|
|
# 4b. Strip the "Resources" section from the home page.
|
|
# Touchless landing page: no upstream documentation links, just the
|
|
# user's notebooks + workspace.
|
|
HOME="$SRC/frontend/src/components/pages/home-page.tsx"
|
|
if [ -f "$HOME" ] && grep -q '<ResourceLinks />' "$HOME"; then
|
|
python3 - "$HOME" <<'PY'
|
|
import sys, re
|
|
p = sys.argv[1]
|
|
s = open(p).read()
|
|
# Remove the JSX element render.
|
|
s = re.sub(r'^\s*<ResourceLinks />\s*\n', '', s, flags=re.M)
|
|
# Remove it from the imports so TS doesn't complain about unused symbols.
|
|
s = re.sub(r'(\bResourceLinks,\s*)', '', s)
|
|
# Relabel the logo so it doesn't say "marimo".
|
|
s = s.replace('alt="marimo logo"', 'alt="fhirworx"')
|
|
open(p, 'w').write(s)
|
|
PY
|
|
fi
|
|
|
|
# 5. Inject the lucide-react → shim alias into vite.config.mts.
|
|
# Match the `resolve: {` block and insert an `alias` entry right after.
|
|
if ! grep -q 'lucide-shim' "$SRC/frontend/vite.config.mts"; then
|
|
python3 - "$SRC/frontend/vite.config.mts" <<'PY'
|
|
import sys, re
|
|
path = sys.argv[1]
|
|
s = open(path).read()
|
|
|
|
# Ensure node:path + node:url are imported for the alias resolution.
|
|
if "from \"node:path\"" not in s and "from 'node:path'" not in s:
|
|
s = 'import { dirname, resolve as pathResolve } from "node:path";\n' + \
|
|
'import { fileURLToPath } from "node:url";\n' + s
|
|
|
|
# Inject alias immediately after `resolve: {`. fileURLToPath() keeps the
|
|
# path Windows-safe and anchored to this config file, regardless of where
|
|
# the build is invoked from.
|
|
inject_alias = (
|
|
' alias: {\n'
|
|
' "lucide-react": pathResolve(\n'
|
|
' dirname(fileURLToPath(import.meta.url)),\n'
|
|
' "src/lucide-shim.tsx",\n'
|
|
' ),\n'
|
|
' },\n'
|
|
)
|
|
s2, n = re.subn(r'(resolve:\s*\{\n)', r'\1' + inject_alias, s, count=1)
|
|
if n != 1:
|
|
sys.exit(f"overlay: could not find 'resolve: {{' in {path}")
|
|
|
|
# Raise the build target to esnext. Default is es2020+old-browsers, and
|
|
# vite-plugin-top-level-await's esbuild pass can't downlevel Tabler's
|
|
# bundled destructuring patterns to that set. All currently-supported
|
|
# evergreen browsers handle esnext output fine; no need to constrain.
|
|
inject_target = (
|
|
' target: "esnext",\n'
|
|
)
|
|
s3, n2 = re.subn(r'(build:\s*\{\n)', r'\1' + inject_target, s2, count=1)
|
|
if n2 != 1:
|
|
sys.exit(f"overlay: could not find 'build: {{' in {path}")
|
|
open(path, "w").write(s3)
|
|
PY
|
|
fi
|
|
|
|
echo "== overlay applied"
|