react() integration breaks dev-mode transform of TS-typed inline <script> in .astro files

Open
#3,603 1 comment 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 2 days

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
32/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
node.js, react, typescript, vite
Domain
build-system

Research direction

Reproduce with astro dev using the integrations in astro.config.mjs (react() plus emdash()), then request the failing URL File.astro?astro&type=script&index=0&lang.ts and diff the served output against the same project without react(). Trace which Vite plugin takes the transform hook for these virtual script modules — likely @astrojs/react's Oxc/esbuild pass running before Astro's TS handling — and check plugin ordering. Done looks like both the typed-parameter and querySelectorAll<HTMLVideoElement> snippets returning 200 with correct transforms.

Written by the indexing model from the issue text.

Description

bot:needs-attention bot:task bug
Description

Adding EmDash's required react() peer integration to a project that has inline <script> blocks using TypeScript syntax (e.g. a typed arrow function parameter, or document.querySelectorAll(...)) breaks Vite's dev-time transform for every such script, project-wide. Worse than a simple parse failure: some TS-only constructs (a typed parameter) fail loudly with a 500; others (expr(...) generic call syntax) get silently misparsed as valid plain-JS comparison-operator chaining (expr < Type > (...), evaluating to a boolean) with no error at all — the bug only surfaces when the resulting runtime exception (TypeError: not iterable on a subsequent for...of) silently aborts the rest of the containing function.

Steps to reproduce
// astro.config.mjs
integrations: [react(), emdash({ ... })]
<!-- any .astro file -->
<script>
  const reveal = (el: Element) => el.classList.add('is-visible');
</script>

Requesting /path/to/File.astro?astro&type=script&index=0&lang.ts under astro dev returns 500:

[PARSE_ERROR] Expected `,` or `)` but found `:`
    at src/layouts/Layout.astro?astro&type=script&index=0&lang.ts:11:20
    const reveal = (el: Element) => el.classList.add("is-visible");
                   ┬  ┬

The more dangerous variant, no error, wrong behavior:

<script>
  for (const video of document.querySelectorAll<HTMLVideoElement>('.hero__video')) {
    video.play();
  }
</script>

Served (200, no error) as:

for (const video of document.querySelectorAll < HTMLVideoElement > ".hero__video") {

— which throws at runtime instead of iterating video elements.

Bisected precisely: removing react() from integrations fixes both cases immediately (200, correct transform, correct runtime behavior); re-adding it reproduces both every time. Same astro/vite versions before and after — ruled out as an Astro-core regression.

Scope: confirmed dev-server only. astro build's bundler (Rollup/esbuild — a different code path from Vite dev's Oxc fast transform) parses both cases correctly; the built/shipped site is unaffected, verified by inspecting the actual built dist/server output and by exercising the built site's interactive JS in a real browser. Still a real, disruptive bug: EmDash's own live-content-editing workflow necessarily runs via astro dev (it needs the live database), so this is exactly the surface a site owner hits while actually using the CMS day to day, not an edge case.

Environment
  • emdash: 1.0.1
  • astro: 7.2.0
  • @astrojs/react: 5.0.7
  • @astrojs/node: 11.1.1 (Node standalone adapter)
  • vite: 8.2.1 (hoisted by astro)
  • react / react-dom: 19.3.0
  • Node.js: v26.10.0
  • npm: 11.19.1
  • Database / storage: SQLite (file:./data.db) + local filesystem media storage — the documented self-hosted target, no Cloudflare involved
  • OS: macOS 15.8 (24H23), arm64 (Apple Silicon)
  • Deploy target: self-hosted via Docker/git-push (Dokploy); bugs reproduced against astro dev locally before any deploy
Screenshots

Not applicable.

Logs / error output

Dominant language
TypeScript
Stars
13.4k
Forks
1.3k
Avg merge
2d 19h
Merged PRs (30d)
345

Getting set up

This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from emdash-cms/emdash

All issues in emdash-cms/emdash

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.