Skip to content

Keep the router out of the embeddable diagram (#356) - #432

Merged
adamjohnwright merged 4 commits into
mainfrom
perf/356-embed-without-router
Oct 13, 2026
Merged

adamjohnwright merged 4 commits into
mainfrom
perf/356-embed-without-router

Conversation

@adamjohnwright

Copy link
Copy Markdown
Contributor

Part of #356: the embed should cost under a third of what the site's Pathway Browser costs for the same diagram.

Cause. The embed never routes, but it carried @angular/router (67 KB).

  • Everything that draws a pathway injects UrlStateService, and that class, the injection token itself, imported the Router to keep state in the address bar.
  • The embed's MemoryState also imported from that file.
  • diagram.component and species.service injected Router/ActivatedRoute optionally, which still imports them.

Change

  • UrlStateService is now an abstract, router-free base. It holds the state signals (built by createStateValues, as before), the tab maps and the dbId lookup. section, settle, navigateTo and two new members are abstract. It imports only router types.
  • RouterUrlStateService (router-url-state.service.ts) is the address-bar implementation. It's moved unchanged, except that the shared parts now come from the base. The site provides it in src/app/app.config.ts, replacing providedIn: 'root'.
  • MemoryState extends the base, so its copy of every field is gone.
  • The last direct router reads are now state.isFirstNavigation() (the diagram's first-load check) and state.queryParams() (the species switch). The embed answers true and {}, which is what it got before, with no router injected.
  • lodash isArray/isNumber in the state service are now Array.isArray and typeof.
  • The detail page's DetailUrlState (a Partial of the state) is unaffected. Nothing on that page calls the two new members: its diagram is an image component, not cr-diagram.

Size. The embed's initial JavaScript goes from 1.58 MB to 1.50 MB (all its JavaScript: 1,650 KB to 1,570 KB). @angular/router is at 0 bytes in the stats.

Checks

  • Unit tests: 723 passed. entity.service.spec now provides the state itself, because it's no longer provided at the root automatically.
  • Full e2e suite locally: 401 passed, 6 skipped.
  • Preflight passes. Lint and dead code are unchanged.

Next for #356

🤖 Generated with Claude Code

adamjohnwright and others added 4 commits October 13, 2026 04:50
The embed never routes, but carried @angular/router (67 KB): everything that
draws a pathway injects UrlStateService, and that class -- the token itself --
imported the Router to keep the state in the address bar. MemoryState, the
embed's in-memory state, also imported from that file.

- UrlStateService is now an abstract, router-free base: the state signals
  (built by createStateValues, as before), the tab maps and the dbId lookup,
  with section, settle, navigateTo and two new members abstract. It imports
  only router *types*.
- RouterUrlStateService (router-url-state.service.ts) is the address-bar
  implementation, moved unchanged apart from the base taking the shared
  parts; the site provides it in src/app/app.config.ts.
- MemoryState extends the base, so its copy of every field is gone.
- The diagram's "first page opened" check and the species switch's query
  parameters were the last direct router reads; they are now
  state.isFirstNavigation() and state.queryParams() (the embed answers true
  and {}, which is what it got before with no router injected).
- lodash's isArray/isNumber in the state service are now Array.isArray and
  typeof.

The embed's initial JavaScript goes from 1.58 MB to 1.50 MB (all its
JavaScript: 1,650 KB -> 1,570 KB). The full e2e suite passes (401, 6 skipped).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ate says it is unchecked

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@adamjohnwright

Copy link
Copy Markdown
Contributor Author

Review (subagent, adversarial): no defects. The moved class is line-for-line the old one (bar Array.isArray, a type rename and Boolean(!x) -> !x); field order under useDefineForClassFields: false is safe (route before section, no base initialiser touches subclass fields); every injector resolves (site via app.config, embed via MemoryState/rootGuards, detail page its own provider, specs updated); isFirstNavigation/queryParams read the same root Router/ActivatedRoute as before; the embed stats show no @angular/router. Nits fixed in the latest commits: queryParams() returns a copy rather than the router's object, a stale comment above the removed Router injection is gone, and DetailUrlState now says plainly that it is a Partial, so nothing checks it has settle/navigateTo/isFirstNavigation/queryParams -- nothing on the content pages calls them.

@adamjohnwright
adamjohnwright merged commit 1559197 into main Oct 13, 2026
6 checks passed
@adamjohnwright
adamjohnwright deleted the perf/356-embed-without-router branch October 13, 2026 05:58
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