Skip to content

Align solid-markdown with react-markdown 10.1.0 and add Solid-native async rendering - #44

Draft
keithce wants to merge 1 commit into
andi23rosca:mainfrom
keithce:keithce/react-markdown-10-solid-port
Draft

Align solid-markdown with react-markdown 10.1.0 and add Solid-native async rendering#44
keithce wants to merge 1 commit into
andi23rosca:mainfrom
keithce:keithce/react-markdown-10-solid-port

Conversation

@keithce

@keithce keithce commented Mar 7, 2026

Copy link
Copy Markdown

Title

Align solid-markdown with react-markdown 10.1.0 and add Solid-native async rendering

Summary

This update moves solid-markdown from an older compatibility-focused API to an upstream-aligned react-markdown 10.1.0 style API, adapted for Solid. The rendering pipeline now follows the upstream remark -> rehype -> JSX runtime model, the public options match current upstream concepts, and async unified plugins are supported both on the server and on the client.

What changed

  • Replaced the custom renderer/filter pipeline with an upstream-style processor flow and hast-util-to-jsx-runtime.
  • Aligned the public API around Markdown, MarkdownAsync, MarkdownResource, remarkRehypeOptions, and urlTransform.
  • Simplified custom component typing so overrides receive normal Solid intrinsic props plus node.
  • Removed legacy wrapper-element behavior and made removed pre-v9 props fail explicitly at runtime instead of lingering as soft compatibility.
  • Added a Solid-native client async path through MarkdownResource.
  • Expanded SSR and client coverage to include rendering parity, URL safety, removed-prop runtime errors, plugin/property passthrough, and async lifecycle behavior.

Why this is valuable

  • It makes the package easier to understand for anyone already using modern react-markdown.
  • It removes older behavior that was diverging from upstream semantics and complicating maintenance.
  • It gives Solid users a clear story for async plugins on both the server and the client.
  • It tightens the package surface area and types instead of preserving multiple generations of API compatibility.
  • It raises confidence in the port with a much broader regression suite across SSR and browser rendering.

Compatibility and migration

This change is intentionally breaking in the same places where upstream has already moved on:

  • SolidMarkdown is removed in favor of the default Markdown export.
  • Wrapper props such as class/className are removed; callers should wrap the component themselves.
  • Legacy props such as source, plugins, renderers, allowNode, allowedTypes, disallowedTypes, transformLinkUri, and transformImageUri now throw.
  • urlTransform replaces the older link/image transform props.
  • renderingStrategy remains temporarily for the sync component only, but it is deprecated and intended for removal in the next major release.

Verification

Verified locally with:

pnpm lint
pnpm test
pnpm build

Current test coverage includes:

  • SSR rendering coverage
  • Browser rendering coverage
  • URL sanitization and transform behavior
  • Removed-prop runtime error coverage
  • Async plugin behavior for both MarkdownAsync and MarkdownResource

Notes for review

  • The goal here is not to preserve every historical solid-markdown API quirk. The goal is to make this package a clean Solid port of modern react-markdown.
  • The only intentional short-term compatibility holdout is the deprecated renderingStrategy prop on Markdown.
  • The README and demo docs were updated to describe the new API and the current verification story so users do not have to infer behavior from source alone.

@andi23rosca

Copy link
Copy Markdown
Owner

Thanks for this!

I'll have to play around with it and test it but I agree with the overall changes 👍🏻

@andi23rosca

Copy link
Copy Markdown
Owner

@keithce we should probably bump the version to 3.0.0 in the package.json since there's so many breaking changes in the API

rigel-mintaka added a commit to RigelBuild/solid-markdown that referenced this pull request Aug 21, 2026
…sertion

Review fixes for the react-markdown-10 port PR (additive child commit).

- README: the "Removed and deprecated behavior" list, adopted from
  upstream andi23rosca#44, wrongly stated renderingStrategy is deprecated and slated
  for removal. This fork deliberately un-deprecates it (design A5/R-A5):
  renderingStrategy="reconcile" is load-bearing for streaming DOM
  stability and consumers depend on it permanently. Corrected the bullet
  to document it as a supported, un-deprecated Solid-specific prop.
