require 'fileutils'
module HtmlMockup::Release::Processors
class Requirejs < Base
def initialize(options = {})
@options = {
:build_files => {"javascripts/site.build.js" => {:dir => "javascripts"}},
:rjs => "r.js",
:node => "node"
}.update(options)
end
# @option options [Hash] :build_files An a hash of files to build (as key) and the target as a hash with either {:dir => "STRING"} or {:file => "STRING"} in the release to put it as value, each one will be built in a separate directory. (default is {"javascripts/site.build.js" => {:dir => "javascripts"}})
# @option options [String] :node The system path for node (defaults to "node" in path)
# @option options [String] :rjs The system path to the requirejs optimizer (r.js) (defaults to "../vendor/requirejs/r.js" (relative to source_path))
def call(release, options={})
@options.update(options)
begin
`#{@options[:node]} -v`
rescue Errno::ENOENT
raise RuntimeError, "Could not find node in #{@options[:node].inspect}"
end
rjs_command = rjs_check()
@options[:build_files].each do |build_file, target|
build_file = release.build_path + build_file
if target.kind_of?(Hash)
if target[:dir]
target = target[:dir]
target_type = :dir
elsif target[:file]
target = target[:file]
target_type = :file
end
else
# Old style
target_type = :dir
end
target = release.build_path + target
release.log(self, "Optimizing #{build_file}")
# Hack to create tempfile in build
t = Tempfile.new("requirejs", release.build_path)
tmp_build_dir = t.path
t.close
t.unlink
# Run r.js optimizer
if target_type == :dir
output = `#{rjs_command} -o #{build_file} dir=#{tmp_build_dir}`
else
output = `#{rjs_command} -o #{build_file} out=#{tmp_build_dir}/out.js`
end
release.debug(self, output)
# Check if r.js succeeded
unless $?.success?
raise RuntimeError, "Asset compilation with node failed.\nr.js output:\n #{output}"
end
if File.exist?(target)
release.log(self, "Removing target #{target}")
FileUtils.rm_rf(target)
end
# Move the tmp_build_dir to target
if target_type == :dir
FileUtils.mv(tmp_build_dir, target)
end
FileUtils.mv("#{tmp_build_dir}/out.js", target)
FileUtils.rm_rf(tmp_build_dir)
end
end
# Incase both a file and bin version are availble file version is taken
#
# @return rjs_command to invoke r.js optimizer with
def rjs_check(path = @options[:rjs])
rjs_command = rjs_file(path) || rjs_bin(path)
if !(rjs_command)
raise RuntimeError, "Could not find r.js optimizer in #{path.inspect} - try updating this by npm install -g requirejs"
end
rjs_command
end
protected
# Checks if the param is the r.js lib from file system
#
# @param [String] Path r.js lib may be kept to be invoked with node
# @return [String] the cli invokement string
def rjs_file(path)
if File.exist?(path)
"#{@options[:node]} #{path}"
else
false
end
end
# Checks if r.js is installed as bin
#
# @param [String] Path to r.js bin
# @return [String] the cli invokement string
def rjs_bin(path)
begin
`#{path} -v`
rescue Errno::ENOENT
false
else
"#{path}"
end
end
end
end