webpack開發--postcss插件

PostCss 是一個CSS後處理工具

PostCss 是什麼

    首先,聊PostCss之前,我們得知道什麼是CSS後處理工具。我們比較熟悉的Less,Sass,Stylus,這類工具都屬於CSS預處理工具通過特殊的規則、文本格式最終生成CSS文件。而PostCss則是對CSS進行處理,最終生成CSS
    多數人最早接觸和使用的應該是Autoprefixer這款插件,Autoprefixer的功能是:以 Can I Use 上的 瀏覽器支持數據 爲基礎,自動處理兼容性問題。

#  Autoprefixer 處理前的CSS樣式
.container {
display: flex;
}
.item {
flex: 1;
}
#  Autoprefixer 處理後的CSS樣式
.container {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
}
.item {
-webkit-box-flex: 1;
-webkit-flex: 1;
-ms-flex: 1;
flex: 1;
}

通過使用Autoprefixer插件,很大程度上節省了CSS重複樣式的編寫。Autoprefixer正是PostCss衆多插件中的一款,查找更多插件,點這裏

PostCss 處理Css過程

作爲一款可安裝使用各類插件的工具,PostCss 提供的API還是很簡潔明瞭的(吐槽一下Less,什麼鬼玩意兒,API文檔都不寫的)

  • Css文件信息處理成樹型結構的Js對象。
  • 根據配置插件的順序對樹型結構的Js對象 進行操作。
  • 最終將處理後獲得的樹型結構的Js對象輸出爲Css文件。

那麼關鍵點就在與Css被處理後生成的樹型結構的Js對象,那麼先讓我們看一看它的小裙裙裏藏着什麼。

PostCss 處理Css詳解
  • 下圖爲一個很標準的Css,有註釋、帶有@的媒體查詢、以及選擇器樣式。
    • 上面的Css最終會處理爲下圖結構,通過打印信息我們可以發現樹型結構的Js對象是一個名爲Root的構造函數,而起樹型結構的nodes節點下還有CommontAtRuleRule構造函數。
  • 樹型結構的Js對象在最後會處理成名爲Result的構造函數,如下圖,帶有css這個屬性,包含完整的Css信息,最終會被寫入到文件中。
PostCss 中的各種構造函數

在上面部分關於 PostCss處理Css中,生成了很多構造函數。而 PostCss的神奇功能也都圍繞着這些構造函數,接下來我們一一介紹。

  • Root: PostCss處理過的Css,整個處理過程基本上都在圍繞着RootCommontAtRuleRule都是它的子節點。

  • Commont: Css中的註釋信息,註釋的內容在Commont.text下。

  • AtRule: 爲帶@標識的部分,name爲標識名稱,params爲標識參數。nodes爲內部包含的其他子節點,可以是CommontAtRuleRule,這讓我們可以自定義更多的規則,

  • Rule: 選擇器樣式部分,一個選擇器代表一個Rule,選擇器對應的樣式列表nodesDeclaration構造函數,

  • Declaration: 爲Css樣式屬性,prop爲樣式屬性,value爲樣式值。可給Rule手動添加樣式屬性,也可以修改prop,value。上文提到的Autoprefixer就是通過clone當前屬性,修改prop並添加到選擇器下。

  • Result: 通過root.toResult()方法可以獲取到帶有css全文本信息的Result對象,也代表這我們 PostCss 單個插件到了尾聲。接下來直接將result.css寫入對應的文件即可。

如何使用 PostCss 插件

PostCss 插件有很多種使用方式,

  • 可以配合在postcss-loaderoptions配置各種插件
plugins: [
          themePlugin({}),
          autoprefixer({})
        ]
  • 也可以直接在Node程序中使用
postcss([themePlugin({})])
      .process(css, {from: ``, to: ``})
      .then(result => {
        // 根據配置文件themeList,分別處理對應的文件,打包各css 文件
      })
      .catch(error => {
        throw new Error(error)
      })
如何編寫一個 PostCss 插件

上文中,我們對Css處理後生成的Root以及其節點下的CommontAtRuleRuleDeclaration有了基本的認識,那麼我們是如何獲得Root,又將拿這些構造函數做些什麼呢。

var postcss = require('postcss');

module.exports = postcss.plugin('postcss-test-plugin', function (opts) {
  opts = opts || {};    // 處理 options    
  return function (root, result) {
    //遍歷所有的選擇器
    root.walkRules(function(rule) {
      //遍歷所有的屬性
      rule.walkDecls(function(decl) {
        //dect 是一個包含屬性-值對和一些操作方法的樣式對象,最重要的兩個屬性是decl.prop 屬性名和decl.value 屬性值.
        //過濾包含 overflow , overflow-x , overflow-y 的屬性
        rule.walkDecls(/^overflow-?/, function(decl) {
          if (decl.value === 'scroll') {
            //判斷是否已經有-webkit-overflow-scrolling,防止重複添加      
            var hasTouch = rule.some(function(i) {
              return i.prop === '-webkit-overflow-scrolling';
            });
            if (!hasTouch) {
              rule.append({
                prop: '-webkit-overflow-scrolling',
                value: 'touch'
              });
            }
          }
        });

      });
    });
  };
});

通過上述插件代碼的示例,其實已經可以很清楚的知道編寫 PostCss 插件的思路。

  • 重點對象是RootCommontAtRuleRuleDeclarationResult;
  • 遍歷方法,walkCommontswalkAtRuleswalkRuleswalkDels;
  • 節點操作(上面的構造函數基本上都有以下類似的操作),appendcloneremovetoString更多操作方法

通過整體梳理,從PostCss 是什麼,做什麼。到PostCss 插件的使用,以及編寫,應該對PostCss 有了整體的認識。PostCssAPI雖然沒有那麼複雜,但足夠我們做很多事情,讓前端工程化玩法更多。示例也只是一個簡單的插件代碼,還有很多像Autoprefixer一樣優秀的插件,我們甚至可以用PostCss 插件像eslint一樣規範Css編寫。

  • 注意事項:
    • postcss-loader默認使用.postcsssrc.js文件的配置,postcss.config.js.postcsssrc.js同時存在是會優先使用.postcsssrc.js中的配置
    • 編寫PostCss 插件時,可能會有很多Node文件操作,請注意同步異步操作的適用情況,避免使用不當,導致產出的css文件內容錯誤
    • vue-loader處理.vue文件時,如果<style>標籤帶有scoped,那麼在經過css-loader > postcss-loader > vue-loader 這一順序處理後,scoped標記會在postcss-loader使用插件產出的css樣式運轉到vue-loader處理時在csshtml標籤處添加[data-v-hash碼] ,此時postcss-loader引用的PostCss 插件如果有導出類的操作,可能會導致scoped失效。並並且沒辦法在vue-loader之後再使用postcss這種思路。只能build的時候在webpack構建鉤子,在處理完.vue文件後再處理相關的導出操作,此時是完整的。(此處還有很多細節,具體有問題,可單獨私聊。)
    • 新版的vue-loaderapi和老版本的有挺大的差別,請做好甄別。

後續看情況更新

有用的網址

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章