class Uglifier

A wrapper around the UglifyJS interface

Constants

DEFAULTS

Default options for compilation

Error

Error class for compilation errors.

HarmonySourcePath

UglifyJS with Harmony source path

LEGACY_OPTIONS
MANGLE_PROPERTIES_DEFAULTS
SOURCE_MAP_DEFAULTS
SourceMapPath

Source Map path

SourcePath

UglifyJS source path

UglifyJSWrapperPath

UglifyJS wrapper path

VERSION

Current version of Uglifier.

Public Class Methods

compile(source, options = {}) click to toggle source

Minifies JavaScript code using implicit context.

@param source [IO, String] valid JS source code. @param options [Hash] optional overrides to Uglifier::DEFAULTS @return [String] minified code.

# File lib/uglifier.rb, line 116
def self.compile(source, options = {})
  new(options).compile(source)
end
compile_with_map(source, options = {}) click to toggle source

Minifies JavaScript code and generates a source map using implicit context.

@param source [IO, String] valid JS source code. @param options [Hash] optional overrides to Uglifier::DEFAULTS @return [Array(String, String)] minified code and source map.

# File lib/uglifier.rb, line 125
def self.compile_with_map(source, options = {})
  new(options).compile_with_map(source)
end
new(options = {}) click to toggle source

Initialize new context for Uglifier with given options

@param options [Hash] optional overrides to Uglifier::DEFAULTS

# File lib/uglifier.rb, line 132
def initialize(options = {})
  (options.keys - DEFAULTS.keys - LEGACY_OPTIONS)[0..1].each do |missing|
    raise ArgumentError, "Invalid option: #{missing}"
  end
  @options = options

  source = @options[:harmony] ? source_with(HarmonySourcePath) : source_with(SourcePath)
  @context = ExecJS.compile(source)
end

Public Instance Methods

compile(source) click to toggle source

Minifies JavaScript code

@param source [IO, String] valid JS source code. @return [String] minified code.

# File lib/uglifier.rb, line 146
def compile(source)
  if @options[:source_map]
    compiled, source_map = run_uglifyjs(source, true)
    source_map_uri = Base64.strict_encode64(source_map)
    source_map_mime = "application/json;charset=utf-8;base64"
    compiled + "\n//# sourceMappingURL=data:#{source_map_mime},#{source_map_uri}"
  else
    run_uglifyjs(source, false)
  end
end
Also aliased as: compress
compile_with_map(source) click to toggle source

Minifies JavaScript code and generates a source map

@param source [IO, String] valid JS source code. @return [Array(String, String)] minified code and source map.

# File lib/uglifier.rb, line 162
def compile_with_map(source)
  run_uglifyjs(source, true)
end
compress(source)
Alias for: compile

Private Instance Methods

comment_options() click to toggle source
# File lib/uglifier.rb, line 248
def comment_options
  case comment_setting
  when :all, true
    true
  when :jsdoc
    "jsdoc"
  when :copyright
    encode_regexp(/(^!)|Copyright/i)
  when Regexp
    encode_regexp(comment_setting)
  else
    false
  end
end
comment_setting() click to toggle source
# File lib/uglifier.rb, line 263
def comment_setting
  if @options.has_key?(:output) && @options[:output].has_key?(:comments)
    @options[:output][:comments]
  elsif @options.has_key?(:comments)
    @options[:comments]
  elsif @options[:copyright] == false
    :none
  else
    DEFAULTS[:output][:comments]
  end
end
compressor_options() click to toggle source
# File lib/uglifier.rb, line 225
def compressor_options
  defaults = conditional_option(
    DEFAULTS[:compress],
    :global_defs => @options[:define] || {},
    :screw_ie8 => screw_ie8?
  )

  conditional_option(
    @options[:compress] || @options[:squeeze],
    defaults,
    { :keep_fnames => keep_fnames?(:compress) }.merge(negate_iife_block)
  )
end
conditional_option(value, defaults, overrides = {}) click to toggle source
# File lib/uglifier.rb, line 340
def conditional_option(value, defaults, overrides = {})
  if value == true || value.nil?
    defaults.merge(overrides)
  elsif value
    defaults.merge(value).merge(overrides)
  else
    false
  end
end
enclose_options() click to toggle source
# File lib/uglifier.rb, line 320
def enclose_options
  if @options[:enclose]
    @options[:enclose].map do |pair|
      pair.first + ':' + pair.last
    end
  else
    false
  end
end
encode_regexp(regexp) click to toggle source
# File lib/uglifier.rb, line 330
def encode_regexp(regexp)
  modifiers = if regexp.casefold?
                "i"
              else
                ""
              end

  [regexp.source, modifiers]
