class BrowserifyRails::BrowserifyProcessor
Attributes
Public Class Methods
# File lib/browserify-rails/browserify_processor.rb, line 15 def self.call(input) instance.call(input) end
# File lib/browserify-rails/browserify_processor.rb, line 11 def self.instance @instance ||= new end
# File lib/browserify-rails/browserify_processor.rb, line 19 def initialize self.config = Rails.application.config.browserify_rails end
Public Instance Methods
# File lib/browserify-rails/browserify_processor.rb, line 23 def call(input) self.file = input[:filename] return input[:data] unless in_path? self.data = input[:data] # Clear the cached dependencies because the source file changes @dependencies = nil ensure_tmp_dir_exists! ensure_commands_exist! # If there's nothing to do, we just return the data we received return data unless should_browserify? dependencies = Set.new(input[:metadata][:dependencies]) # Signal dependencies to sprockets to ensure we track changes evaluate_dependencies(input[:environment].paths).each do |path| resolved = input[:environment].resolve(path) if resolved && resolved.is_a?(Array) dependencies += resolved[1] elsif resolved dependencies << "file-digest://#{Addressable::URI.escape resolved}" elsif config.evaluate_node_modules dependencies << "file-digest://#{Addressable::URI.escape path}" end end new_data = run_browserify(input[:name]) { data: new_data, dependencies: dependencies } end
Private Instance Methods
# File lib/browserify-rails/browserify_processor.rb, line 124 def asset_paths @asset_paths ||= Rails.application.config.assets.paths.collect { |p| p.to_s }.join(":") || "" end
Is this file already packaged for the browser?
# File lib/browserify-rails/browserify_processor.rb, line 112 def browserified? data.to_s.include?("define.amd") || data.to_s.include?("_dereq_") end
# File lib/browserify-rails/browserify_processor.rb, line 62 def browserify_cmd @browserify_cmd ||= File.join(config.node_bin, "browserify").freeze end
# File lib/browserify-rails/browserify_processor.rb, line 272 def browserify_command(force=nil) rails_path(uses_browserifyinc(force) ? browserifyinc_cmd : browserify_cmd) end
# File lib/browserify-rails/browserify_processor.rb, line 66 def browserifyinc_cmd @browserifyinc_cmd ||= File.join(config.node_bin, "browserifyinc").freeze end
Is this a commonjs module?
Be here as strict as possible, so that non-commonjs files are not preprocessed.
# File lib/browserify-rails/browserify_processor.rb, line 120 def commonjs_module? data.to_s.include?("module.exports") || data.present? && data.to_s.match(/(require\(.*\)|import)/) && dependencies.length > 0 end
@return [<String>] Paths of files, that this file depends on
# File lib/browserify-rails/browserify_processor.rb, line 140 def dependencies @dependencies ||= begin # We forcefully run browserify (avoiding browserifyinc) with the --list # option to get a list of files. list = run_browserify(nil, "--list") cleaned_paths = list.lines.map do |path| # clean and normalize paths for all operating systems Pathname.new(path.strip).cleanpath.to_s end cleaned_paths.select do |path| # Filter the temp file, where browserify caches the input stream File.exist?(path) end end end
# File lib/browserify-rails/browserify_processor.rb, line 78 def ensure_commands_exist! error = ->(cmd) { "Unable to run #{cmd}. Ensure you have installed it with npm." } # Browserify has to be installed in any case if !File.exist?(rails_path(browserify_cmd)) raise BrowserifyRails::BrowserifyError.new(error.call(browserify_cmd)) end # If the user wants to use browserifyinc, we need to ensure it's there too if config.use_browserifyinc && !File.exist?(rails_path(browserifyinc_cmd)) raise BrowserifyRails::BrowserifyError.new(error.call(browserifyinc_cmd)) end end
# File lib/browserify-rails/browserify_processor.rb, line 74 def ensure_tmp_dir_exists! FileUtils.mkdir_p(rails_path(tmp_path)) end
Environtment to run browserify in:
NODE_PATH nodejs.org/api/all.html#all_loading_from_the_global_folders but basically allows one to have multiple locations for non-relative requires to be resolved to.
NODE_ENV is set to the Rails.env. This is used by some modules to determine how to build. Example: facebook.github.io/react/downloads.html#npm
# File lib/browserify-rails/browserify_processor.rb, line 166 def env env_hash = {} env_hash["NODE_PATH"] = asset_paths unless uses_exorcist env_hash["NODE_ENV"] = config.node_env || Rails.env env_hash end
This primarily filters out required files from node modules
@return [<String>] Paths of dependencies to evaluate
# File lib/browserify-rails/browserify_processor.rb, line 131 def evaluate_dependencies(asset_paths) return dependencies if config.evaluate_node_modules dependencies.select do |path| path.start_with?(*asset_paths) end end
# File lib/browserify-rails/browserify_processor.rb, line 70 def exorcist_cmd @exorcist_cmd ||= rails_path(File.join(config.node_bin, "exorcist").freeze) end
# File lib/browserify-rails/browserify_processor.rb, line 294 def exorcist_options exorcist_options = [] root_path = config.root || File.expand_path('../..', __FILE__) exorcist_base_path = config.exorcist_base_path || root_path exorcist_options.push("-b #{exorcist_base_path}") exorcist_options.join(" ") end
# File lib/browserify-rails/browserify_processor.rb, line 96 def force_browserify? if config.force.is_a? Proc config.force.call file else config.force end end
# File lib/browserify-rails/browserify_processor.rb, line 302 def get_granular_config(logical_path) granular_config = config.granular["javascript"] granular_config && granular_config[logical_path] end
# File lib/browserify-rails/browserify_processor.rb, line 308 def granular_options(logical_path) granular_config = get_granular_config(logical_path) return nil if granular_config.blank? # We set separate options for each of the items in granular_config options = granular_config.keys.collect do |key| granular_config[key].collect { |value| "--#{key} #{value}" } end options.flatten.join(" ") if options end
Is this file in any of the configured paths?
# File lib/browserify-rails/browserify_processor.rb, line 105 def in_path? config.paths.any? do |path_spec| path_spec === file end end
# File lib/browserify-rails/browserify_processor.rb, line 284 def options options = [] options.push("-d") if config.source_map_environments.include?(Rails.env) options += options_to_array(config.commandline_options) if config.commandline_options.present? options.uniq.join(" ") end
# File lib/browserify-rails/browserify_processor.rb, line 276 def options_to_array(options) if options.respond_to? :call options.call(file) else Array(options) end end
# File lib/browserify-rails/browserify_processor.rb, line 321 def rails_path(*paths) Rails.root.join(*paths).to_s end
Run the requested version of browserify (browserify or browserifyinc) based on configuration or the use_browserifyinc parameter if present.
We are passing the data via stdin, so that earlier preprocessing steps are respected. If you had, say, an “application.js.coffee.erb”, passing the filename would fail, because browserify would read the original file with ERB tags and fail. By passing the data via stdin, we get the expected behavior of success, because everything has been compiled to plain javascript at the time this processor is called.
@raise [BrowserifyRails::BrowserifyError] if browserify does not succeed @param logical_path [String] Sprockets's logical path for the file @param extra_options [String] Options to be included in the command @param force_browserifyinc [Boolean] Causes browserifyinc to be used if true @return [String] Output of the command
# File lib/browserify-rails/browserify_processor.rb, line 188 def run_browserify(logical_path=nil, extra_options=nil, force_browserifyinc=nil) command_options = "#{options} #{extra_options} #{granular_options(logical_path)}".strip # Browserifyinc uses a special cache file. We set up the path for it if # we're going to use browserifyinc. if uses_browserifyinc(force_browserifyinc) cache_file_path = rails_path(tmp_path, "browserifyinc-cache.json") command_options << " --cachefile=#{Shellwords.escape(cache_file_path)}" end # Create a temporary file for the output. Such file is necessary when # using browserifyinc, but we use it in all instances for consistency output_file = Tempfile.new("output", rails_path(tmp_path)) command_options << " -o #{output_file.path.inspect}" # Compose the full command (using browserify or browserifyinc as necessary) command = "#{Shellwords.escape(browserify_command(force_browserifyinc))} #{command_options} -" # The directory the command will be executed from base_directory = File.dirname(file) Logger::log "Browserify: #{command}" # If we are on JRuby 1.x, capture3 does not support chdir option stdout, stderr, status = if RUBY_PLATFORM == "java" && JRUBY_VERSION =~ /^1/ Dir.chdir(base_directory) { Open3.capture3(env, command, stdin_data: data) } else Open3.capture3(env, command, stdin_data: data, chdir: base_directory) end if !status.success? raise BrowserifyRails::BrowserifyError.new("Error while running `#{command}`:\n\n#{stderr}") end # If using exorcist, pipe output from browserify command into exorcist if uses_exorcist && logical_path if stdout.present? bfy_output = stdout else bfy_output = output_file.read end sourcemap_output_file = "#{File.dirname(file)}/#{logical_path.split('/')[-1]}.map" exorcist_command = "#{Shellwords.shellescape(exorcist_cmd)} #{Shellwords.shellescape(sourcemap_output_file)} #{exorcist_options}" Logger::log "Exorcist: #{exorcist_command}" exorcist_stdout, exorcist_stderr, exorcist_status = Open3.capture3(env, exorcist_command, stdin_data: bfy_output, chdir: base_directory) if !exorcist_status.success? raise BrowserifyRails::BrowserifyError.new("Error while running `#{exorcist_command}`:\n\n#{exorcist_stderr}") end end # Read the output that was stored in the temp file output_file.open output = output_file.read # Destroy the temp file (good practice) output_file.close output_file.unlink # Some command flags (such as --list) make the output go to stdout, # ignoring -o. If this happens, we give out stdout instead. # If we're using exorcist, then we directly use its output if uses_exorcist && exorcist_stdout.present? exorcist_stdout elsif stdout.present? stdout else output end end
# File lib/browserify-rails/browserify_processor.rb, line 92 def should_browserify? force_browserify? || (in_path? && !browserified? && commonjs_module?) end
# File lib/browserify-rails/browserify_processor.rb, line 58 def tmp_path @tmp_path ||= Rails.root.join("tmp", "cache", "browserify-rails").freeze end
# File lib/browserify-rails/browserify_processor.rb, line 264 def uses_browserifyinc(force=nil) !force.nil? ? force : config.use_browserifyinc end
# File lib/browserify-rails/browserify_processor.rb, line 268 def uses_exorcist config.use_exorcist end