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 +4 -4
- data/CHANGELOG.md +10 -0
- data/CONTRIBUTING.md +3 -32
- data/README.md +55 -20
- data/lib/react_email_rails/configuration.rb +1 -0
- data/lib/react_email_rails/railtie.rb +2 -0
- data/lib/react_email_rails/render_modes/subprocess.rb +1 -1
- data/lib/react_email_rails/tasks.rb +32 -0
- data/lib/react_email_rails/version.rb +1 -1
- data/lib/react_email_rails.rb +1 -0
- data/lib/tasks/react_email_rails/build.rake +23 -0
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8f53daab3807503144d3acc647a0d82c164e7c580a01a6c515131eee0f1dbfd9
|
|
4
|
+
data.tar.gz: 4e6529c8d47c16201f929c4c3a4486ec2d8bcf5965ac459b0c99b47bd8d88760
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
-
|
|
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
|
-
|
|
44
|
-
# or: ruby scripts/prepare_release.rb minor
|
|
45
|
-
# or: ruby scripts/prepare_release.rb major
|
|
34
|
+
bin/release
|
|
46
35
|
```
|
|
47
36
|
|
|
48
|
-
|
|
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,**
|
|
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
|
-
|
|
388
|
-
|
|
389
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
474
|
+
For production deploys, run the normal Rails asset task:
|
|
446
475
|
|
|
447
|
-
|
|
476
|
+
```sh
|
|
477
|
+
bin/rails assets:precompile
|
|
478
|
+
```
|
|
448
479
|
|
|
449
|
-
The
|
|
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
|
-
|
|
482
|
+
You can run it directly when needed:
|
|
452
483
|
|
|
453
|
-
|
|
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
|
-
|
|
492
|
+
The bundle is required, not an optimization. If it's missing, renders raise `ReactEmailRails::RenderError` and no mail is sent.
|
|
456
493
|
|
|
457
|
-
|
|
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
|
-
|
|
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
|
|
|
@@ -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
|
|
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
|
data/lib/react_email_rails.rb
CHANGED
|
@@ -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.
|
|
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
|