end
extract_source_mapping_url(source) click to toggle source
# File lib/uglifier.rb, line 362
def extract_source_mapping_url(source)
  comment_start = %r{(?://|/\*\s*)}
  comment_end = %r{\s*(?:\r?\n?\*/|$)?}
  source_mapping_regex = /#{comment_start}[@#]\ssourceMappingURL=\s*(\S*?)#{comment_end}/
  rest = /\s#{comment_start}[@#]\s[a-zA-Z]+=\s*(?:\S*?)#{comment_end}/
  regex = /#{source_mapping_regex}(?:#{rest})*\Z/m
  match = regex.match(source)
  match && match[1]
end
input_source_map(source, generate_map) click to toggle source
# File lib/uglifier.rb, line 372
def input_source_map(source, generate_map)
  return nil unless generate_map
  source_map_options = @options[:source_map].is_a?(Hash) ? @options[:source_map] : {}
  sanitize_map_root(source_map_options.fetch(:input_source_map) do
    url = extract_source_mapping_url(source)
    if url && url.start_with?("data:")
      Base64.strict_decode64(url.split(",", 2)[-1])
    end
  end)
rescue ArgumentError, JSON::ParserError
  nil
end
keep_fnames?(type) click to toggle source
# File lib/uglifier.rb, line 290
def keep_fnames?(type)
  if @options[:keep_fnames] || DEFAULTS[:keep_fnames]
    true
  else
    @options[type].respond_to?(:[]) && @options[type][:keep_fnames] ||
      DEFAULTS[type].respond_to?(:[]) && DEFAULTS[type][:keep_fnames]
  end
end
mangle_options() click to toggle source
# File lib/uglifier.rb, line 202
def mangle_options
  defaults = conditional_option(
    DEFAULTS[:mangle],
    :keep_fnames => keep_fnames?(:mangle)
  )

  conditional_option(
    @options.fetch(:mangle, DEFAULTS[:mangle]),
    defaults,
    :keep_fnames => keep_fnames?(:mangle)
  )
end
mangle_properties_options() click to toggle source
# File lib/uglifier.rb, line 215
def mangle_properties_options
  mangle_options = @options.fetch(:mangle_properties, DEFAULTS[:mangle_properties])
  options = conditional_option(mangle_options, MANGLE_PROPERTIES_DEFAULTS)
  if options && options[:regex]
    options.merge(:regex => encode_regexp(options[:regex]))
  else
    options
  end
end
negate_iife_block() click to toggle source

Prevent negate_iife when wrap_iife is true

# File lib/uglifier.rb, line 240
def negate_iife_block
  if output_options[:wrap_iife]
    { :negate_iife => false }
  else
    {}
  end
end
output_options() click to toggle source
# File lib/uglifier.rb, line 275
def output_options
  DEFAULTS[:output].merge(@options[:output] || {}).merge(
    :comments => comment_options,
    :screw_ie8 => screw_ie8?
  ).reject { |key, _| key == :ie_proof }
end
parse_options() click to toggle source
# File lib/uglifier.rb, line 312
def parse_options
  if @options[:source_map].respond_to?(:[])
    { :filename => @options[:source_map][:filename] }
  else
    {}
  end
end
read_source(source) click to toggle source
# File lib/uglifier.rb, line 194
def read_source(source)
  if source.respond_to?(:read)
    source.read
  else
    source.to_s
  end
end
run_uglifyjs(input, generate_map) click to toggle source

Run UglifyJS for given source code

# File lib/uglifier.rb, line 176
def run_uglifyjs(input, generate_map)
  source = read_source(input)
  input_map = input_source_map(source, generate_map)
  options = {
    :source => source,
    :output => output_options,
    :compress => compressor_options,
    :mangle => mangle_options,
    :mangle_properties => mangle_properties_options,
    :parse_options => parse_options,
    :source_map_options => source_map_options(input_map),
    :generate_map => generate_map,
    :enclose => enclose_options
  }

  @context.call("uglifier", options)
end
sanitize_map_root(map) click to toggle source
# File lib/uglifier.rb, line 350
def sanitize_map_root(map)
  if map.nil?
    nil
  elsif map.is_a? String
    sanitize_map_root(JSON.parse(map))
  elsif map["sourceRoot"] == ""
    map.merge("sourceRoot" => nil)
  else
    map
  end
end
screw_ie8?() click to toggle source
# File lib/uglifier.rb, line 282
def screw_ie8?
  if (@options[:output] || {}).has_key?(:ie_proof)
    !@options[:output][:ie_proof]
  else
    @options.fetch(:screw_ie8, DEFAULTS[:screw_ie8])
  end
end
source_map_options(input_map) click to toggle source
# File lib/uglifier.rb, line 299
def source_map_options(input_map)
  options = conditional_option(@options[:source_map], SOURCE_MAP_DEFAULTS) || SOURCE_MAP_DEFAULTS

  {
    :file => options[:output_filename],
    :root => options.fetch(:root) { input_map ? input_map["sourceRoot"] : nil },
    :orig => input_map,
    :map_url => options[:map_url],
    :url => options[:url],
    :sources_content => options[:sources_content]
  }
end
source_with(path) click to toggle source
# File lib/uglifier.rb, line 168
def source_with(path)
  [SourceMapPath, path,
   UglifyJSWrapperPath].map do |file|
    File.open(file, "r:UTF-8", &:read)
  end.join("\n")
end