Skip to content

fix: resolve dev hydration failure, add CI - #2

Merged
benjamincanac merged 5 commits into
mainfrom
fix/dev-hydration-and-ci
Jul 28, 2026
Merged

fix: resolve dev hydration failure, add CI#2
benjamincanac merged 5 commits into
mainfrom
fix/dev-hydration-and-ci

Conversation

@benjamincanac

@benjamincanac benjamincanac commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

elkjs / dev hydration

elkjs/lib/elk.bundled.js is UMD. In dev the browser was being served it raw,
so the ES import found no default export and hydration died with a 500 page
on every route. SSR output was always correct, which made it look intermittent.

The chain is @comark/vue's Mermaid component -> beautiful-mermaid -> elkjs. The
culprit was the beautiful-mermaid > elkjs/lib/elk.bundled.js entry in
optimizeDeps.include: it resolved to the same file beautiful-mermaid imports,
which made the optimizer split elkjs out of beautiful-mermaid's chunk into a
second entry the browser then had to resolve itself — and got the raw UMD.

The fix is to declare only beautiful-mermaid and let the optimizer inline
elkjs into its chunk, so the raw UMD is never served. Verified against the dev
dep cache: beautiful-mermaid.js contains elkjs inline and imports nothing;
there is no separate elkjs chunk.

Checked on a cold dep cache in headless Chromium — all four playground routes
hydrate, the mermaid diagram renders, and console errors, uncaught exceptions
and failed requests are all empty, on both a cold and a warm cache.

CI

Add a workflow mirroring comark-cms: install, prepare, typecheck, build. No lint
or test steps -- this package has neither, so the job is named ci rather than
test. Runs with permissions: contents: read, a concurrency group that cancels
superseded runs, and an explicit --frozen-lockfile. The build covers the
playground, which exercises content pages, the landing route, OG images and the
generated ISR route rules.

Footer

Credits default drops to © ${year} ${owner}. — no "Copyright" prefix, no
"All rights reserved." (legally inert under Berne). README, app.config.ts,
nuxt.schema.ts and AppFooter.vue all updated to agree.

Playground

  • index.md uses navigation: false so Home is no longer a sidebar entry.
  • Dropped the duplicate ## Code blocks section from 1.introduction.md;
    2.installation.md already covers bash/ts code blocks and the mermaid
    diagram, which is what exercises the elkjs path above.
  • Footer gains a GitHub link, and owner is Vercel, Inc.

Dependencies

Routine bumps carried along: nuxt 4.5.1, satori 0.29, @nuxtjs/sitemap 8.3,
@nuxtjs/robots 6.1.3, nuxt-og-image 6.7.4, nuxt-seo-utils 8.3.2, exsolve 1.1,
iconify collections, and the h3 override to ^1.15.11. Satori renders OG images
at request time, so the build compiles them but does not render them — worth an
eyeball on a preview deploy.

elkjs
-----
`elkjs/lib/elk.bundled.js` is UMD. In dev the browser was being served it raw,
so the ES import found no `default` export and hydration died with a 500 page
on every route. SSR output was always correct, which made it look intermittent.

The chain is @comark/vue's Mermaid component -> beautiful-mermaid -> elkjs. The
earlier `beautiful-mermaid > elkjs/lib/elk.bundled.js` entry did produce an
optimized chunk, but the optimizer keys it by that chain string while the
specifier beautiful-mermaid actually imports is the bare
`elkjs/lib/elk.bundled.js` -- so the import was never rewritten to it. Matching
the specifier verbatim requires elkjs to resolve from the layer root, hence the
direct dependency on a package nothing here imports.

Verified end to end: @comark/vue now imports the optimized beautiful-mermaid
chunk, which imports the optimized elkjs chunk (a proper CJS->ESM conversion
with no external imports). Console is clean across a fresh tab, repeated
reloads, cross-page navigation and a dev-server restart against an existing
tab -- the case that previously resurfaced it from a stale module graph.

Footer
------
Drop the `(c)` from the default credits line, restoring the wording the sites
had before the footer was made configurable.

CI
--
Add a workflow mirroring comark-cms: install, prepare, typecheck, build. No
lint or test steps -- this package has neither. The build covers the playground,
which exercises content pages, the landing route, OG images and the generated
ISR route rules.
@benjamincanac benjamincanac changed the title fix: resolve dev hydration failure, drop footer (c), add CI fix: resolve dev hydration failure, add CI Jul 28, 2026
The `elkjs` direct dependency and its `optimizeDeps.include` entry did
nothing. Evidence from the dev dep cache:

  beautiful-mermaid          -> .pnpm/beautiful-mermaid@1.1.3/…/index.js
  elkjs/lib/elk.bundled.js   -> .pnpm/elkjs@0.12.0/…/elk.bundled.js

beautiful-mermaid declares `elkjs: ^0.11.0` and resolves 0.11.1, so the
entry (0.12.0 from the layer root) pointed at a different file than the
one beautiful-mermaid imports. It could not affect that chunk: the
optimized beautiful-mermaid.js inlines elkjs 0.11.1 and imports nothing,
while elkjs_lib_elk__bundled__js.js sat orphaned at 2.5 MB.

So what actually fixed hydration was removing the *old*
`beautiful-mermaid > elkjs/lib/elk.bundled.js` entry, which did resolve
to bm's own copy, collided with it and split elkjs back out where the
browser got raw UMD. The replacement only looked load-bearing because
the version mismatch kept it from colliding — an invariant that would
break the moment beautiful-mermaid widens its elkjs range.

Dropping both leaves `['beautiful-mermaid', 'motion-v']`, saves a
needless 1.5 MB dependency for every consumer of the layer plus 2.5 MB
of cold-start optimizer work, and removes the latent trap. The comment
now says why an elkjs entry must not be re-added.

Verified on a cold dep cache in headless Chromium: all four playground
routes hydrate, the mermaid diagram renders, and console/exceptions/
failed-requests are empty on both cold and warm cache. prepare,
typecheck and build pass.

Also:
- app.config.ts credits comment still said "All rights reserved."
- CI: `permissions: contents: read`, concurrency with cancel-in-progress,
  explicit `--frozen-lockfile`, job renamed `test` -> `ci` (no tests here)
- trailing newlines in pnpm-workspace.yaml and 1.introduction.md
@benjamincanac
benjamincanac merged commit 920a312 into main Jul 28, 2026
1 check passed
@benjamincanac
benjamincanac deleted the fix/dev-hydration-and-ci branch July 28, 2026 12:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant