Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Add .compile_with_map to compile with source maps

  • Loading branch information...
commit 7a4e8cf877da2cf9f5bdd02e1c899745b62c1ccf 1 parent 2edec1c
@ConradIrwin ConradIrwin authored
View
1  Gemfile
@@ -22,4 +22,5 @@ group :development do
gem "bundler", "~> 1.0"
gem "jeweler", "~> 1.8.3"
gem "rdoc", "~> 3.11"
+ gem "source_map"
end
View
72 lib/uglifier.rb
@@ -27,7 +27,11 @@ class Uglifier
:indent_level => 4,
:indent_start => 0,
:space_colon => false
- }
+ },
+ :source_filename => nil, # The filename of the input
+ :source_root => nil, # The URL of the directory which contains :source_filename
+ :output_filename => nil, # The filename or URL where the minified output can be found
+ :input_source_map => nil, # The contents of the source map describing the input
}
SourcePath = File.expand_path("../uglify.js", __FILE__)
@@ -43,6 +47,16 @@ def self.compile(source, options = {})
self.new(options).compile(source)
end
+ # Minifies JavaScript code and generates a source map using implicit context.
+ #
+ # source should be a String or IO object containing valid JavaScript.
+ # options contain optional overrides to Uglifier::DEFAULTS
+ #
+ # Returns a pair of [minified code as String, source map as a String]
+ def self.compile_with_map(source, options = {})
+ self.new(options).compile_with_map(source)
+ end
+
# Initialize new context for Uglifier with given options
#
# options - Hash of options to override Uglifier::DEFAULTS
@@ -57,11 +71,30 @@ def initialize(options = {})
#
# Returns minified code as String
def compile(source)
+ really_compile(source, false)
+ end
+ alias_method :compress, :compile
+
+ # Minifies JavaScript code and generates a source map
+ #
+ # source should be a String or IO object containing valid JavaScript.
+ #
+ # Returns a pair of [minified code as String, source map as a String]
+ def compile_with_map(source)
+ really_compile(source, true)
+ end
+
+ private
+
+ # Minifies JavaScript code
+ #
+ # source should be a String or IO object containing valid JavaScript.
+ def really_compile(source, generate_map)
source = source.respond_to?(:read) ? source.read : source.to_s
js = <<-JS
var source = %{source};
- var ast = UglifyJS.parse(source);
+ var ast = UglifyJS.parse(source, %{parse_options});
ast.figure_out_scope();
if (%{squeeze}) {
@@ -75,7 +108,14 @@ def compile(source)
ast.mangle_names(%{mangle_options});
}
- var stream = UglifyJS.OutputStream(%{gen_code_options});
+ var gen_code_options = %{gen_code_options};
+
+ if (%{generate_map}) {
+ var source_map = UglifyJS.SourceMap(%{source_map_options});
+ gen_code_options.source_map = source_map;
+ }
+
+ var stream = UglifyJS.OutputStream(gen_code_options);
if (%{copyright}) {
var comments = ast.start.comments_before;
@@ -86,7 +126,11 @@ def compile(source)
}
ast.print(stream);
- return stream.toString() + ";";
+ if (%{generate_map}) {
+ return [stream.toString() + ";", source_map.toString()];
+ } else {
+ return stream.toString() + ";";
+ }
JS
@context.exec(js % {
@@ -94,14 +138,14 @@ def compile(source)
:compressor_options => json_encode(compressor_options),
:gen_code_options => json_encode(gen_code_options),
:mangle_options => json_encode(mangle_options),
+ :parse_options => json_encode(parse_options),
+ :source_map_options => json_encode(source_map_options),
:squeeze => squeeze?.to_s,
:mangle => mangle?.to_s,
- :copyright => copyright?.to_s
+ :copyright => copyright?.to_s,
+ :generate_map => (!!generate_map).to_s
})
end
- alias_method :compress, :compile
-
- private
def mangle?
!!@options[:mangle]
@@ -144,6 +188,18 @@ def gen_code_options
end
end
+ def source_map_options
+ {
+ :file => @options[:output_filename],
+ :root => @options[:source_root],
+ :orig => @options[:input_source_map]
+ }
+ end
+
+ def parse_options
+ {:filename => @options[:source_filename]}
+ end
+
# MultiJson API detection
if MultiJson.respond_to? :dump
def json_encode(obj)
View
86 spec/source_map_spec.rb
@@ -0,0 +1,86 @@
+# encoding: UTF-8
+require 'stringio'
+require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
+
+describe "Uglifier" do
+ it "generates source maps" do
+ source = File.open("lib/uglify.js", "r:UTF-8").read
+ minified, map = Uglifier.new.compile_with_map(source)
+ minified.length.should < source.length
+ map.length.should > 0
+ lambda {
+ JSON.parse(map)
+ }.should_not raise_error
+ end
+
+ it "generates source maps with the correct meta-data" do
+ source = <<-JS
+ function hello () {
+ function world () {
+ return 2;
+ };
+
+ return world() + world();
+ };
+ JS
+
+ minified, map = Uglifier.compile_with_map(source,
+ :source_filename => "ahoy.js",
+ :output_filename => "ahoy.min.js",
+ :source_root => "http://localhost/")
+
+ map = SourceMap.from_s(map)
+ map.file.should == "ahoy.min.js"
+ map.sources.should == ["ahoy.js"]
+ map.names.should == ["hello", "world"]
+ map.source_root.should == "http://localhost/"
+ map.mappings.first[:generated_line].should == 1
+ end
+
+ it "should skip copyright lines in source maps" do
+ source = <<-JS
+ /* @copyright Conrad Irwin */
+ function hello () {
+ function world () {
+ return 2;
+ };
+
+ return world() + world();
+ };
+ JS
+
+ minified, map = Uglifier.compile_with_map(source,
+ :source_filename => "ahoy.js",
+ :source_root => "http://localhost/")
+ map = SourceMap.from_s(map)
+ map.mappings.first[:generated_line].should == 2
+ end
+
+ it "should be able to handle an input source map" do
+ source = <<-JS
+ function hello () {
+ function world () {
+ return 2;
+ };
+
+ return world() + world();
+ };
+ JS
+
+ minified1, map1 = Uglifier.compile_with_map(source,
+ :source_filename => "ahoy.js",
+ :source_root => "http://localhost/",
+ :mangle => false)
+
+ minified2, map2 = Uglifier.compile_with_map(source,
+ :input_source_map => map1,
+ :mangle => true)
+
+ minified1.lines.to_a.length.should == 1
+
+ map = SourceMap.from_s(map2)
+ map.sources.should == ["http://localhost/ahoy.js"]
+ map.mappings.first[:source_line].should == 1
+ map.mappings.last[:source_line].should == 6
+ end
+end
View
1  spec/spec_helper.rb
@@ -1,6 +1,7 @@
# encoding: UTF-8
require 'uglifier'
require 'rspec'
+require 'source_map'
# Requires supporting files with custom matchers and macros, etc,
# in ./support/ and its subdirectories.
Please sign in to comment.
Something went wrong with that request. Please try again.