一場由postcss-bem引發的血案

墨箏發表於2018-03-26

緣起

樓主最近搭建了一套前後端開發環境用於開發自己的網站並嘗試一些有趣的前端技術,在整個環境執行正常之後,樓主某天心血來潮想將之前的less檔案用pcss代替,使用bem的方式去編寫css,然後用postcss-bem外掛去處理樣式規則的轉換。在一切配置準備就緒後,正當我興致勃勃的執行webpack編譯打包時,令人驚奇的事情發生了
原始碼:

一場由postcss-bem引發的血案

postcss處理後結果:
一場由postcss-bem引發的血案

很明顯的是在component宣告中的樣式規則可以正常輸出,但是在子宣告中的規則就被幹掉了,儘管class可以正常解析。
一場由postcss-bem引發的血案
這強烈的刺激到了樓主的好奇之心,於是我便開始扒這個外掛的原始碼,終於發現了問題所在
一場由postcss-bem引發的血案

postcss-bem外掛在處理modifier和descendent型別宣告的過程中將當前規則的子節點移植到newRule時用的是moveTo方法,由於我之前升級了webpack4,併為了適配webpack4將其他的loader等也升級到了最新版,而在最新版的postcss中,由css源字串解析成的抽象語法樹已經廢棄了該方法,導致當前規則的子節點不能移植到新建的規則newRule中,從而使子宣告中的樣式規則丟失。
一場由postcss-bem引發的血案
明白了這一點之後我準備給該專案的開發者提issue,卻發現npm網站中該專案連結到的Github地址404了,對,你沒看錯,就是404了
一場由postcss-bem引發的血案

此刻的內心:開發者你出來,我保證不打死你
一場由postcss-bem引發的血案

擴充

基於上述原因,我決定自己開發一個postcss-bem外掛,可以幫助到那些和我遇到相同問題的開發者,順便也幫助大家瞭解怎樣去開發一個postcss外掛。

@mozheng-neal/postcss-bem

因為舊專案的程式碼無人維護而且有可能會有其他坑,所以我選擇了重新造輪子,這就是@mozheng-neal/postcss-bem,與此同時通過快取父級元素選擇器的方式,它在元素選擇器的生成上擁有更快的速度。大家可以在github上看到該專案的原始碼和使用方式(您的star是對我最大的鼓勵)。

一場由postcss-bem引發的血案
接下來我會用一個簡單的示例向大家介紹如何寫一個postcss外掛,以便大家以後在開發過程中可以利用自己的奇思妙想創造更多有趣的東西。

如何寫一個postcss外掛

假設我們要實現這樣一個功能:在css的每個樣式宣告中新增一個color屬性,值為#666,如果當前宣告中已經存在color屬性但值不為#666,那麼就將其設定為#666。
首先我們來看下一個postcss外掛的基本結構

const postcss = require('postcss')
postcss.plugin(pluginName, function (opts) {
  return function (root, result) {
    // root is the root node object
    // this is where your plugin process logic should be placed
  }  
})
複製程式碼

postcss會將獲取到的css原始碼字串轉換為js表示的抽象語法樹,上述的root就表示該語法樹的根節點。要實現我們之前想要的功能,在外掛邏輯中我們需要藉助一些postcss為節點物件提供的API。

return function (root, result) {
  root.walkRules(function (rule) {
    // rule為樣式檔案中的宣告塊
    let hasColorProp = false
    rule.walkDecls(function (decl) {
      /* 
       * decl表示宣告塊中的每條css屬性節點
       * 比如color:#fff會被解析成decl.prop === color,decl.value === #fff
      */
      if (decl.prop === 'color') {
        hasColorProp = true
        if (decl.value !== '#666') {
          decl.value = '#666'
        }
      }
    })
    if (!hasColorProp) {
      rule.append({prop: 'color', value: '#666'})
    }
  })
}
複製程式碼

通過如此簡單的一個外掛就能完成以往我們需要付出很多手力勞動才能做到的事是不是開心到爆炸

一場由postcss-bem引發的血案
在這個過程中我們改動的只是抽象語法樹結構,在外掛處理完成後postcss會利用轉換後的抽象語法樹生成新的css原始碼字串。而這還只是我們對於postcssAPI的簡單應用,postcss為節點物件提供了更加豐富的能力,如果想了解更多,你可以參考postcssAPI詳情

結語

postcss是一個非常便利的css開發工具,使用得當也可以極大提升你的開發效率,而且postcss外掛的編寫也並不複雜,它絕對是你在前端開發的學習過程中值得去掌握的一個技能。最後再囉嗦一句,歡迎大家使用我的postcss-bem外掛,有任何問題歡迎提issue, 我會一直維護這個專案的。

插播一條廣告

蘑菇街前端開發團隊持續招聘高階/資深前端開發工程師,歡迎各位大佬砸簡歷給我哦,郵箱m13710224694@163.com

相關文章