From Sass(+Compass) to libSass(+compass-mixins)

最近又要對抄筆記做不小個改動,於是打算來解決一個困擾我已久的問題: Sass/Compass 有夠慢!

http://lmgtfy.com/?q=sass+slow

舊做法:Compass + concat

其實很早以前我就已經嘗試處理過這個問題,原本所有需要 compile 的 @import 都會回歸到同一個 .scss 檔案,但由於每次在 watch 的狀態下按存檔我都要等個 10 秒左右,最後我就受不了了,於是出現了如下的結構:

sass_tree_01.png

這樣每次會生出 一堆 css(沒有前置底線的都會生成 .css 檔案),然後再透 Grunt 在這些 .css 檔生出來之後把它們 concat 起來,如此在只更改單一檔案的時候(e.g. sass/cards/new-features.scss)就不會需要同時 compile 其它的一大包東西(是說我本來以為 Sass 本身的 cache 機制進場可以解決這個問題,但上網查了一下跟親自試了一下之後覺得似乎沒有什麼幫助...)

此時的 Gruntfile.js (我是用 grunt-contrib-compass) 就生出了這兩段新的 configuration:

// in grunt.initConfig

concat: {
  css: {
    options: {
      separator: ''
    },
    src: [
      '<%= config.concatDir %>/css/*.css',
      '<%= config.concatDir %>/css/cards/*.css'
    ],
    dest: '<%= config.distDir %>/content/css/app.css'
  }
},
watch: {
  css: {
    files: ['<%= config.concatDir %>/css/{,**/}*.css'],
    tasks: ['concat:css']
  }
}

然而在碰到修改的是共用的 _ xxx.scss 或著是需要整包做一次重新 compile 就會要等有點久...

新做法:libSass + compass-mixins

  • libSass

    Sass engine 的 C/C++ port 版,運作速度非常非常之快。並且有各個 language 的 wrapper,都可以在頁面上找到。

  • compass-mixins

    脫離了 Ruby Compass 的魔掌之後仍然有 Compass 大部分的 mixin 可以用。

  • grunt-sass

    Grunt + node-sass

安裝必須品

npm install --save-dev compass-mixins
npm install --save-dev grunt-sass

修改 Gruntfile.js

// in grunt.initConfig

sass: {
  options: {
    includePaths: [
      // 把 compass-mixins 加到 sass 的 include path

      'node_modules/compass-mixins/lib'
    ]
  },
  dist: {
    options: {
      sourceComments: true
    },
    // 用 grunt 展開檔案丟給 node-sass

    // ref: http://gruntjs.com/configuring-tasks#globbing-patterns

    files: [{
      expand: true,
      cwd: '<%= config.appDir %>/sass',
      src: '{,**/}*.scss',
      dest: '<%= config.concatDir %>/css',
      ext: '.css'
    }]
  }
}

值得注意的是如果是從 Compass 轉移過來的話,原本 Compass 是自動 compile 整個設定的 Sass 資料夾內非 _ 開頭的 Sass 檔案,而 node-sass 的 compile 是以單一檔案為基礎的,因此在這邊我們需要透過 Grunt 的 globbing patterns 把原本 Compass 設定的 Sass 資料夾內的檔案展開餵給 grunt-sass。

如果你沒有這個需求,可以直接參考 grunt-sass 的 README 有最基本的一對一設定方法:

sass: {
  options: {
    sourceMap: true
  },
  dist: {
    files: {
        'main.css': 'main.scss'
    }
  }
}

馬上來試一下速度怎麼樣!

後記

其實當時要改成 Compass + concat 前我就已經有稍微調查過 node-sass,不過那時候恰恰是 Sass 迎來升上 3.3 並且 Compass 迎向 1.0 的可怕時刻,然而偏偏我就是需要 Sass 3.3 才有的功能,而 libSass 的進展畢竟還是沒有直接跟上 Sass,最後我只好作罷。

Switching from Ruby Sass to LibSass
http://www.sitepoint.com/switching-ruby-sass-libsass/

時過境遷,後來 Ruby Sass 停下來等 libSass 追上後再齊頭並進,才有了今天這麼快速又不落人後的 libSass!

Sass Compatibility
http://sass-compatibility.github.io/

果然在這個變化快速的產業,偶爾就是需要讓子彈飛一陣子。

angular-easyfb v1.3.0 released!

https://goo.gl/ky60u0

  • 把預設的 ezfb.init() 中的 version 拉到 v2.0
  • 新增 Page plugin 支援

要說今晚為什麼一事無成都是因為在忙這個

原本只是想說把人家發的 PR 處理一下,畢竟那個 PR 延宕已久,之前寫 comment 給發來的人請他改一下他遲遲沒有回應,我只好親自下海修正再 merge 了。

想不到就在 merge 的前後冒出了一個神秘印度人表示他疑似試了並不 work,render 出來的 plugin 寬度不太正常。我試了一下還真如他所說,還好我還沒 push tag 上去。

趕緊查了 Facebook 官方的 Page plugin 頁面,發現這個 plugin 搭配了一個玄妙、不同於以往的莫名奇妙功能叫作 Adaptive Width : https://developers.facebook.com/docs/plugins/page-plugin#adaptive-width

The plugin will automatically adapt to the width of its parent element on page load (min. 180px / max. 500px)

這敘述聽起來是滿美好的... 讓我們繼續看下去

The Page plugin works with responsive, fluid and static layouts. You can use media queries or other methods to set the width of the parent element, yet:

Yet 來了...

  • The plugin will determine its width on page load
  • It will not react changes to the box model after page load

總而言之就是基本上它 adaptive width 的決定性 render 就只有一次,之後還是要靠自己... 然後它就造成我 angular-easyfb 的 directive rendering 發生了神秘的錯誤 Orz

總之由於實作 Angular directive -> Facebook plugin 的對應上我是使用 FB.XFBML.parse ,而它只針對參數的 child element 做 parse,為了不影響到其它的 element,在 parse 前我原本是會先用一個看不到的 <span> 把 plugin 的元素整個包起來。

這個 adaptive width 破壞了這項平衡... 總之現在碰到 adaptive width 的 plugin 我就一律改用 <div> 來包,也索性不加太多隱藏用的 style,畢竟這個 adaptive width 大概是需要去抓 parent element 的寬度的。

好了,總之經過一番千辛萬苦總算修正完成,連 test 部分也一併改好,終於 release 了!

剛剛上面提到恰好出現的神秘印度人一整個就因為剛好碰到我在解這個 issue,他就在線等 XD

Awesome!!! Its working perfectly.. Really thanks a lot for the quick fix..

真的是超級 quick fix wwwww