webpack雪碧图生成

原文连接:http://dopro.io/webpack-sprites.htmljavascript

前言

在HTTP/2.0尚未普及的如今,css sprite(雪碧图)还是前端工程化中必备的一环,而随着webpack应用的普及,构建工具切换到webpack后雪碧图该如何处理呢?css

目标

先说下咱们但愿达到的效果。html

一、须要合成的雪碧图icon统一放在src / assets / sprite文件夹下前端

二、在src / img 会生成一份以上级目录名称命名的雪碧图,如icon文件夹中用到的图标拼合成icon.png

三、雪碧图从上到下的方式排列,而且每一个图标间隔20px,如图所示

四、在sass中编写,按需合并。

五、编译后获得的样式以下,包括width、height也一同输出

常见方案

目前主要的解决方案有两种java

一种是以webpack-spritesmith、postcss-sprites为表明的插件,webpack-spritesmith主要的运行方式是会预先把sprite目录中的图标拼合好,页面主要依赖生成后的雪碧图。而postcss-sprites则是经过对已经生成的 CSS 文件进行分析,将其中的 background 或 background-image 做为依赖收集,合并成雪碧图后再将相关参数替换。webpack

第二种是loader处理方式,不过网上基本上没有很好的方案,好比说这种git

这种经过注释的方式来识别并非很好。

目前市面上的方案都不能知足咱们的个性化要求,相对于插件针对某一文件夹/文件处理方式,咱们更但愿采用loader链式处理的方式来实现。github

解决方案

采用loader的话只能经过添加标记的方式告知须要合成,好比在background url加上“?_sprite”,而后利用正则获取图片路径,给到相关的库去合成。web

这里主要利用spritesmith开源项目来进行开发,spritesmith很强大,它能够比较灵活的合成雪碧图,经过相应的API能够得到图标的相关信息。

其中sprites是须要被合成的图片路径,里面包含了图标的绝对路径前端工程化

var Spritesmith = require('spritesmith');
Spritesmith.run({src: sprites}, function handleResult (err, result) {
/* ... */
});
复制代码

另外还提供了多种排列的规则,以及能够设置图片间的间距

Spritesmith.run({src: sprites,algorithm:'top-down',padding: 20}, function handleResult (err, result) {
if(err) {
throw err;
}
});
复制代码

打印result能够看到返回的数据主要包括图片的绝对路径,坐标、宽高以及雪碧图的Buffer

利用这些信息咱们能够对返回的样式进行从新处理,知足前面第5点的样式要求

let imageW = image.width;
let imageH = image.height;
if(mobile){
    imageW = imageW/2;
    imageH = imageH/2;
}

let imgWidth = 'width:' + imageW + 'px;';
let imgHeight = 'height:' + imageH + 'px;';

if(i < afterContent.length) {
    
    if(afterContent[i] == ';') {
        end = i + 1;
        afterContent = afterContent.substring(0, end) + backgroundSize+ imgWidth+ '\n' + imgHeight + afterContent.substring(end);
    } else {
        end = i;
        afterContent = afterContent.substring(0, end) + ';\n' +  backgroundSize +imgWidth+ '\n' + imgHeight+ afterContent.substring(end);
    }
    
} 
let imagePosX = image.x;
let imagePosY = image.y;
if(mobile){
    imagePosX = imagePosX/2;
    imagePosY = imagePosY/2;
}
let imageX = image.x == 0 ? ' 0' : ' -' + imagePosX + 'px';
let imageY = image.y == 0 ? ' 0' : ' -' + imagePosY + 'px';
let imagePosition = '';
if(image.x || image.y){
    imagePosition = imageX + imageY;
}

let cssVal = 'url("' + spriteRelativePath + '")' + imagePosition;
复制代码

通常项目中的h5采用的都是双倍图,这里能够增长个判断,若是h5的话则width、height、background-size都减半处理

module:{
      rules:[
          {
              test:/\.(scss|css)$/,
              use: ExtractTextPlugin.extract({
                fallback: "style-loader",
                publicPath: '../../', 
                use: [{
                  loader:'css-loader'
                },{
                  loader:'isprite-loader',
                  options:{
                    outputPath:'./src/assets/img/',
                    mobile:true
                  }
                },{
                  loader:'sass-loader'
                }],
              })
          },
      ]
}
复制代码

最后

到这里已经基本能达到预期的效果,不过仍有些问题没有处理好,好比每次都会生成雪碧图,这对于编译速度会有必定的影响,针对这种问题,能够采用hash值进行对比,若是文件没有改动的话则不处理。

每个业务都有不一样的需求场景,这种方式可能不必定适用于全部项目,但愿对你们有所帮助。

附上demo (https://github.com/Klchan-me/srpite)

欢迎关注“腾讯DeepOcean”微信公众号,订阅更多优质前端文章哟~

相关文章
相关标签/搜索