-
Notifications
You must be signed in to change notification settings - Fork 174
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Engine server hook #347
Engine server hook #347
Changes from all commits
f77a0ce
534a840
355ed62
eed5343
7265220
b4879aa
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,9 @@ | |
|
||
module Tailwindcss | ||
class Engine < ::Rails::Engine | ||
config.tailwindcss = ActiveSupport::OrderedOptions.new | ||
config.tailwindcss.server_process = false # Rails.env.development? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If (or when) you decide to make "server process" the default for all:
|
||
|
||
initializer "tailwindcss.assets" do | ||
Rails.application.config.assets.precompile += %w( inter-font.css ) | ||
end | ||
|
@@ -13,5 +16,9 @@ class Engine < ::Rails::Engine | |
config.app_generators do |g| | ||
g.template_engine :tailwindcss | ||
end | ||
|
||
server do | ||
flavorjones marked this conversation as resolved.
Show resolved
Hide resolved
|
||
ServerProcess.start if config.tailwindcss.server_process | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
module Tailwindcss | ||
class ServerProcess | ||
attr_reader :server, :pid | ||
|
||
def self.start | ||
new.start | ||
end | ||
|
||
def initialize | ||
@server = Server.new(self) | ||
end | ||
|
||
def start | ||
@pid = existing_process || start_process | ||
server.monitor_process | ||
server.exit_hook | ||
end | ||
|
||
def stop | ||
return if dead? | ||
|
||
Process.kill(:INT, pid) | ||
Process.wait(pid) | ||
rescue Errno::ECHILD, Errno::ESRCH | ||
end | ||
|
||
def dead? | ||
Process.wait(pid, Process::WNOHANG) | ||
false | ||
rescue Errno::ECHILD, Errno::ESRCH | ||
true | ||
end | ||
|
||
private | ||
|
||
def existing_process | ||
if (pid = Pidfile.pid) | ||
begin | ||
Process.kill 0, pid | ||
pid | ||
rescue Errno::ESRCH | ||
# Process does not exist | ||
rescue Errno::EPERM | ||
# Ignore process owned by another user | ||
end | ||
end | ||
end | ||
|
||
def start_process | ||
pid = fork do | ||
Pidfile.write | ||
monitor_server | ||
exit_hook | ||
# Using IO.popen(command, 'r+') will avoid watch_command read from $stdin. | ||
# If we use system(*command) instead, IRB and Debug can't read from $stdin | ||
# correctly bacause some keystrokes will be taken by watch_command. | ||
IO.popen(Commands.watch_command, 'r+') do |io| | ||
IO.copy_stream(io, $stdout) | ||
end | ||
ensure | ||
Pidfile.delete | ||
end | ||
Process.detach pid | ||
pid | ||
end | ||
|
||
def monitor_server | ||
Thread.new do | ||
loop do | ||
if server.dead? | ||
puts "Tailwind detected server has gone away" | ||
exit | ||
end | ||
sleep 2 | ||
end | ||
end | ||
end | ||
|
||
def exit_hook | ||
at_exit do | ||
puts "Stopping tailwind..." | ||
server.stop | ||
end | ||
end | ||
|
||
module Pidfile | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pidfile is a solution to a problem described here: #347 (comment) |
||
def self.path | ||
Rails.root.join("tmp", "pids", "tailwindcss.txt") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. New rails app already have There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is similar to turning the cache on or off, touch restart.txt, etc. |
||
end | ||
|
||
def self.read | ||
File.read(path, mode: "rb:UTF-8") | ||
rescue Errno::ENOENT | ||
# File does not exist | ||
end | ||
|
||
def self.write | ||
File.write(path, Process.pid, mode: "wb:UTF-8") | ||
end | ||
|
||
def self.delete | ||
File.exist?(path) && File.delete(path) | ||
end | ||
|
||
def self.pid | ||
Integer(read) | ||
rescue ArgumentError, TypeError | ||
# Invalid content | ||
delete | ||
end | ||
end | ||
|
||
class Server | ||
attr_reader :process, :pid | ||
|
||
def initialize(process) | ||
@process = process | ||
@pid = Process.pid | ||
end | ||
|
||
def monitor_process | ||
Thread.new do | ||
loop do | ||
if process.dead? | ||
puts "Detected tailwind has gone away, stopping server..." | ||
exit | ||
end | ||
sleep 2 | ||
end | ||
end | ||
end | ||
|
||
def exit_hook | ||
at_exit do | ||
process.stop | ||
end | ||
end | ||
|
||
def dead? | ||
Process.ppid != pid | ||
end | ||
|
||
def stop | ||
Process.kill(:INT, pid) | ||
rescue Errno::ECHILD, Errno::ESRCH | ||
end | ||
end | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will enable the "server process" only for new installs.
I opted for this solution over creating an initializer file because:
config/environments/*
, not initializers