Skip to content

Commit 56eaa12

Browse files
committed
Puma plugins to run yarn or bun
1 parent 8b20363 commit 56eaa12

File tree

3 files changed

+143
-0
lines changed

3 files changed

+143
-0
lines changed

README.md

+13
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,19 @@ Or, in Rails 7+, you can preconfigure your new application to use a specific bun
3939

4040
## FAQ
4141

42+
### Puma plugin
43+
44+
Using [Puma](https://github.com/puma/puma) in development you can now add a plugin to build and compile your javascript. Just add the following to your `puma.rb`.
45+
46+
```
47+
# config/puma.rb
48+
plugin :yarn if ENV.fetch("RAILS_ENV", "development") == "development"
49+
50+
# or if you're using Bun
51+
plugin :bun if ENV.fetch("RAILS_ENV", "development") == "development"
52+
53+
```
54+
4255
### Is there a work-around for lack of glob syntax on Windows?
4356

4457
The default build script for esbuild relies on the `app/javascript/*.*` glob pattern to compile multiple entrypoints automatically. This glob pattern is not available by default on Windows, so you need to change the build script in `package.json` to manually list the entrypoints you wish to compile.

lib/puma/plugin/bun.rb

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
require "puma/plugin"
2+
3+
Puma::Plugin.create do
4+
attr_reader :puma_pid, :bun_pid, :log_writer
5+
6+
def start(launcher)
7+
@log_writer = launcher.log_writer
8+
@puma_pid = $$
9+
@bun_pid = fork do
10+
Thread.new { monitor_puma }
11+
IO.popen("bun run build --watch", "r+") do |io|
12+
IO.copy_stream(io, $stdout)
13+
end
14+
end
15+
16+
launcher.events.on_stopped { stop_bun }
17+
18+
in_background do
19+
monitor_bun
20+
end
21+
end
22+
23+
private
24+
def stop_bun
25+
Process.waitpid(bun_pid, Process::WNOHANG)
26+
log "Stopping Bun..."
27+
Process.kill(:INT, bun_pid) if bun_pid
28+
Process.wait(bun_pid)
29+
rescue Errno::ECHILD, Errno::ESRCH
30+
end
31+
32+
def monitor_puma
33+
monitor(:puma_dead?, "Detected Puma has gone away, stopping Bun...")
34+
end
35+
36+
def monitor_bun
37+
monitor(:bun_dead?, "Detected Bun has gone away, stopping Puma...")
38+
end
39+
40+
def monitor(process_dead, message)
41+
loop do
42+
if send(process_dead)
43+
log message
44+
Process.kill(:INT, $$)
45+
break
46+
end
47+
sleep 2
48+
end
49+
end
50+
51+
def bun_dead?
52+
Process.waitpid(bun_pid, Process::WNOHANG)
53+
false
54+
rescue Errno::ECHILD, Errno::ESRCH
55+
true
56+
end
57+
58+
def puma_dead?
59+
Process.ppid != puma_pid
60+
end
61+
62+
def log(...)
63+
log_writer.log(...)
64+
end
65+
end

lib/puma/plugin/yarn.rb

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
require "puma/plugin"
2+
3+
Puma::Plugin.create do
4+
attr_reader :puma_pid, :yarn_pid, :log_writer
5+
6+
def start(launcher)
7+
@log_writer = launcher.log_writer
8+
@puma_pid = $$
9+
@yarn_pid = fork do
10+
Thread.new { monitor_puma }
11+
IO.popen("yarn build --watch", "r+") do |io|
12+
IO.copy_stream(io, $stdout)
13+
end
14+
end
15+
16+
launcher.events.on_stopped { stop_yarn }
17+
18+
in_background do
19+
monitor_yarn
20+
end
21+
end
22+
23+
private
24+
def stop_yarn
25+
Process.waitpid(yarn_pid, Process::WNOHANG)
26+
log "Stopping Yarn..."
27+
Process.kill(:INT, yarn_pid) if yarn_pid
28+
Process.wait(yarn_pid)
29+
rescue Errno::ECHILD, Errno::ESRCH
30+
end
31+
32+
def monitor_puma
33+
monitor(:puma_dead?, "Detected Puma has gone away, stopping Yarn...")
34+
end
35+
36+
def monitor_yarn
37+
monitor(:yarn_dead?, "Detected Yarn has gone away, stopping Puma...")
38+
end
39+
40+
def monitor(process_dead, message)
41+
loop do
42+
if send(process_dead)
43+
log message
44+
Process.kill(:INT, $$)
45+
break
46+
end
47+
sleep 2
48+
end
49+
end
50+
51+
def yarn_dead?
52+
Process.waitpid(yarn_pid, Process::WNOHANG)
53+
false
54+
rescue Errno::ECHILD, Errno::ESRCH
55+
true
56+
end
57+
58+
def puma_dead?
59+
Process.ppid != puma_pid
60+
end
61+
62+
def log(...)
63+
log_writer.log(...)
64+
end
65+
end

0 commit comments

Comments
 (0)