react-email-rails 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a5aaa4184f5aef5765da5cefbb47b85c6b1619f61d8cf3d7f722c6268fe8bfdf
4
- data.tar.gz: 25d7d5100887b3976a0c258aa83df20c74080e042bea88f16767c4d7dc227055
3
+ metadata.gz: 8f53daab3807503144d3acc647a0d82c164e7c580a01a6c515131eee0f1dbfd9
4
+ data.tar.gz: 4e6529c8d47c16201f929c4c3a4486ec2d8bcf5965ac459b0c99b47bd8d88760
5
5
  SHA512:
6
- metadata.gz: 78c3a0fb601dd5d81d2705872d3d2b7de0ed7876dd02013fc9b9108f0adbabd36e39b1f9dd92128d2a9005ee514679e7fcc3b8b5983ef21374c7d5a57c913349
7
- data.tar.gz: 7a3a777b82c24144e8447c086004f61cb3c1f9d6dff596c6a309c1d103a6751eef8b78f45445794a028c9e15aea56a2930df11d933cc551d6d95f4cfda4f566e
6
+ metadata.gz: 395b4fb684b90dc42d154d2a85138ac4aad707e0789f3e5d980a5fd809049643e9255db6bdb6b255650e71288d6c4a8c2d9e81e3b01841e9649991844fe0a2f1
7
+ data.tar.gz: 0360e86df8ed619d6f6ab4294bbbd2c0659bb942d0cb906c68389b17e1541515e1ba1ae5c0f8cb6a8b2ae439d4c87d4d1b649c8e609f8f62893834351c867735
data/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.2
4
+
5
+ - Support Vite 8 hook filters while keeping production email bundles standalone by default.
6
+ - Keep development email rendering compatible with Vite's module runner.
7
+
8
+ ## 0.1.1
9
+
10
+ - Build production React Email bundles from Rails asset tasks with an isolated email-only Vite build.
11
+ - Add `react-email-rails-build` for direct production email bundle builds.
12
+
3
13
  ## 0.1.0
4
14
 
5
15
  - Initial public release.
data/CONTRIBUTING.md CHANGED
@@ -22,47 +22,18 @@ cd vite && pnpm run build
22
22
 
23
23
  The Ruby gem version in `lib/react_email_rails/version.rb` is the package version source of truth. The renderer protocol version in `lib/react_email_rails/render_protocol.rb` is also synced into the Vite package. Run `cd vite && pnpm run sync:version` after changing either one.
24
24
 
25
- ## Release Checks
26
-
27
- Before publishing, verify both packages can be built:
28
-
29
- ```sh
30
- bundle exec rake build
31
- cd vite && pnpm pack --dry-run
32
- ```
33
-
34
25
  ## Publishing
35
26
 
36
27
  Releases are tag-driven. Pushing `vX.Y.Z` to GitHub runs `.github/workflows/release.yml`, publishes the Ruby gem to RubyGems, publishes the Vite package to npm, and creates the GitHub Release with the built `.gem` and `.tgz` artifacts.
37
28
 
38
29
  ### Patch, Minor, and Major Releases
39
30
 
40
- Prepare the version bump:
31
+ Update the source-of-truth gem version in `lib/react_email_rails/version.rb`, update `CHANGELOG.md`, and commit the release prep on `main` or open and merge a release pull request. Then tag the release commit:
41
32
 
42
33
  ```sh
43
- ruby scripts/prepare_release.rb patch
44
- # or: ruby scripts/prepare_release.rb minor
45
- # or: ruby scripts/prepare_release.rb major
34
+ bin/release
46
35
  ```
47
36
 
