From a82687f13a67fc051ec9de7f7d0a86625bde4eab Mon Sep 17 00:00:00 2001 From: Shaoshing Date: Tue, 4 Jun 2013 15:10:32 +0800 Subject: [PATCH 1/7] Support SASS sourcemap. --- cmd/bundle_test.go | 2 +- handler.go | 12 ++++++++++++ handler_test.go | 6 ++++-- interpreter/bridge.go | 16 +++++++++++++--- interpreter/bridge_test.go | 3 +++ interpreter/interpreter.rb | 33 +++++++++++++++++++++++---------- 6 files changed, 56 insertions(+), 16 deletions(-) diff --git a/cmd/bundle_test.go b/cmd/bundle_test.go index 2362a7a..bd36e40 100644 --- a/cmd/bundle_test.go +++ b/cmd/bundle_test.go @@ -16,7 +16,7 @@ func assertEqual(path, content string) { if err != nil { panic(err) } - assert.Equal(content, string(c)) + assert.Contain(content, string(c)) } func TestCommand(t *testing.T) { diff --git a/handler.go b/handler.go index a51a958..83eb56a 100644 --- a/handler.go +++ b/handler.go @@ -1,6 +1,7 @@ package train import ( + "github.com/shaoshing/train/interpreter" "io" "log" "net/http" @@ -18,6 +19,7 @@ func servePublicAssets(w http.ResponseWriter, r *http.Request) { var contentTypes = map[string]string{ ".js": "application/javascript", ".css": "text/css", + ".map": "text/plain", } func serveAssets(w http.ResponseWriter, r *http.Request) { @@ -40,6 +42,16 @@ func serveAssets(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", contentTypes[ext]) io.Copy(w, strings.NewReader(content)) } + case ".map": + filePath := strings.Replace(url, "/", "", 1) + sourcemap, err := interpreter.Compile(filePath) + if err != nil { + io.Copy(w, strings.NewReader(err.Error())) + log.Printf("Failed to compile sourcemap\nGET %s\n-----------------------\n%s\n", url, err.Error()) + } else { + w.Header().Set("Content-Type", contentTypes[ext]) + io.Copy(w, strings.NewReader(sourcemap)) + } default: (*assetServer).ServeHTTP(w, r) } diff --git a/handler_test.go b/handler_test.go index db09b8a..2417f51 100644 --- a/handler_test.go +++ b/handler_test.go @@ -56,6 +56,8 @@ h2 { color: green; } `, "text/css") + assertAsset("/assets/stylesheets/app.sass.map", `"file": "assets/stylesheets/app.css"`, "text/plain") + assertAsset("/assets/stylesheets/app2.css", `h2 { color: green; } @@ -108,8 +110,8 @@ func get(url string) (body, contentType string, status int) { func assertAsset(url, expectedBody, expectedContentType string) { body, contentType, _ := get(url) - assert.Equal(expectedBody, body) - assert.Equal(true, strings.Index(contentType, expectedContentType) != -1) + assert.Contain(expectedBody, body) + assert.True(strings.Index(contentType, expectedContentType) != -1) } func assert404(url string) { diff --git a/interpreter/bridge.go b/interpreter/bridge.go index 5018d48..8c6e7c0 100644 --- a/interpreter/bridge.go +++ b/interpreter/bridge.go @@ -41,7 +41,17 @@ func Compile(filePath string) (result string, err error) { if e != nil { panic(err) } - result, err = interpreter.Render(strings.Replace(fileExt, ".", "", 1), content) + result, err = interpreter.Render(strings.Replace(fileExt, ".", "", 1), content, filePath) + case ".map": + filePath = strings.Replace(filePath, ".map", "", 1) + fileExt := path.Ext(filePath) + content, e := ioutil.ReadFile(filePath) + if e != nil { + panic(err) + } + result, err = interpreter.Render(strings.Replace(fileExt, ".", "", 1)+"_source_map", content, filePath) + wd, _ := os.Getwd() + result = strings.Replace(result, "../.."+wd, "", -1) default: err = errors.New("Unsupported format (" + filePath + "). Valid formats are: sass.") } @@ -49,7 +59,7 @@ func Compile(filePath string) (result string, err error) { return } -func (this *Interpreter) Render(format string, content []byte) (result string, err error) { +func (this *Interpreter) Render(format string, content []byte, filePath string) (result string, err error) { this.Lock() defer this.Unlock() @@ -62,7 +72,7 @@ func (this *Interpreter) Render(format string, content []byte) (result string, e option := getOption() - conn.Write([]byte(format + "<<" + option + "<<" + string(content))) + conn.Write([]byte(format + "<<" + option + "<<" + string(content) + "<<" + filePath)) var data bytes.Buffer data.ReadFrom(conn) conn.Close() diff --git a/interpreter/bridge_test.go b/interpreter/bridge_test.go index fd7809b..c5d3499 100644 --- a/interpreter/bridge_test.go +++ b/interpreter/bridge_test.go @@ -38,6 +38,9 @@ func TestSass(t *testing.T) { Config.SASS.LineNumbers = true css, e = Compile("assets/stylesheets/app.sass") assert.Contain("line 1", css) + + css, e = Compile("assets/stylesheets/app.sass.map") + assert.Contain(`"file": "assets/stylesheets/app.css"`, css) } func TestCoffee(t *testing.T) { diff --git a/interpreter/interpreter.rb b/interpreter/interpreter.rb index bb687c6..d230469 100644 --- a/interpreter/interpreter.rb +++ b/interpreter/interpreter.rb @@ -10,10 +10,10 @@ def self.serve server = listen loop do client = server.accept - format, option, content = read_all(client) + format, option, content, file_path = read_all(client) begin - result = self.send("render_#{format}", content, option) + result = self.send("render_#{format}", content, option, file_path) client.write "success<<#{result}" rescue Exception => e puts e @@ -71,15 +71,19 @@ def self.read_all client data.split("<<") end - def self.render_sass content, option - _render_sass(content, :sass, option) + def self.render_sass content, option, file_path + _render_sass(content, :sass, option, file_path) end - def self.render_scss content, option - _render_sass(content, :scss, option) + def self.render_scss content, option, file_path + _render_sass(content, :scss, option, file_path) end - def self._render_sass content, syntax, option + def self.render_sass_source_map content, option, file_path + _render_sass(content, :scss, "source_map", file_path) + end + + def self._render_sass content, syntax, option, file_path require "sass" options = { @@ -89,12 +93,21 @@ def self._render_sass content, syntax, option options[:debug_info] = true if option == "debug_info" options[:line_numbers] = true if option == "line_numbers" - + options[:filename] = file_path engine = Sass::Engine.new(content, options) - engine.render + + source_map_uri = "/" + file_path + ".map" + css_uri = file_path.sub(/\.(scss|sass)/, ".css") + results = engine.render_with_sourcemap(source_map_uri) + + if option == "source_map" + results[1].to_json(:css_uri => css_uri, :sourcemap_path => source_map_uri) + else + results[0] + end end - def self.render_coffee content, option + def self.render_coffee content, option, file_path require "coffee-script" CoffeeScript.compile content end From 17713abed9b36f8cd775acd45c6048e65baf4b85 Mon Sep 17 00:00:00 2001 From: Shaoshing Date: Tue, 4 Jun 2013 15:15:47 +0800 Subject: [PATCH 2/7] Cache SASS source map to improve performance. --- interpreter/interpreter.rb | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/interpreter/interpreter.rb b/interpreter/interpreter.rb index d230469..bd241e7 100644 --- a/interpreter/interpreter.rb +++ b/interpreter/interpreter.rb @@ -98,13 +98,16 @@ def self._render_sass content, syntax, option, file_path source_map_uri = "/" + file_path + ".map" css_uri = file_path.sub(/\.(scss|sass)/, ".css") + + @source_map ||= {} + return @source_map[css_uri] if option == "source_map" && @source_map[css_uri] + results = engine.render_with_sourcemap(source_map_uri) + css = results[0] + source_map = results[1].to_json(:css_uri => css_uri, :sourcemap_path => source_map_uri) - if option == "source_map" - results[1].to_json(:css_uri => css_uri, :sourcemap_path => source_map_uri) - else - results[0] - end + @source_map[css_uri] = source_map + option == "source_map" ? @source_map[css_uri] : css end def self.render_coffee content, option, file_path From 8cf8da1ae2087250945070993c5b20b9c06d3c30 Mon Sep 17 00:00:00 2001 From: Shaoshing Date: Tue, 4 Jun 2013 15:18:12 +0800 Subject: [PATCH 3/7] Make Travis use pre-released SASS. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b8824c4..d7b4e84 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,7 @@ install: - go get github.com/shaoshing/gotest - go get github.com/shaoshing/train - go get github.com/shaoshing/train/interpreter - - gem in sass + - gem in sass --pre - gem in coffee-script script: ./test_all.sh From 6b479bb6c7375f486487ee1d70b0051c7bdf8b8f Mon Sep 17 00:00:00 2001 From: Shaoshing Date: Tue, 4 Jun 2013 15:50:10 +0800 Subject: [PATCH 4/7] Try to fix Travis. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index d7b4e84..52b0c33 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,4 +8,5 @@ install: - gem in sass --pre - gem in coffee-script script: + cd $GOPATH/src/github.com/shaoshing/train ./test_all.sh From d83243992c7c246ab61b4d8a795544ed63eb22df Mon Sep 17 00:00:00 2001 From: Shaoshing Date: Sat, 8 Jun 2013 15:08:55 +0800 Subject: [PATCH 5/7] Update the diagnose command to detect for support of sourcemap. --- cmd/diagnose.go | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/cmd/diagnose.go b/cmd/diagnose.go index 7a9417d..4b7a5ed 100644 --- a/cmd/diagnose.go +++ b/cmd/diagnose.go @@ -11,7 +11,7 @@ import ( func diagnose() bool { var err error - fmt.Println("== Diagnosing\n") + fmt.Println("== Diagnosing") var rubyVersion string rubyVersion, err = bash(`ruby -e "puts RUBY_VERSION"`) @@ -34,15 +34,19 @@ func diagnose() bool { _, err = bash("gem which sass") if err != nil { fmt.Println("-- SASS is disabled because the required gem is not found.") - fmt.Println(" (install it if you wish to use SASS: gem install sass)\n") + fmt.Println(" (install it if you wish to use SASS: gem install sass)") allGood = false } else { _, err = interpreter.Compile(assetsPath + "/stylesheets/font.sass") if err != nil { fmt.Println("-- SASS is disabled because error raised while compiling. Error:") fmt.Printf("%s\n", err.Error()) - fmt.Println("(this might related to your Ruby Environment; try re-installing Ruby)\n") + fmt.Println("(this might related to your Ruby Environment; try re-installing Ruby)") allGood = false + } else { + sassVersion, _ := bash(`ruby -e "require 'sass'; puts Sass::VERSION"`) + supportSourceMap, _ := bash(`ruby -e 'require "sass"; e = Sass::Engine.new ""; puts(e.respond_to?(:render_with_sourcemap) ? "yes" : "no")'`) + fmt.Printf("-- SASS [supported] version: %s, sourcemap: %s\n", strings.Trim(sassVersion, "\n"), strings.Trim(supportSourceMap, "\n")) } } @@ -56,8 +60,11 @@ func diagnose() bool { if err != nil { fmt.Println("-- CoffeeScript is disabled because error raised while compiling. Error: ") fmt.Printf("%s\n", err.Error()) - fmt.Println("(this might related to your Ruby Environment; try re-installing Ruby)\n") + fmt.Println("(this might related to your Ruby Environment; try re-installing Ruby)") allGood = false + } else { + coffeeVersion, _ := bash(`ruby -e "require 'coffee-script'; puts CoffeeScript.version"`) + fmt.Printf("-- Coffee [supported] version: %s\n", strings.Trim(coffeeVersion, "\n")) } } From c7fe1bd632e35d7871e526462715073c81f290f3 Mon Sep 17 00:00:00 2001 From: Shaoshing Date: Sat, 8 Jun 2013 15:18:56 +0800 Subject: [PATCH 6/7] Make asset interpreter detect for support of sourcemap. --- interpreter/interpreter.rb | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/interpreter/interpreter.rb b/interpreter/interpreter.rb index bd241e7..26b8b55 100644 --- a/interpreter/interpreter.rb +++ b/interpreter/interpreter.rb @@ -96,18 +96,25 @@ def self._render_sass content, syntax, option, file_path options[:filename] = file_path engine = Sass::Engine.new(content, options) - source_map_uri = "/" + file_path + ".map" css_uri = file_path.sub(/\.(scss|sass)/, ".css") - @source_map ||= {} return @source_map[css_uri] if option == "source_map" && @source_map[css_uri] - results = engine.render_with_sourcemap(source_map_uri) - css = results[0] - source_map = results[1].to_json(:css_uri => css_uri, :sourcemap_path => source_map_uri) + if engine.respond_to?(:render_with_sourcemap) + source_map_uri = "/" + file_path + ".map" + results = engine.render_with_sourcemap(source_map_uri) + css = results[0] + source_map = results[1].to_json(:css_uri => css_uri, :sourcemap_path => source_map_uri) + + @source_map[css_uri] = source_map + option == "source_map" ? @source_map[css_uri] : css + else + if option == "source_map" + raise "Please install sass pre-released SASS version (gem in sass --pre) to get support of sourcemap" + end - @source_map[css_uri] = source_map - option == "source_map" ? @source_map[css_uri] : css + engine.render + end end def self.render_coffee content, option, file_path From ed4d4f7e1415c8d2eb611a243dc7dcde9b37a396 Mon Sep 17 00:00:00 2001 From: Shaoshing Date: Sat, 8 Jun 2013 15:50:13 +0800 Subject: [PATCH 7/7] Fix travis project path. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 52b0c33..472a3a7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,5 +8,5 @@ install: - gem in sass --pre - gem in coffee-script script: - cd $GOPATH/src/github.com/shaoshing/train + cd $HOME/gopath/src/github.com/shaoshing/train ./test_all.sh