Skip to content

Constant-tag Dynamic / dynamic() should take the compiled-element path #3387

Description

@ryansolid

Version: 2.0.0-rc.8 (@solidjs/web), packages/web/src/index.ts ~282–381 and index.server.ts ~81–142

dynamic(() => "button") — a string tag that can never change — still allocates a factory memo over source, a per-instance memo, and on the client goes through createElement + a full spread. That's the cost @yak/solid measured its way out of by reimplementing the element path from template/getNextElement/spread/insert (createElementRenderer in next-yak#644), i.e. by hand-writing what the compiler emits for <button {...props}>.

Proposal

When source is a string (or Dynamic's component is a non-reactive string):

  1. No memos. Resolve the tag once at factory time; the per-instance function returns the element directly. Hydration ids stay aligned because no owner is created on either side (the server path mirrors it).
  2. Template + static class. Accept a static class (and other static attrs) to bake into a cached template() like compiled JSX does, so the per-instance work is clone + getNextElement + reactive bindings only.
  3. Compiled-element semantics. Call runHydrationEvents() after binding (missing today, see dynamic() / Dynamic with a string tag: no runHydrationEvents(), namespace ignores parent #3386), and take the namespace from the mount context or an explicit option instead of SVGElements.has(tag) alone (see dynamic() / Dynamic with a string tag: no runHydrationEvents(), namespace ignores parent #3386).
  4. Keep the existing memo path for function/async sources; the string branch is a fast path, not a behavior change.

Tracker: #3389.

Public shape is open: either dynamic() detects it, or a small explicit primitive (element(tag, props, { class })) that libraries with a runtime styled() API can target. The second is what yak actually needed.

Measured

ryansolid/yak-bench: yak's base runtime rendered every styled element through Dynamic and sits at 0.65× React on SSR and ~2× slower than the PR on hydrate/mount; the PR's hand-rolled element path is 25× React on SSR for static tags. Acceptance for this issue: a yak-runtime variant that uses the new path instead of createElementRenderer lands within noise of it on compose-1 / button-variants-nested / btn-variant.

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