- test/client.test.tsx: replace deprecated Node.isSameNode() in the
  node-identity characterization test with strict !== (expect().not.toBe),
  the modern idiom. Behavior identical; assertion still fails if identity
  were preserved.

Refs RIG-2187
Co-authored-by: Matt Wilkinson <matt@rigel.build>
rigel-mintaka added a commit to RigelBuild/solid-markdown that referenced this pull request Aug 22, 2026
Replaces the Solid-1 upstream renderer with the react-markdown-10 API
(upstream PR andi23rosca#44 + andi23rosca#45), re-ported to Solid 2, and ships the bun test
harness that runs the component suite. Supersedes the earlier draft of
this PR, which was based on the pnpm+vitest toolchain that `main` retired
when it converted to bun + biome.

## Source

- `src/index.tsx` — the react-markdown-10 renderer (`Markdown`,
  `MarkdownAsync`, `MarkdownResource`, `defaultUrlTransform`) built on
  `hast-util-to-jsx-runtime`, re-ported to Solid 2 (`@solidjs/web`,
  `createStore`/`reconcile`, owned-write signals).
- `src/jsx-runtime.ts` — fork-local JSX runtime for
  `hast-util-to-jsx-runtime` over Solid-2 primitives, replacing the
  Solid-1-bound `solid-jsx` dependency.
- `src/types.ts` — public option/component types over `@solidjs/web` `JSX`.
- Retires the Solid-1 renderer: `renderer.tsx`, `rehype-filter.ts`,
  `utils.ts`, `utils.test.ts`.

## Test harness (bun)

`main` runs `bun test`, which has no Vite pipeline and no Solid JSX
transform, so the Solid-2 component suite needs a harness:

- `test/setup.ts` — a `Bun.plugin` preload that runs `babel-preset-solid`
  over `.tsx` sources (`SOLID_GENERATE` picks `dom` vs `ssr` output) and
  registers happy-dom globals for the client leg only.
- `bunfig.toml` — wires the preload into `bun test`.
- Two legs mirror the retired vitest `--mode ssr` split:
  `test:client` (happy-dom, `--conditions=browser --conditions=development`)
  and `test:ssr` (node env, `--conditions=development` for `devlop`
  assertion messages). `bun run test` runs both.
- `test/client.test.tsx` (11) + `test/server.test.tsx` (20) converted from
  vitest to `bun:test`; `@solidjs/testing-library` bumped to `1.0.0-beta.2`
  (the Solid-2 line — imports from `@solidjs/web`, drops the removed
  `onError`, which bun's strict ESM rejects where vitest silently tolerated).

## Packaging

- `package.json` — Solid-2 peers (`solid-js`, `@solidjs/web` `^2.0.0-rc.0`),
  `3.0.0-rc.0`, bun harness devDeps, two-leg test scripts.
- `biome.json` — disables the React-specific `noChildrenProp` rule
  (`children` as a prop is this package's public API).
- `.github/workflows/ci.yml` + `publish.yml` — run `bun run test` (both
  legs); `publish.yml` converted pnpm -> bun, tag-driven, dist-tag aware
  (`next` for prereleases, `latest` otherwise).

Spec-impact: none. Refs RIG-2187, RIG-2358.

Co-authored-by: Matt Wilkinson <matt@rigel.build>
rigel-mintaka added a commit to RigelBuild/solid-markdown that referenced this pull request Aug 22, 2026
… bun

Replaces the Solid-1 upstream renderer with the react-markdown-10 API
(upstream PR andi23rosca#44 + andi23rosca#45), re-ported to Solid 2, and ships the bun test
harness + bun build that the fork's bun + biome toolchain needs.

## Source

- `src/index.tsx` — the react-markdown-10 renderer (`Markdown`,
  `MarkdownAsync`, `MarkdownResource`, `defaultUrlTransform`) built on
  `hast-util-to-jsx-runtime`, re-ported to Solid 2 (`@solidjs/web`,
  `createStore`/`reconcile`, owned-write signals).
- `src/jsx-runtime.ts` — fork-local JSX runtime for
  `hast-util-to-jsx-runtime` over Solid-2 primitives, replacing the
  Solid-1-bound `solid-jsx` dependency.
- `src/types.ts` — public option/component types over `@solidjs/web` `JSX`.
- Retires the Solid-1 renderer: `renderer.tsx`, `rehype-filter.ts`,
  `utils.ts`, `utils.test.ts`.

## Build (bun)

The prior `tsup` + `tsup-preset-solid` + `esbuild-plugin-solid` chain was
hard-pinned to `babel-preset-solid@1` (Solid 1) and emitted the removed
`solid-js/web` import subpath, so the published dist threw
`ERR_PACKAGE_PATH_NOT_EXPORTED` on load under the Solid-2 peer. Replaced
with `build.ts`, a `bun build` script running `babel-preset-solid@2` (the
same transform the test harness uses):

- Emits the six export-condition variants (dom prod/dev, ssr, and the
  JSX-preserving `.jsx` for the `solid` condition) + `index.d.ts` via `tsc`.
- `scripts/smoke-dist.ts` imports every compiled entry and asserts the
  public API resolves — chained into `build` and run in CI + before publish,
  so a dead-on-arrival bundle fails the gate (nothing else imports `dist`).
- Runtime deps moved from `devDependencies` to `dependencies` (they are
  externalized in dist and must install for consumers); dead deps and the
  retired tsup/esbuild toolchain removed.

## Test harness (bun)

`bun test` has no Vite pipeline and no Solid JSX transform, so the Solid-2
suite needs a harness:

- `test/setup.ts` — a `Bun.plugin` preload that runs `babel-preset-solid`
  over `.tsx` sources (`SOLID_GENERATE` picks `dom` vs `ssr`) and registers
  happy-dom globals for the client leg only.
- `bunfig.toml` — wires the preload into `bun test`.
- Two legs mirror the retired vitest `--mode ssr` split:
  `test:client` (happy-dom, `--conditions=browser --conditions=development`)
  and `test:ssr` (node env, `--conditions=development` for `devlop`
  assertion messages). `bun run test` runs both.
- `test/client.test.tsx` (11) + `test/server.test.tsx` (20) converted from
  vitest to `bun:test`; `@solidjs/testing-library` bumped to `1.0.0-beta.2`
  (the Solid-2 line — imports from `@solidjs/web`, drops the removed
  `onError`, which bun's strict ESM rejects where vitest silently tolerated).

## Packaging

- `package.json` — Solid-2 peers (`solid-js`, `@solidjs/web` `^2.0.0-rc.0`),
  `3.0.0-rc.0`, runtime `dependencies` + bun harness/build devDeps, two-leg
  test scripts, `bun run build.ts` build.
- `biome.json` — disables the React-specific `noChildrenProp` rule
  (`children` as a prop is this package's public API).
- `.github/workflows/ci.yml` + `publish.yml` — run `bun run test` (both
  legs) + `bun run build` (which self-verifies via the dist smoke check);
  `publish.yml` converted pnpm -> bun, tag-driven, dist-tag aware.

Spec-impact: none. Refs RIG-2187, RIG-2358.

Co-authored-by: Matt Wilkinson <matt@rigel.build>
rigel-mintaka added a commit to RigelBuild/solid-markdown that referenced this pull request Aug 22, 2026
… bun

Replaces the Solid-1 upstream renderer with the react-markdown-10 API
(upstream PR andi23rosca#44 + andi23rosca#45), re-ported to Solid 2, and ships the bun test
harness + bun build that the fork's bun + biome toolchain needs.

## Source

- `src/index.tsx` — the react-markdown-10 renderer (`Markdown`,
  `MarkdownAsync`, `MarkdownResource`, `defaultUrlTransform`) built on
  `hast-util-to-jsx-runtime`, re-ported to Solid 2 (`@solidjs/web`,
  `createStore`/`reconcile`, owned-write signals).
- `src/jsx-runtime.ts` — fork-local JSX runtime for
  `hast-util-to-jsx-runtime` over Solid-2 primitives, replacing the
  Solid-1-bound `solid-jsx` dependency.
- `src/types.ts` — public option/component types over `@solidjs/web` `JSX`.
- Retires the Solid-1 renderer: `renderer.tsx`, `rehype-filter.ts`,
  `utils.ts`, `utils.test.ts`.

## Build (bun)

`build.ts` builds `dist/` with `babel-preset-solid@2` (the Solid compiler)
as the one transform, in two output modes:

- Compiled (`index.js` dom/prod, `dev.js` dom/dev, `server.js` ssr) — Solid
  compiles the JSX to `@solidjs/web` runtime calls, then `bun build` bundles
  the now JSX-free modules. `bun build` never sees JSX.
- Source (`index.jsx` + a sibling `jsx-runtime.js`) — babel strips types but
  leaves the JSX untransformed, written directly, so the `solid` export
  condition ships raw JSX for a consuming app's own Solid compiler (matching
  its exact `solid-js` version and generate settings). This variant is not
  routed through `bun build`, whose own automatic JSX-runtime transform would
  emit a `@solidjs/web/jsx-dev-runtime` import that subpath does not provide.
- `index.d.ts` via `tsc --project tsconfig.build.json`.
- `scripts/smoke-dist.ts` guards the published artifact: imports each compiled
  entry and asserts the public API resolves, and compiles the `.jsx` source
  entry the way a consumer would, asserting it targets `@solidjs/web` and never
  a removed subpath. Chained into `build` and run in CI + before publish, so a
  dead-on-arrival bundle fails the gate (nothing else imports `dist`).
- Runtime deps are declared under `dependencies` (externalized in dist);
  peer deps under `peerDependencies`; build/harness tooling under
  `devDependencies`.

## Test harness (bun)

`bun test` has no Vite pipeline and no Solid JSX transform, so the Solid-2
suite needs a harness:

- `test/setup.ts` — a `Bun.plugin` preload that runs `babel-preset-solid`
  over `.tsx` sources (`SOLID_GENERATE` picks `dom` vs `ssr`) and registers
  happy-dom globals for the client leg only.
- `bunfig.toml` — wires the preload into `bun test`.
- Two legs mirror the retired vitest `--mode ssr` split:
  `test:client` (happy-dom, `--conditions=browser --conditions=development`)
  and `test:ssr` (node env, `--conditions=development` for `devlop`
  assertion messages). `bun run test` runs both.
- `test/client.test.tsx` (11) + `test/server.test.tsx` (20) converted from
  vitest to `bun:test`; `@solidjs/testing-library` bumped to `1.0.0-beta.2`
  (the Solid-2 line — imports from `@solidjs/web`, drops the removed
  `onError`, which bun's strict ESM rejects where vitest silently tolerated).

## Packaging

- `package.json` — Solid-2 peers (`solid-js`, `@solidjs/web` `^2.0.0-rc.0`),
  `3.0.0-rc.0`, runtime `dependencies` + bun harness/build devDeps, two-leg
  test scripts, `bun run build.ts` build.
- `biome.json` — disables the React-specific `noChildrenProp` rule
  (`children` as a prop is this package's public API).
- `.github/workflows/ci.yml` + `publish.yml` — run `bun run test` (both
  legs) + `bun run build` (which self-verifies via the dist smoke check);
  `publish.yml` converted pnpm -> bun, tag-driven, dist-tag aware.

Spec-impact: none. Refs RIG-2187, RIG-2358.

Co-authored-by: Matt Wilkinson <matt@rigel.build>
mattwilkinsonn added a commit to RigelBuild/solid-markdown that referenced this pull request Aug 22, 2026
… bun (#1)

Replaces the Solid-1 upstream renderer with the react-markdown-10 API
(upstream PR andi23rosca#44 + andi23rosca#45), re-ported to Solid 2, and ships the bun test
harness + bun build that the fork's bun + biome toolchain needs.

## Source

- `src/index.tsx` — the react-markdown-10 renderer (`Markdown`,
  `MarkdownAsync`, `MarkdownResource`, `defaultUrlTransform`) built on
  `hast-util-to-jsx-runtime`, re-ported to Solid 2 (`@solidjs/web`,
  `createStore`/`reconcile`, owned-write signals).
- `src/jsx-runtime.ts` — fork-local JSX runtime for
  `hast-util-to-jsx-runtime` over Solid-2 primitives, replacing the
  Solid-1-bound `solid-jsx` dependency.
- `src/types.ts` — public option/component types over `@solidjs/web` `JSX`.
- Retires the Solid-1 renderer: `renderer.tsx`, `rehype-filter.ts`,
  `utils.ts`, `utils.test.ts`.

## Build (bun)

`build.ts` builds `dist/` with `babel-preset-solid@2` (the Solid compiler)
as the one transform, in two output modes:

- Compiled (`index.js` dom/prod, `dev.js` dom/dev, `server.js` ssr) — Solid
  compiles the JSX to `@solidjs/web` runtime calls, then `bun build` bundles
  the now JSX-free modules. `bun build` never sees JSX.
- Source (`index.jsx` + a sibling `jsx-runtime.js`) — babel strips types but
  leaves the JSX untransformed, written directly, so the `solid` export
  condition ships raw JSX for a consuming app's own Solid compiler (matching
  its exact `solid-js` version and generate settings). This variant is not
  routed through `bun build`, whose own automatic JSX-runtime transform would
  emit a `@solidjs/web/jsx-dev-runtime` import that subpath does not provide.
- `index.d.ts` via `tsc --project tsconfig.build.json`.
- `scripts/smoke-dist.ts` guards the published artifact: imports each compiled
  entry and asserts the public API resolves, and compiles the `.jsx` source
  entry the way a consumer would, asserting it targets `@solidjs/web` and never
  a removed subpath. Chained into `build` and run in CI + before publish, so a
  dead-on-arrival bundle fails the gate (nothing else imports `dist`).
- Runtime deps are declared under `dependencies` (externalized in dist);
  peer deps under `peerDependencies`; build/harness tooling under
  `devDependencies`.

## Test harness (bun)

`bun test` has no Vite pipeline and no Solid JSX transform, so the Solid-2
suite needs a harness:

- `test/setup.ts` — a `Bun.plugin` preload that runs `babel-preset-solid`
  over `.tsx` sources (`SOLID_GENERATE` picks `dom` vs `ssr`) and registers
  happy-dom globals for the client leg only.
- `bunfig.toml` — wires the preload into `bun test`.
- Two legs mirror the retired vitest `--mode ssr` split:
  `test:client` (happy-dom, `--conditions=browser --conditions=development`)
  and `test:ssr` (node env, `--conditions=development` for `devlop`
  assertion messages). `bun run test` runs both.
- `test/client.test.tsx` (11) + `test/server.test.tsx` (20) converted from
  vitest to `bun:test`; `@solidjs/testing-library` bumped to `1.0.0-beta.2`
  (the Solid-2 line — imports from `@solidjs/web`, drops the removed
  `onError`, which bun's strict ESM rejects where vitest silently tolerated).

## Packaging

- `package.json` — Solid-2 peers (`solid-js`, `@solidjs/web` `^2.0.0-rc.0`),
  `3.0.0-rc.0`, runtime `dependencies` + bun harness/build devDeps, two-leg
  test scripts, `bun run build.ts` build.
- `biome.json` — disables the React-specific `noChildrenProp` rule
  (`children` as a prop is this package's public API).
- `.github/workflows/ci.yml` + `publish.yml` — run `bun run test` (both
  legs) + `bun run build` (which self-verifies via the dist smoke check);
  `publish.yml` converted pnpm -> bun, tag-driven, dist-tag aware.

Spec-impact: none. Refs RIG-2187, RIG-2358.

Co-authored-by: Matt Wilkinson <matt@rigel.build>
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.

2 participants