48
- Replace the generated `CHANGELOG.md` TODO entry with the actual release notes, then run the checks:
49
-
50
- ```sh
51
- ruby scripts/check_version_sync.rb
52
- bin/test
53
- bin/lint
54
- cd vite && pnpm run ci && pnpm pack --dry-run
55
- ```
56
-
57
- Commit the release prep on `main` or open and merge a release pull request. Then tag the release commit:
58
-
59
- ```sh
60
- git switch main
61
- git pull --ff-only origin main
62
- VERSION=$(ruby -r ./lib/react_email_rails/version -e 'print ReactEmailRails::VERSION')
63
- ruby scripts/check_release_tag.rb "v$VERSION"
64
- git tag -a "v$VERSION" -m "v$VERSION"
65
- git push origin "v$VERSION"
66
- ```
37
+ `bin/release` fetches `origin/main`, validates the version and changelog, infers whether the release is patch, minor, major, or initial from the existing SemVer tags, creates the annotated `vX.Y.Z` tag on `origin/main`, and pushes it after confirmation.
67
38
 
68
39
  The GitHub release workflow handles the rest. If publishing fails before both registries are updated, do not reuse the same version unless neither registry accepted it; bump to the next patch version and release again.
data/README.md CHANGED
@@ -25,7 +25,7 @@ Building HTML emails is painfully archaic. [React Email](https://react.email) is
25
25
 
26
26
  **In development,** the gem renders components live through Vite's dev pipeline, so your emails get the same module resolution and transforms as the rest of your frontend.
27
27
 
28
- **In production,** Vite builds a server-side email bundle ahead of time. The plugin adds a dedicated `email` build environment, so your normal `vite build` emits the bundle alongside your client assets.
28
+ **In production,** Rails builds a server-side email bundle during `assets:precompile`. The bundled rake task runs an isolated email-only Vite build, using `reactEmailRails()` in your app's Vite config for discovery and options.
29
29
 
30
30
  Delivery, headers, multipart parts, previews, queues, and callbacks all stay normal Action Mailer. If rendering fails, no email is sent and `ReactEmailRails::RenderError` is raised.
31
31
 
@@ -64,6 +64,13 @@ bin/rails generate react_email_rails:install
64
64
 
65
65
  This creates `config/initializers/react_email_rails.rb`, installs missing JavaScript dependencies when it can detect your package manager, adds `reactEmailRails()` to `vite.config.*`, and creates `app/javascript/emails`.
66
66
 
67
+ The installed setup follows the normal Rails lifecycle:
68
+
69
+ - `bin/rails generate react_email_rails:email ...` creates matching mailers and React components.
70
+ - Development renders through Vite on demand.
71
+ - `bin/rails assets:precompile` builds the production email bundle automatically.
72
+ - `bin/rails react_email_rails:build` builds the bundle directly when CI or tests need it.
73
+
67
74
  ### Manual Install
68
75
 
69
76
  Install the npm package and peer dependencies manually:
@@ -384,18 +391,17 @@ Every render emits an [ActiveSupport::Notifications](https://guides.rubyonrails.
384
391
 
385
392
  ```ruby
386
393
  ActiveSupport::Notifications.subscribe("render.react-email-rails") do |event|
387
- Rails.logger.info(
388
- "[react-email-rails] rendered #{event.payload[:component]} " \
389
- "(#{event.payload[:html_bytes]} bytes) in #{event.duration.round(1)}ms"
390
- )
394
+ next if event.payload[:exception]
395
+
396
+ Rails.logger.info("[react-email-rails] Rendered #{event.payload[:component]} (Duration: #{event.duration.round}ms | Size: #{event.payload[:html_bytes]} bytes)")
391
397
  end
392
398
  ```
393
399
 
394
400
  ### Vite Configuration
395
401
 
396
- Most apps only need the `reactEmailRails()` plugin from [Quick Start](#quick-start). The options below change where components are discovered and how the bundle handles dependencies.
402
+ Most apps only need the `reactEmailRails()` plugin from [Quick Start](#quick-start). The options below change where components are discovered, how the bundle handles dependencies, and which email-only Vite transforms run in the isolated renderer.
397
403
 
398
- In development, the renderer loads the `reactEmailRails()` plugin, JSX support, and your `resolve`, `define`, and `css` config — but none of your other dev-server plugins.
404
+ In development and production, the isolated renderer loads the `reactEmailRails()` plugin, JSX support, and component-facing Vite config such as `resolve`, `define`, `css`, `json`, `assetsInclude`, `esbuild`, and `oxc` — but none of your other app plugins. Forwarded config is only for compiling and resolving email components; server, preview, dependency optimization, and build output settings stay owned by React Email Rails.
399
405
 
400
406
  #### Plugin Options
401
407
 
@@ -404,7 +410,8 @@ In development, the renderer loads the `reactEmailRails()` plugin, JSX support,
404
410
  | `emails.path` | `"app/javascript/emails"` | Directory containing email components |
405
411
  | `emails.extension` | `[".tsx", ".jsx"]` | Component extension, or an array of extensions |
406
412
  | `emails.ignore` | `["**/_*", "**/_*/**"]` | Glob patterns ignored under `emails.path` |
407
- | `standalone` | `true` | Inline SSR dependencies with `ssr.noExternal: true` |
413
+ | `standalone` | `true` | Inline production email bundle dependencies |
414
+ | `vite` | `{}` | Extra email-only Vite config for compilation and resolution |
408
415
 
409
416
  Use a custom directory:
410
417
 
@@ -426,9 +433,31 @@ reactEmailRails({
426
433
 
427
434
  Component names come from the Vite directory layout (see [Component Names](#component-names)). To map mailer actions to a different layout, override `component_path_resolver` on the Ruby side rather than renaming in the plugin, so both halves stay in sync.
428
435
 
436
+ #### Advanced: Email-Only Vite Plugins
437
+
438
+ Most apps do not need extra email plugins. If email components need a transform that is not part of Vite's default pipeline, add that transform to the email renderer:
439
+
440
+ ```ts
441
+ import mdx from "@mdx-js/rollup"
442
+ import { defineConfig } from "vite"
443
+ import { reactEmailRails } from "react-email-rails"
444
+
445
+ export default defineConfig({
446
+ plugins: [
447
+ reactEmailRails({
448
+ vite: {
449
+ plugins: [mdx()],
450
+ },
451
+ }),
452
+ ],
453
+ })
454
+ ```
455
+
456
+ These `vite` options are used by `react-email-rails-dev` and `react-email-rails-build`. They are intentionally scoped to React Email. Only `assetsInclude`, `css`, `define`, `esbuild`, `json`, `oxc`, `plugins`, and `resolve` are accepted here; output settings such as `build.outDir` and `build.rollupOptions` are ignored so the Ruby renderer can always find the generated bundle.
457
+
429
458
  #### Standalone Builds
430
459
 
431
- By default the email bundle inlines React, `@react-email/render`, and other Node dependencies. That makes the bundle larger, but it works well for Rails deploys that build assets in one stage and run without `node_modules` in the final runtime image.
460
+ By default the production email bundle inlines React, `@react-email/render`, and other Node dependencies. That makes the bundle larger, but it works well for Rails deploys that build assets in one stage and run without `node_modules` in the final runtime image. Development previews keep dependencies external for Vite's module runner, even when `standalone` is enabled.
432
461
 
433
462
  Set `standalone: false` when your runtime already ships `node_modules` and you prefer a smaller SSR-style bundle:
434
463
 
@@ -442,23 +471,29 @@ Externalized bundles are smaller and may build faster, but the renderer needs th
442
471
 
443
472
  ## Deployment
444
473
 
445
- For a standard Rails + Vite deploy, there is nothing extra to configure. Keep running your normal asset build and the email bundle is emitted alongside your client assets.
474
+ For production deploys, run the normal Rails asset task:
446
475
 
447
- ### Standard Vite Builds
476
+ ```sh
477
+ bin/rails assets:precompile
478
+ ```
448
479
 
449
- The plugin registers a dedicated `email` [build environment](https://vite.dev/guide/api-environment), so a normal `vite build` writes `tmp/react-email-rails/emails.js`, which the bundled production renderer runs with Node. With [rails_vite](https://github.com/skryukov/rails_vite/), this already happens during `assets:precompile`.
480
+ The `react_email_rails:build` task is hooked into `assets:precompile` automatically. It loads your Vite config to find `reactEmailRails()` and its options, then writes `tmp/react-email-rails/emails.js` with the isolated React Email pipeline.
450
481
 
451
- The bundle is required, not an optimization. If it's missing, renders raise `ReactEmailRails::RenderError` and no mail is sent. Make sure `vite build` runs anywhere that renders mail, the same as for the rest of your assets.
482
+ You can run it directly when needed:
452
483
 
453
- The Ruby gem and npm package must stay on the same version. The renderer includes a small protocol/version handshake, so mismatched installs fail with an actionable `ReactEmailRails::RenderError` instead of silently returning malformed output.
484
+ ```sh
485
+ bin/rails react_email_rails:build
486
+ ```
487
+
488
+ Production rendering runs that bundle with Node. Set `SKIP_REACT_EMAIL_RAILS_BUILD=1` to skip the automatic asset hook. Directly running `bin/rails react_email_rails:build` always attempts the build.
489
+
490
+ The npm package, Vite, React, and `@react-email/render` must be available when Rails runs `assets:precompile`. This is the same stage where Rails apps normally install JavaScript dependencies and build frontend assets.
454
491
 
455
- ### Custom Vite Builds
492
+ The bundle is required, not an optimization. If it's missing, renders raise `ReactEmailRails::RenderError` and no mail is sent.
456
493
 
457
- To emit the bundle without a dedicated command, the plugin opts your project into Vite's [whole-app build](https://vite.dev/guide/api-environment):
494
+ The Ruby gem and npm package must stay on the same version. The renderer includes a small protocol/version handshake, so mismatched installs fail with an actionable `ReactEmailRails::RenderError` instead of silently returning malformed output.
458
495
 
459
- - A plain `vite build` builds every configured environment in one pass. For a standard client-only app, that's just your client assets plus the `email` bundle.
460
- - If you've defined other Vite environments, such as a custom `ssr` build, they build in the same pass too.
461
- - If your Vite config defines a custom `builder.buildApp`, make sure it builds `builder.environments.email` alongside your other environments. Custom builders replace Vite's default whole-app build orchestration.
496
+ The build command preserves `emails.path`, `emails.extension`, `emails.ignore`, `standalone`, and email-only `vite` options.
462
497
 
463
498
  ### Runtime Dependencies
464
499
 
@@ -470,8 +505,8 @@ Boot verification is disabled by default. If you want the app to check the rende
470
505
 
471
506
  ```ruby
472
507
  ReactEmailRails.configure do |config|
473
- config.verify_render_on_boot = -> { Rails.env.production? && Sidekiq.server? }
474
508
  config.render_mode = :persistent if Rails.env.production? && Sidekiq.server?
509
+ config.verify_render_on_boot = -> { Rails.env.production? && Sidekiq.server? }
475
510
  end
476
511
  ```
477
512
 
@@ -1,5 +1,6 @@
1
1
  class ReactEmailRails::Configuration
2
2
  BUNDLE_PATH = "tmp/react-email-rails/emails.js"
3
+ BUILD_BIN = "node_modules/.bin/react-email-rails-build"
3
4
  DEV_RENDER_BIN = "node_modules/.bin/react-email-rails-dev"
4
5
 
5
6
  DEFAULT_RENDER_TIMEOUT = 10
@@ -5,6 +5,8 @@ class ReactEmailRails::Railtie < Rails::Railtie
5
5
  end
6
6
  end
7
7
 
8
+ rake_tasks { load(File.expand_path("../tasks/react_email_rails/build.rake", __dir__)) }
9
+
8
10
  config.after_initialize do
9
11
  if ReactEmailRails.configuration.verify_render_on_boot? && !ReactEmailRails.healthy?
10
12
  Rails.logger.error(
@@ -82,7 +82,7 @@ class ReactEmailRails::RenderModes::Subprocess
82
82
  return unless command_path == "node" && bundle_path.end_with?(ReactEmailRails::Configuration::BUNDLE_PATH)
83
83
  return if File.file?(bundle_path)
84
84
 
85
- raise(render_error("email bundle not found at #{bundle_path.inspect}; run vite build before rendering React emails"))
85
+ raise(render_error("email bundle not found at #{bundle_path.inspect}; run react-email-rails-build before rendering React emails"))
86
86
  end
87
87
 
88
88
  def validate_response!(body)
@@ -0,0 +1,32 @@
1
+ require("fileutils")
2
+
3
+ module ReactEmailRails::Tasks
4
+ class << self
5
+ def build
6
+ command = build_command
7
+ raise("react-email-rails build command not found at #{command.inspect}; run JavaScript package install first") unless File.exist?(command)
8
+
9
+ system(command, exception: true, chdir: Rails.root.to_s)
10
+ raise("react-email-rails build completed, but the email bundle was not found at #{bundle_path.inspect}") unless File.file?(bundle_path)
11
+ end
12
+
13
+ def clobber
14
+ FileUtils.rm_rf(Rails.root.join(File.dirname(ReactEmailRails::Configuration::BUNDLE_PATH)))
15
+ end
16
+
17
+ private
18
+
19
+ def build_command
20
+ candidates = [
21
+ ReactEmailRails::Configuration::BUILD_BIN,
22
+ "#{ReactEmailRails::Configuration::BUILD_BIN}.cmd",
23
+ ]
24
+ candidates.map { |path| Rails.root.join(path).to_s }.find { |path| File.exist?(path) } ||
25
+ Rails.root.join(ReactEmailRails::Configuration::BUILD_BIN).to_s
26
+ end
27
+
28
+ def bundle_path
29
+ Rails.root.join(ReactEmailRails::Configuration::BUNDLE_PATH).to_s
30
+ end
31
+ end
32
+ end
@@ -1,3 +1,3 @@
1
1
  module ReactEmailRails
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.2"
3
3
  end
@@ -22,6 +22,7 @@ require_relative("react_email_rails/render_modes/persistent")
22
22
  require_relative("react_email_rails/render_modes/persistent/server")
23
23
  require_relative("react_email_rails/render_modes/persistent/command_runner")
24
24
  require_relative("react_email_rails/configuration")
25
+ require_relative("react_email_rails/tasks")
25
26
  require_relative("react_email_rails/props_resolver")
26
27
  require_relative("react_email_rails/railtie")
27
28
 
@@ -0,0 +1,23 @@
1
+ namespace(:react_email_rails) do
2
+ desc("Build the React Email Rails production bundle")
3
+ task(build: :environment) { ReactEmailRails::Tasks.build }
4
+
5
+ desc("Remove the React Email Rails production bundle")
6
+ task(clobber: :environment) { ReactEmailRails::Tasks.clobber }
7
+ end
8
+
9
+ unless ENV["SKIP_REACT_EMAIL_RAILS_BUILD"]
10
+ if Rake::Task.task_defined?("assets:precompile")
11
+ Rake::Task["assets:precompile"].enhance(["react_email_rails:build"])
12
+ else
13
+ desc("Compile assets")
14
+ Rake::Task.define_task("assets:precompile" => "react_email_rails:build")
15
+ end
16
+
17
+ if Rake::Task.task_defined?("assets:clobber")
18
+ Rake::Task["assets:clobber"].enhance(["react_email_rails:clobber"])
19
+ else
20
+ desc("Remove compiled assets")
21
+ Rake::Task.define_task("assets:clobber" => "react_email_rails:clobber")
22
+ end
23
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: react-email-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Supertape
@@ -163,7 +163,9 @@ files:
163
163
  - lib/react_email_rails/render_modes/subprocess/command_runner.rb
164
164
  - lib/react_email_rails/render_protocol.rb
165
165
  - lib/react_email_rails/rendered_email.rb
166
+ - lib/react_email_rails/tasks.rb
166
167
  - lib/react_email_rails/version.rb
168
+ - lib/tasks/react_email_rails/build.rake
167
169
  homepage: https://github.com/heysupertape/react-email-rails
168
170
  licenses:
169
171
  - MIT