Skip to content

feat(components): make CodeView language grammars tree-shakeable #227

Description

@pasevin

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 language values 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 + plaintext does 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

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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions