Skip to content

feat(react-email): hot reloading around dynamic import#3422

Open
actuallyzefe wants to merge 21 commits into
resend:canaryfrom
actuallyzefe:fix/3412-email-dev-not-watching-messages-files
Open

feat(react-email): hot reloading around dynamic import#3422
actuallyzefe wants to merge 21 commits into
resend:canaryfrom
actuallyzefe:fix/3412-email-dev-not-watching-messages-files

Conversation

@actuallyzefe
Copy link
Copy Markdown
Contributor

@actuallyzefe actuallyzefe commented Apr 25, 2026

Fixes #3412.

When an email template loads files through a dynamic import() . for example, react-i18next registering translations via resourcesToBackend((lng, ns) => import(./messages/${lng}/${ns}.json)) . those files never entered the static dependency graph that email dev builds. The chokidar watcher therefore never saw them, and editing a translation JSON did not refresh the preview.

The user had to edit the template at the same time or restart the dev server.

This PR teaches the dev server's AST traversal to recognize dynamic import() calls, so the relevant directories are watched automatically, no flag, no configuration.

How it works

The dependency graph already parses every module with Babel and collects static import / require paths. Two cases are now also
handled:

  1. import('./literal-string') treated identically to a static import. The path is added to the graph as a regular file
    dependency.

  2. import(`./prefix/${expr}/...`) the leading static portion of the template literal (./prefix/) is captured as a glob
    directory dependency
    of the importing module. The directory is added to chokidar's watch set, and any file change inside it
    propagates to the importing module's dependents through the existing transitive-resolution path. The set of watched directories is
    reconciled on every graph update, so adding or removing a dynamic import while the dev server is running just works.

Guards in resolveGlobPrefixToDirectory keep the watch set focused:

  • bare module specifiers are skipped (import(`pkg/${x}`));
  • the importing module's own directory and its ancestors are skipped (import(`./${x}`) would otherwise reload everything on
    every change);
  • non-existent or non-directory targets are skipped.

Behavior

  • import(`./locales/${lng}.json`)./locales/ is watched automatically.
  • Works for any extension or no extension, the watcher is path-based, not content-aware. JSON, MDX, YAML, HTML, SVG, raw text,
    etc.
  • Static import 'x.json' continues to work exactly as before.

Summary by cubic

Auto-watches directories discovered from dynamic import() calls in react-email dev, so edits to runtime-loaded files (e.g., i18n JSON) refresh previews. Resolves tsconfig path aliases with fallback; no flags or config needed.

  • Bug Fixes

    • Detect dynamic imports: import('./x') and import(./x) are treated as static; import(./prefix/${...}) watches the leading ./prefix/; alias form import(@/prefix/${...}) resolves tsconfig path aliases with fallback to the first existing directory.
    • Changes in these directories map to the importing template and its dependents, triggering reloads even when files aren’t in the static graph. The watch set is reconciled on graph updates; skips bare specifiers, the module’s own dir/ancestors, and missing/non-directory paths. Path checks handle edge cases (e.g., root paths). Tests cover dynamic, aliased, and alias-fallback cases.
  • Refactors

    • Renamed internal glob tracking to dynamicDependencyDirectories for clarity.

Written for commit 548a3c2. Summary will update on new commits.

Introduced a new --watch option to the CLI for specifying additional file or directory paths to monitor. Changes in these paths will trigger a reload of all email previews, enhancing the development experience for files loaded at runtime. Updated the setupHotreloading function to handle these paths and added utility functions for path management.
@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented Apr 25, 2026

@actuallyzefe is attempting to deploy a commit to the resend Team on Vercel.

A member of the Team first needs to authorize it.

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 25, 2026

🦋 Changeset detected

Latest commit: 548a3c2

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

This PR includes changesets to release 3 packages
Name Type
react-email Patch
@react-email/editor Patch
@react-email/ui 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

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Apr 25, 2026

Open in StackBlitz

npm i https://pkg.pr.new/react-email@3422

commit: 548a3c2

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

No issues found across 6 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

Shadow auto-approve: would auto-approve. Additive, opt-in CLI feature for the dev server with no impact on production logic or default behavior. Includes tests and documentation.

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

0 issues found across 2 files (changes from recent commits).

Shadow auto-approve: would require human review. Introduces a new CLI flag and additive logic for directory traversal and watching in the dev server. This is a feature addition that requires human review for UX and performance impact.

Comment thread packages/react-email/readme.md Outdated
Comment thread packages/react-email/src/cli/index.ts Outdated
Copy link
Copy Markdown
Member

@gabrielmfern gabrielmfern left a comment

Choose a reason for hiding this comment

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

I think it's worth it exploring if we can improve file watching to get things to work with dynamic imports too.

@actuallyzefe
Copy link
Copy Markdown
Contributor Author

I think it's worth it exploring if we can improve file watching to get things to work with dynamic imports too.

on it, thanks

This commit removes the `--watch` option from the CLI, simplifying the development server setup. It enhances the dynamic import handling by introducing a mechanism to track directories from dynamic imports, ensuring that changes in these directories trigger email previews to reload. Additionally, it updates the dependency graph to accommodate these changes and includes tests for the new functionality.
@actuallyzefe actuallyzefe changed the title fix(cli): add --watch option for dynamic file watching in dev server fix(cli): detect dynamic imports in the dev server's dependency graph Apr 27, 2026
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

3 issues found across 13 files (changes from recent commits).

Shadow auto-approve: would not auto-approve because issues were found.

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/react-email/src/cli/utils/preview/hot-reloading/get-imported-modules.ts">

<violation number="1" location="packages/react-email/src/cli/utils/preview/hot-reloading/get-imported-modules.ts:68">
P2: Dynamic `import()` with template literals that have no interpolation are misclassified as glob prefixes instead of static imports.</violation>
</file>

<file name="packages/react-email/src/cli/utils/preview/hot-reloading/create-dependency-graph.ts">

<violation number="1" location="packages/react-email/src/cli/utils/preview/hot-reloading/create-dependency-graph.ts:81">
P2: `isUnderDirectory` fails for root directory paths (`/`), causing incorrect ancestry/containment checks in new dynamic glob dependency handling.</violation>

<violation number="2" location="packages/react-email/src/cli/utils/preview/hot-reloading/create-dependency-graph.ts:96">
P2: Alias-based dynamic import template prefixes are discarded, so hot reloading can miss changes for files imported via tsconfig path aliases.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

…solution

This commit introduces a new function to resolve tsconfig path aliases for dynamic imports, allowing for more flexible module loading. It updates the dependency graph to accommodate these changes and adds tests to verify the correct resolution of aliased paths. Additionally, it refactors the `isUnderDirectory` function to handle edge cases more effectively.
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 8 files (changes from recent commits).

Shadow auto-approve: would not auto-approve because issues were found.

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/react-email/src/cli/utils/preview/hot-reloading/resolve-path-aliases.ts">

<violation number="1" location="packages/react-email/src/cli/utils/preview/hot-reloading/resolve-path-aliases.ts:56">
P2: Using `() => true` for `fileExists` in `matchPath` can short-circuit tsconfig path fallback and return non-existent first candidates, causing valid later alias mappings to be skipped.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread packages/react-email/src/cli/utils/preview/hot-reloading/resolve-path-aliases.ts Outdated
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

0 issues found across 5 files (changes from recent commits).

Shadow auto-approve: would require human review. This PR introduces non-trivial logic changes to the dev server's dependency graph and file-watching mechanism, including AST traversal for dynamic imports.

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

0 issues found across 5 files (changes from recent commits).

Shadow auto-approve: would require human review. This PR modifies core dependency graph resolution and hot-reloading logic in the CLI, which is a high-impact area that requires human validation of the AST traversal logic.

@gabrielmfern gabrielmfern changed the title fix(cli): detect dynamic imports in the dev server's dependency graph feat(react-email): hot reloading around dynamic import Apr 28, 2026
Copy link
Copy Markdown
Member

@gabrielmfern gabrielmfern left a comment

Choose a reason for hiding this comment

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

problems around code quality mostly, the idea seems good, and overall looks pretty good too

Comment thread packages/react-email/src/cli/utils/preview/hot-reloading/get-imported-modules.ts Outdated
…yDirectories and update related logic

This change improves clarity by renaming `globDependencyPaths` to `dynamicDependencyDirectories` across the codebase. The update includes adjustments in the dependency graph creation and related tests to reflect this new naming convention, enhancing the understanding of dynamic imports in the context of the project.
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

0 issues found across 6 files (changes from recent commits).

Requires human review: This PR introduces significant logic changes to the dev server's dependency graph and hot-reloading mechanism, including AST traversal for dynamic imports and manual watcher management.

@actuallyzefe
Copy link
Copy Markdown
Contributor Author

problems around code quality mostly, the idea seems good, and overall looks pretty good too

Hey, thanks for the reviews. I think i resolved the comments.
Appreciate it if you could review when you have time.

@actuallyzefe
Copy link
Copy Markdown
Contributor Author

problems around code quality mostly, the idea seems good, and overall looks pretty good too

Hey, thanks for the reviews. I think i resolved the comments.
Appreciate it if you could review when you have time.

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.

email dev not watching messages files, thus no re-rendering happens on file content change

2 participants