OpenZeppelin / OpenZeppelin/openzeppelin-ui
feat(components): make CodeView language grammars tree-shakeable
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 7
- Forks
- 3
- Avg merge
- 20h 20m
- Merged PRs (30d)
- 26
Description
Summary
Today, importing @openzeppelin/ui-components/code-view statically registers all highlight.js grammars in one module. Bundlers cannot drop unused languages based on the runtime language prop. Make grammar loading tree-shakeable (or otherwise optional per language) so apps that only need a subset do not pay for every grammar.
Related: add TypeScript / JavaScript / Solidity — #226. Context from CodeView in #225.
Current behaviour
// highlight.ts — all grammars are static imports
const lowlight = createLowlight({ bash, ini, json, markdown, rust });
- App never imports
./code-view: highlighter is correctly excluded (subpath boundary). - App imports CodeView once: every registered grammar ships, regardless of which
languagevalues are used.
Documented contract: tokenization is synchronous in render, memoized on [source, language].
Why this is non-trivial
Per-language tree-shaking needs either lazy import() (async first paint) or opt-in side-effect imports (awkward DX). Both are deliberate API/invariant changes, not a half-day cleanup.
Options to evaluate (Design)
| Approach | Tree-shake? | Trade-off |
|---|---|---|
Lazy grammar import() + cache; plaintext/skeleton until ready |
Yes | Breaks pure sync first highlight; needs loading path + invariant/docs rewrite |
Opt-in side-effect entrypoints (e.g. code-view/languages/rust) |
Yes | Hosts must import every language they use; easy to miss |
| Consumer-registered grammars | Yes | Larger API; fights closed private registry |
Preference to explore first: lazy load + one-frame plaintext (or last-good) fallback — cleanest product shape if we accept a contract change.
Acceptance criteria
- Design note chooses an approach and updates CodeView invariants/docs for sync vs async highlighting.
- An app that only ever highlights e.g.
rust+plaintextdoes not include unused grammar modules in a production bundle (proven with a packed-consumer or rollup/vite size check). - Fail-soft behaviour preserved (tokenizer errors → plaintext).
- No requirement for consumers to supply themes/colors.
- Changeset + docs for the new loading / import model.
Out of scope
- Adding new languages (#226) — but the design should scale to TS/JS/Solidity without a second rewrite.
- Replacing lowlight/highlight.js wholesale.
Motivation
As we add TypeScript, JavaScript, and especially Solidity (#226), the shared ./code-view chunk grows for every consumer. Tree-shaking keeps that expansion from punishing apps that only need a subset.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the highlight.ts static grammar imports and the CodeView context in #225, then compare the listed lazy-loading, opt-in entrypoint, and consumer-registration approaches. Validate the chosen design with a packed consumer or Rollup/Vite size check, and update the sync/async invariants, fail-soft behavior, changeset, and loading documentation.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- frontend, performance
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 32/100