Skip to content

🐛 Images - Show the same image URLs with local Tina data as with TinaCloud data - #2804

Open
bradystroud wants to merge 5 commits into
mainfrom
bs/2801-absolute-image-paths
Open

bradystroud wants to merge 5 commits into
mainfrom
bs/2801-absolute-image-paths

Conversation

@bradystroud

Copy link
Copy Markdown
Member

Description

✏️
Relates to #2801 (phase 3, first task). Release this pull request before the build reads local content.

Pain

  • TinaCloud returns an image as a URL: https://assets.tina.io/<client ID>/rules/<folder>/<file>.
  • The local Tina server returns the stored path: /uploads/rules/<folder>/<file>. The production site does not serve that path (404).
  • A production build from local content with the components on main has broken images. In a test build, 16 of 18 pages had image URLs that are different from production (50 URLs).

Change

  • New lib/tinaAssets.ts:
    • toTinaAssetUrl(value) gives the URL that TinaCloud returns for a stored media path. All other values stay the same.
    • tinaImageSrc(value) does the same for an image value. In development it keeps the stored path, because proxy.ts serves that path from the local content repository.
    • withTinaImageSrc(content) converts the URL of each markdown image in rich-text content.
  • Each function gives the same result when a value passes through it two times.
  • NEXT_PUBLIC_TINA_CLIENT_ID gives the client ID. It is a Docker build argument, and Next.js puts it into the server and client code at build time.
Place Value Change
components/embeds/imageEmbed.tsx src of an image embed tinaImageSrc
components/typography-components.tsx (img) markdown image tinaImageSrc
components/typography-components.tsx (a) link to a file Uses toTinaAssetUrl. The result is the same as before.
app/[filename]/ServerRulePage.tsx rule thumbnail tinaImageSrc
All 7 TinaMarkdown render sites: ServerRulePage.tsx, ServerCategoryPage.tsx, rule-list-item.tsx, boxEmbed.tsx, emailEmbed.tsx, HelpImproveCard.tsx, WhyRulesCard.tsx rich-text content withTinaImageSrc
  • Why the content needs a conversion: TinaMarkdown shows the content of a table cell with its default components. An image in a table does not get the img component of the site. 5 images in 2 rules are in tables.

Values (measured on 18 production pages and on all 4,173 content files)

Local Tina server TinaCloud Number in the content
/uploads/rules/<folder>/<file> https://assets.tina.io/<client ID>/rules/<folder>/<file> 5,601
/uploads/categories/<file> https://assets.tina.io/<client ID>/categories/<file> 4
/uploads/__staging/<path> https://assets.tina.io/<client ID>/__staging/<path> 1
/uploadshttps://github.com/... https://github.com/... 6
External image URL Same value 51
Link to a file: /uploads/rules/<folder>/<file>.pdf Same value (Tina does not change a link) 15

Result

  • TinaCloud data: no change. The full HTML of the rule body is the same before and after the change for the 41 bodies from production and for all 4,173 content files in the TinaCloud form.
  • Local data, production build with the local Tina server: 18 pages (16 rules, 2 categories), 321 URLs. 0 differences from production. Without the change: 50 differences on 16 pages.
  • Local data, all content: 5,663 images in 4,173 files have the URL that TinaCloud returns.
  • Other prerendered routes (/, /categories, /archived, /orphaned, /search, /user): no Tina image value in the HTML. The Open Graph routes use the title and the author profile URL only.
  • Browser (Chrome, local production build): 8 page loads and 6 client-side navigations, 35 image URLs. All are the same as in production. No hydration message.
  • Development server: 7 pages, 57 URLs. No change.

Tests

  • 85 new unit tests in 3 files (tinaAssets, tinaImagePaths, tinaContentImages).
  • pnpm lint and pnpm test pass. tina/tina-lock.json does not change.

Risks

  • A pull request preview that uses its own content branch: after phase 3, its images get asset URLs of the default branch. A new image of that branch can give a 404 until the merge. The TinaCloud form for such a branch (/__staging/<branch>/__file/...) was not measured.
  • Release order: a browser tab with the old JavaScript that navigates to a page built from local data shows relative paths. Next.js makes a full page load when the build ID changes, so no problem is expected. This was not tested.
  • Found, not changed:
    • In development with a base path, ImageEmbed and an image in a table ask for /uploads/... without the base path and get a 404. This is the same as on main.
    • A link to a file in a table cell keeps the stored path, with TinaCloud data and with local data.
    • Content error: 6 image values have /uploads in front of an external URL. Rules: easy-recording-space, follow-up-effectively, good-email-subject. TinaCloud removes the prefix, and this change does the same.
    • Content error: 11 links point to assets of a different Tina client ID (0860fe57-1f97-414a-83c0-f84291018cf3). Rules: browser-add-branding, use-icons-to-not-surprise-users, video-background.

Possible TinaCMS follow-up

  • TinaMarkdown table cells ignore the given components. It passes only p to the content of a cell, so an image or a link in a table always gets the default component.

Screenshot (optional)

✏️ Not applicable. The pages look the same.

🤖 Generated with Claude Code

https://claude.ai/code/session_01UTtNDpWnuaUUQ2winSSgMb

bradystroud and others added 4 commits November 13, 2026 08:55
…Cloud data (#2801)

The local Tina server returns the stored path of a media file, for example
"/uploads/rules/<folder>/<file>". TinaCloud returns the URL of its asset host for the same file.
No route of the production site serves the stored path. Thus a page that is built from local
content has broken images.

- Add lib/tinaAssets.ts. It gives the URL that TinaCloud returns for a stored media path.
- Use it in the image embed, the markdown image and the rule thumbnail.
- Convert the image URLs in the rule body before TinaMarkdown gets the body. TinaMarkdown shows
  an image in a table cell with its default components, not with the components of the site.
- Use the same function for the link to a file. The result of the link does not change.
- In development, the image path does not change. The development server serves that path from
  the local content repository.

A value from TinaCloud does not change. Thus the pages that are built from TinaCloud data stay the same.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UTtNDpWnuaUUQ2winSSgMb
… cards (#2801)

The "Help Improve Our Rules" card and the "Why All These Rules?" card give only some components
to TinaMarkdown. TinaMarkdown thus shows an image in their rich text with its default component,
and the URL must be correct in the content.

No image is in these two fields at this time, so no page changes. With local Tina data, an image
that an editor adds later gets the same URL as with TinaCloud data.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UTtNDpWnuaUUQ2winSSgMb
…2801)

The list has values that are not a path of the media library. TinaCloud does not return each of
them in the same form, so the old comment was not correct.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UTtNDpWnuaUUQ2winSSgMb
#2801)

The category page, the box embed and the email embed also give rich text to TinaMarkdown.
They now convert the image URLs in that content, so each TinaMarkdown render site has the
same guarantee. An embed does not depend on the page that renders it.

The conversion gives the same result when a value passes through it two times. Tests cover this.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UTtNDpWnuaUUQ2winSSgMb
@bradystroud

Copy link
Copy Markdown
Member Author

🎬 Explainer video for this pull request (about 40 seconds, no sound): the problem, the change, and how it helps.

🤖 Generated with Claude Code

pr-2804.mp4

Comment thread lib/tinaAssets.ts Resolved
Comment thread components/typography-components.tsx Resolved
- tinaAssets.ts: the development proxy serves only /uploads/rules/ images and
  files, not each stored path.
- typography-components.tsx: Tina leaves a link path unchanged, and this
  function converts it to the asset URL.

Review suggestions from Josh Berman.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UTtNDpWnuaUUQ2winSSgMb

This branch has not been deployed

No deployments
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