webpack雪碧圖生成

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

top

前言

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

目標

先說下咱們但願達到的效果。

一、須要合成的雪碧圖icon統一放在src / assets / sprite文件夾下html

src

二、在src / img 會生成一份以上級目錄名稱命名的雪碧圖,如icon文件夾中用到的圖標拼合成icon.png前端

img

三、雪碧圖從上到下的方式排列,而且每一個圖標間隔20px,如圖所示webpack

icon

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

sass

五、編譯後獲得的樣式以下,包括width、height也一同輸出github

style

 

常見方案

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

一種是以webpack-spritesmith、postcss-sprites爲表明的插件,webpack-spritesmith主要的運行方式是會預先把sprite目錄中的圖標拼合好,頁面主要依賴生成後的雪碧圖。而postcss-sprites則是經過對已經生成的 CSS 文件進行分析,將其中的 background 或 background-image 做爲依賴收集,合併成雪碧圖後再將相關參數替換。web

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

use

這種經過註釋的方式來識別並非很好。sass

目前市面上的方案都不能知足咱們的個性化要求,相對於插件針對某一文件夾/文件處理方式,咱們更但願採用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能夠看到返回的數據主要包括圖片的絕對路徑,座標、寬高以及雪碧圖的Buffer result

利用這些信息咱們能夠對返回的樣式進行從新處理,知足前面第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等領域相關的原創優質技術文章:

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

相關文章
相關標籤/搜索