教你寫個webpack的loader

loader介紹

loader是將指定格式的資源文件轉化成必定格式輸出,例如sass-loaderscss文件轉化成css文件, babel-loaderES6轉化成ES5.一個loader的結構就是一個函數,最簡單loader以下:css

module.exports = function(content){  // content就是你要處理文件的內容,如處理App.vue文件,content就是你在App.vue寫的代碼
    //... 中間能夠對content處理
    return content  // 這裏你也能夠用this.callback(null, content)導出
}

loader的使用,配置webpack文件html

{
        test: /\.css$/,
        // easy-css-loader就是下面我要寫的loader
        use: ['style-loader', 'css-loader', 'easy-css-loader'] 
    }

loader解析順序是:從右向左, 上一個loader處理完的content傳遞給下一個loader, 通常每種loader功能是單一的vue

easy-css-loader實現

easy-css-loader將實現一些css代碼的簡寫(雖然sass等已經有這個功能,可是每次都要寫個.scss文件在導入,不大方便).webpack

效果圖git


例:
對應代碼github

<div>
    <div class="easy-css">2</div>
</div>
<style >
.easy-css{
  border: 1px solid red;
  posC;    
  wh(100px, 80px);
  font(20px, blue, center);
  comB(http://ww1.sinaimg.cn/large/b44313e1gy1fyz1li77jzj20q411wdop.jpg); 
}
</style>

下面講講font(..)解析過程web

<!--你代碼寫的樣式-->
<style >
  .easy-css{
    font(20px, yellow);
  }
</style>
<!-- 會解析成 -->
<style >
  .easy-css{
    font-size: 20px;
    color: yellow;
    text-align: left;
  }
</style>

上面的代碼, 若是在webpack配置解析.css的自定義的loader, 那麼在loader裏,前面說的content就長成這樣了npm

.easy-css{
    font(20px, yellow);
  }

是否是隻要正則匹配font(20px, yellow),替換成數組

font-size: 20px;
color: yellow;
text-align: left;

下面是loader的代碼緩存

/**
 * @param {*} fontStr 待解析字符串的`font(..)`
 * @returns 解析完css字體樣式
 */
function fontParse(fontStr) {
  let start = fontStr.indexOf('(') + 1  // ‘(’後面一個字符位置
  let args = fontStr.slice(start, -1)  // 就是取font(..)括號裏面字符串,按例子args爲'20px, yellow'
  let argsList = args.split(',')  // 分割成數組['20px', 'yellow']
  switch (argsList.length) { // 判斷開發者傳遞參數個數
    case 2:
      argsList.push('left')
      break
    case 1:
      argsList.push('#000', 'left')
      break
  }
  cssName = ['font-size', 'color', 'text-align'].map((item, index) => {
    return `${item}:${argsList[index]}` // 組合成新的樣式數組
  })
  let cssStr = cssName.join(';')  //造成新css字符串
  return cssStr  // 回調
}
module.exports = function (content) {  // content就是在<style>..</style>寫的裏面的內容,或者引入的.css文件
  content = content.replace(/font\((.|\n)*?\)/ig, (str) => fontParse(str)) 
  this.cacheable()  // 緩存
  this.callback(null, content)  // 回調
}

上面的正則會匹配到font(..), str就匹配到的font(20px, yellow)字符串, 最終會被fontParse(str)值替換.就已經完成font的解析

其它樣式的解析能夠寫成鏈式

module.exports = function (content) {  // content就是在<style>..</style>寫的裏面的內容,或者引入的.css文件
  content = content.replace(/font\((.|\n)*?\)/ig, (str) => fontParse(str))  // 解析font()字體樣式
                    .replace(/wh\((.|\n)*?\)/ig, (str) => whParse(str))  // 解析wh()寬高樣式
                      .replace(/posC(.|\n)*?;/ig, (str) => posCParse(str))  // 解析posC居中樣式
                          .replace(/flex(.|\n)*?;/ig, (str) => flexParse(str))  // 解析flex佈局樣式
                            .replace(/comB(.|\n)*?;/ig, (str) => backParse(str))  // 解析comB(..)背景圖片樣式
                              .replace(/posL(.|\n)*?;/ig, (str) => posLRParse(str, 'left')) // 解析posL(..)居左樣式
                                .replace(/posR(.|\n)*?;/ig, (str) => posLRParse(str, 'right'))  // 解析posR(..)居右樣式
  this.cacheable()  // 緩存
  this.callback(null, content)  // 回調
}

一個loader大功告成

說明

具體的能夠去看源碼,在github上,以爲能夠的話幫忙star一下

我發佈npmeasy-css-loader使用以下配置

{
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader', 'easy-css-loader'] // 順序必定要注意
      }
    ]
  }
}
相關文章
相關標籤/搜索