Skip to content

⚡ Give @tinacms/mdx a light sanitize-url subpath so rich-text skips the parser#7233

Merged
joshbermanssw merged 1 commit into
mainfrom
perf/mdx-sanitize-url-subpath
Jul 23, 2026
Merged

⚡ Give @tinacms/mdx a light sanitize-url subpath so rich-text skips the parser#7233
joshbermanssw merged 1 commit into
mainfrom
perf/mdx-sanitize-url-subpath

Conversation

@wicksipedia

@wicksipedia wicksipedia commented Jul 13, 2026

Copy link
Copy Markdown
Member

Tagged: tina-io-git-jb-test-7233-tinacms.vercel.app

Summary

  • packages/tinacms/src/rich-text/index.tsx and static.tsx (source of TinaMarkdown / StaticTinaMarkdown) imported sanitizeUrl from the root @tinacms/mdx entry, which is built with bundleDeps: true and inlines the entire remark/mdast/micromark/prettier markdown-parsing toolchain (~2MB) — even though sanitizeUrl is a ~40-line URL-scheme check.
  • Adds a dedicated, dependency-free @tinacms/mdx/sanitize-url subpath (own entry point in buildConfig.entryPoints, own exports map entry — same multi-entry pattern @tinacms/bridge already uses) and points the rich-text renderer at it instead.
  • The root @tinacms/mdx export of sanitizeUrl is unchanged (still re-exported from parse/remarkToPlate.ts), so this is purely additive/non-breaking.

Fixes #7232

Measured before/after

Built both packages from main (711ba30f6) vs. this branch with pnpm exec turbo run build --filter=@tinacms/mdx --filter=tinacms --force, then measured the actual emitted files:

Before After
tinacms/dist/rich-text/index.js import from "@tinacms/mdx" from "@tinacms/mdx/sanitize-url"
what that import resolves to @tinacms/mdx/dist/index.js2,013,349 bytes (Node/SSR) or dist/index.browser.js1,976,351 bytes (browser condition) @tinacms/mdx/dist/sanitize-url.js658 bytes
rich-text/index.js itself 12,493 bytes 12,506 bytes (+13 bytes, longer import specifier)
total pulled in by a site's rich-text import ~1.99–2.03 MB 13,164 bytes (~12.9 KB)

That's a ~99.3% reduction — the new sanitize-url.js was also grepped to confirm it contains no remark/mdast/micromark/prettier references.

Test plan

  • pnpm test from repo root (full suite, not filtered) — 58/58 tasks passed, including @tinacms/mdx's existing sanitizeUrl unit tests (remarkToPlate.test.ts, 21 tests, unchanged) and tinacms's full vitest suite (444 passed, 5 skipped)
  • Verified packages/@tinacms/mdx/dist/sanitize-url.js is 658 bytes and free of remark/mdast/micromark/prettier imports
  • Verified packages/tinacms/dist/rich-text/index.js now imports @tinacms/mdx/sanitize-url, not the @tinacms/mdx root
  • Verified tsc (the types task) emits a real .d.ts for the new entry point
  • Added a changeset (@tinacms/mdx: minor, tinacms: patch)

🤖 Generated with Claude Code

…he parser

TinaMarkdown/StaticTinaMarkdown only needed sanitizeUrl from @tinacms/mdx,
but importing anything from the package root pulled in its whole
remark/mdast/micromark bundle (~2MB) into every site's client bundle.

Adds a dedicated @tinacms/mdx/sanitize-url entry (same multi-entry pattern
as @tinacms/bridge) and points tinacms's rich-text renderer at it. The root
@tinacms/mdx export of sanitizeUrl is unchanged.

Fixes #7232

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@wicksipedia
wicksipedia requested a review from a team as a code owner July 13, 2026 23:31
@changeset-bot

changeset-bot Bot commented Jul 13, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: c86202f

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 16 packages
Name Type
@tinacms/mdx Minor
tinacms Patch
@tinacms/app Patch
@tinacms/graphql Patch
next-tinacms-azure Patch
next-tinacms-cloudinary Patch
next-tinacms-dos Patch
next-tinacms-s3 Patch
tinacms-authjs Patch
tinacms-clerk Patch
@tinacms/cli Patch
@tinacms/vercel-previews Patch
playwright-testing Patch
@tinacms/datalayer Patch
@tinacms/search Patch
tinacms-gitprovider-github Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions

Copy link
Copy Markdown
Contributor

Playwright E2E Test Results

passed  48 passed
skipped  3 skipped

Details

stats  51 tests across 16 suites
duration  50.8 seconds
commit  c86202f

Skipped tests

chromium › retain-input-value-from-localstorage.spec.ts › Local storage retain edit test
chromium › rich-text-editor/newline-parsing.spec.ts › should be able to parse newline from markdown
api › api/security.spec.ts › media delete rejects null byte

