webpack雪碧圖生成

騰訊DeepOcean發表於2018-11-16

騰訊DeepOcean原創文章:dopro.io/webpack-spr…

top

前言

在HTTP/2.0還沒有普及的現在,css sprite(雪碧圖)仍是前端工程化中必備的一環,而隨著webpack應用的普及,構建工具切換到webpack後雪碧圖該如何處理呢?

目標

先說下我們希望達到的效果。

1、需要合成的雪碧圖icon統一放在src / assets / sprite資料夾下

src

2、在src / img 會生成一份以上級目錄名稱命名的雪碧圖,如icon資料夾中用到的圖示拼合成icon.png

img

3、雪碧圖從上到下的方式排列,並且每個圖示間隔20px,如圖所示

icon

4、在sass中編寫,按需合併。

sass

5、編譯後得到的樣式如下,包括width、height也一同輸出

style

 

常見方案

目前主要的解決方案有兩種

一種是以webpack-spritesmith、postcss-sprites為代表的外掛,webpack-spritesmith主要的執行方式是會預先把sprite目錄中的圖示拼合好,頁面主要依賴生成後的雪碧圖。而postcss-sprites則是通過對已經生成的 CSS 檔案進行分析,將其中的 background 或 background-image 作為依賴收集,合併成雪碧圖後再將相關引數替換。

第二種是loader處理方式,不過網上基本上沒有很好的方案,比如說這種

use

這種通過註釋的方式來識別並不是很好。

目前市面上的方案都不能滿足我們的個性化要求,相對於外掛針對某一資料夾/檔案處理方式,我們更希望採用loader鏈式處理的方式來實現。

解決方案

採用loader的話只能通過新增標記的方式告知需要合成,比如在background url加上“?_sprite”,然後利用正則獲取圖片路徑,給到相關的庫去合成。url

這裡主要利用spritesmith開源專案來進行開發,spritesmith很強大,它可以比較靈活的合成雪碧圖,通過相應的API可以獲得圖示的相關資訊。

其中sprites是需要被合成的圖片路徑,裡面包含了圖示的絕對路徑

  1. Spritesmith.run({src: sprites,algorithm:'top-down',padding: 20
    },
    function handleResult (err, result) {
  2.  
     
    if(err) {
  3.  
     
     
     
    throw err;
  4.  
     

    }

  5. });
     
     
     
     
     
     

另外還提供了多種排列的規則,以及可以設定圖片間的間距sort

  1. Spritesmith.run({src: sprites,algorithm:'top-down',padding: 20
    },
    function handleResult (err, result) {
  2.  
     
    if(err) {
  3.  
     
     
     
    throw err;
  4.  
     

    }

  5. });
     

列印result可以看到返回的資料主要包括圖片的絕對路徑,座標、寬高以及雪碧圖的Bufferresult

利用這些資訊我們可以對返回的樣式進行重新處理,滿足前面第5點的樣式要求

  1. let imageW = image.width;
  2. let imageH = image.height;
  3. if(mobile){
  4.  
     
    imageW
    = imageW/2;
  5.  
     
    imageH
    = imageH/2;

  6. }
  7.  
  8. let imgWidth = 'width:' + imageW + 'px;
    '
    ;
  9. let imgHeight = 'height:' + imageH + 'px;
    '
    ;
  10.  
  11. if(i <
    afterContent.length) {
  12.  
  13.  
     
    if(afterContent[i] == ';
    '
    ) {
  14.  
     
     
     
    end = i + 1;
  15.  
     
     
     
    afterContent
    = afterContent.substring(0, end) + backgroundSize+ imgWidth+ '\n' + imgHeight + afterContent.substring(end);
  16.  
     

    }
    else {
  17.  
     
     
     
    end = i;
  18.  
     
     
     
    afterContent
    = afterContent.substring(0, end) + ';
    \n'
    +  
    backgroundSize
    +imgWidth+ '\n' + imgHeight+ afterContent.substring(end);
  19.  
     

    }
  20.  

  21. }
  22. let imagePosX = image.x;
  23. let imagePosY = image.y;
  24. if(mobile){
  25.  
     
    imagePosX
    = imagePosX/2;
  26.  
     
    imagePosY
    = imagePosY/2;

  27. }
  28. let imageX = image.x == 0 ? ' 0' : ' -' + imagePosX + 'px';
  29. let imageY = image.y == 0 ? ' 0' : ' -' + imagePosY + 'px';
  30. let imagePosition = '';
  31. if(image.x || image.y){
  32.  
     
    imagePosition
    = imageX + imageY;

  33. }
  34.  
  35. let cssVal = 'url("' + spriteRelativePath + '")' + imagePosition;

一般專案中的h5採用的都是雙倍圖,這裡可以增加個判斷,如果h5的話則width、height、background-size都減半處理

  1. module:{
  2.  
     
     
    rules
    :[
  3.  
     
     
     
     
    {
  4.  
     
     
     
     
     
     
    test
    :/\.(scss|css)$/,
  5.  
     
     
     
     
     
     
    use: ExtractTextPlugin.extract({
  6.  
     
     
     
     
     
     
     
    fallback
    : "style-loader",
  7.  
     
     
     
     
     
     
     
    publicPath
    : '../../',
  8.  
     
     
     
     
     
     
     
    use: [{
  9.  
     
     
     
     
     
     
     
     
    loader
    :'css-loader'
  10.  
     
     
     
     
     
     
     

    },{
  11.  
     
     
     
     
     
     
     
     
    loader
    :'isprite-loader',
  12.  
     
     
     
     
     
     
     
     
    options
    :{
  13.  
     
     
     
     
     
     
     
     
     
    outputPath
    :'./src/assets/img/',
  14.  
     
     
     
     
     
     
     
     
     
    mobile
    :true
  15.  
     
     
     
     
     
     
     
     

    }
  16.  
     
     
     
     
     
     
     

    },{
  17.  
     
     
     
     
     
     
     
     
    loader
    :'sass-loader'
  18.  
     
     
     
     
     
     
     

    }],
  19.  
     
     
     
     
     
     

    })
  20.  
     
     
     
     

    },
  21.  
     
     
    ]

  22. }

 

最後

到這裡已經基本能達到預期的效果,不過仍有些問題沒有處理好,比如每次都會生成雪碧圖,這對於編譯速度會有一定的影響,針對這種問題,可以採用hash值進行對比,如果檔案沒有改動的話則不處理。

每一個業務都有不同的需求場景,這種方式可能不一定適用於其他專案,希望對大家有所幫助。

附上demo

github.com/Klchan-me/s…

歡迎關注”騰訊DeepOcean”微信公眾號,每週為你推送前端、人工智慧、SEO/ASO等領域相關的原創優質技術文章:

看小編搬運這麼辛苦,關注一個唄:)

webpack雪碧圖生成

來源:https://juejin.im/post/5bee2b1ce51d45787a4bc441

相關文章