@joshbermanssw joshbermanssw left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving. Built the branch and verified the numbers rather than reading them: dist/sanitize-url.js is 658 bytes with no remark/mdast/micromark/prettier in it, dist/index.js is untouched at 2,013,373 bytes, both rich-text entries emit the subpath import, the subpath and root export resolve identically at runtime, and the types task emits a real .d.ts (not the build-time stub). mdx tests and the tinacms typecheck pass. The sanitizer body is a byte-identical move, which is the right call for a security-relevant function.

Two follow-ups, neither blocking:

  1. Latent footgun worth a comment. @tinacms/scripts (src/index.ts:411-435) hardcodes dist/index.js / dist/index.browser.js as outfiles in the @tinacms/mdx branch, ignoring the entry's computed output path. The new entry is safe only because it's a plain string, which normalizes to target: 'browser' and takes the Vite path instead. If someone later rewrites it in object form with target: 'node' to match its sibling (which reads as harmless tidying), it silently overwrites the 2MB root bundle with the 658-byte sanitizer. Worth a note on the entry in package.json, or fixing the script to use outInfo.outfile.

  2. The description's mechanism isn't quite right. bundleDeps isn't read anywhere in @tinacms/scripts; the Entry type has bundle: string[] (graphql/datalayer only) and target. mdx's dep bundling comes from that hardcoded package-name branch. The outcome is correct, but the causal story will mislead whoever touches this next.

Nits: the sanitizeUrl tests still live in parse/remarkToPlate.test.ts and import from ./remarkToPlate, so they exercise the re-export shim rather than the new module (src/sanitize-url.test.ts would be the natural home). And the changeset says "~15-line sanitizer" while the PR body says "~40-line"; the changeset is the one that lands in the public CHANGELOG.

@joshbermanssw joshbermanssw added the tagged This PR should be given a tagged release label Jul 15, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📦 Tagged Release Published

Your tagged PR has been published! You can install the packages using their version tags:

pnpm add @tinacms/app@0.0.0-2f4b2ec-20260715013251
pnpm add @tinacms/astro@0.0.0-2f4b2ec-20260715013251
pnpm add @tinacms/bridge@0.0.0-2f4b2ec-20260715013251
pnpm add @tinacms/cli@0.0.0-2f4b2ec-20260715013251
pnpm add @tinacms/datalayer@0.0.0-2f4b2ec-20260715013251
pnpm add @tinacms/graphql@0.0.0-2f4b2ec-20260715013251
pnpm add @tinacms/mdx@0.0.0-2f4b2ec-20260715013251
pnpm add @tinacms/search@0.0.0-2f4b2ec-20260715013251
pnpm add @tinacms/vercel-previews@0.0.0-2f4b2ec-20260715013251
pnpm add next-tinacms-azure@0.0.0-2f4b2ec-20260715013251
pnpm add next-tinacms-cloudinary@0.0.0-2f4b2ec-20260715013251
pnpm add next-tinacms-dos@0.0.0-2f4b2ec-20260715013251
pnpm add next-tinacms-s3@0.0.0-2f4b2ec-20260715013251
pnpm add tinacms-authjs@0.0.0-2f4b2ec-20260715013251
pnpm add tinacms-clerk@0.0.0-2f4b2ec-20260715013251
pnpm add tinacms-gitprovider-github@0.0.0-2f4b2ec-20260715013251
pnpm add tinacms@0.0.0-2f4b2ec-20260715013251

Published Packages:

  • @tinacms/app@0.0.0-2f4b2ec-20260715013251
  • @tinacms/astro@0.0.0-2f4b2ec-20260715013251
  • @tinacms/bridge@0.0.0-2f4b2ec-20260715013251
  • @tinacms/cli@0.0.0-2f4b2ec-20260715013251
  • @tinacms/datalayer@0.0.0-2f4b2ec-20260715013251
  • @tinacms/graphql@0.0.0-2f4b2ec-20260715013251
  • @tinacms/mdx@0.0.0-2f4b2ec-20260715013251
  • @tinacms/search@0.0.0-2f4b2ec-20260715013251
  • @tinacms/vercel-previews@0.0.0-2f4b2ec-20260715013251
  • next-tinacms-azure@0.0.0-2f4b2ec-20260715013251
  • next-tinacms-cloudinary@0.0.0-2f4b2ec-20260715013251
  • next-tinacms-dos@0.0.0-2f4b2ec-20260715013251
  • next-tinacms-s3@0.0.0-2f4b2ec-20260715013251
  • tinacms-authjs@0.0.0-2f4b2ec-20260715013251
  • tinacms-clerk@0.0.0-2f4b2ec-20260715013251
  • tinacms-gitprovider-github@0.0.0-2f4b2ec-20260715013251
  • tinacms@0.0.0-2f4b2ec-20260715013251

Commit: 2f4b2ec6aa40d92ca14c18c7291ebd1de069d018

@joshbermanssw
joshbermanssw merged commit 5f14d96 into main Jul 23, 2026
25 checks passed
@joshbermanssw
joshbermanssw deleted the perf/mdx-sanitize-url-subpath branch July 23, 2026 00:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

tagged This PR should be given a tagged release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

🤖 TinaMarkdown's rich-text renderer pulls in @tinacms/mdx's full ~2MB markdown parser just for sanitizeUrl

3 participants