webpack下图片文件转webp方案

1,614 阅读3分钟

目的

webp的优势我就不说了,现在的需求就是老项目给所有图片打包成webp格式的,同时考虑兼容性,所有webp格式以及原图片格式都的保留一份

方案

nginx转发方案

通过打包一套静态图片,用nginx转一次,这个最简单,无论css还是js图片拦截代理到webp图片地址,你的项目代码一句不用改

生产环境配置方案

imagemin-webp-webpack-plugin推荐这个插件,使用简单,会自动打包一套webp格式的图片

    const ImageminWebpWebpackPlugin= require("imagemin-webp-webpack-plugin");
    module.exports = {
        plugins: [new ImageminWebpWebpackPlugin()]
    };

    
    tips:但是如果你在css中用到{ background-image: url('../images/icon.webp'); }
    因为此时你的开发环境并没有这张图片,会报资源找不到的错误


    css 背景图片(场景一)

    1.建议css中使用自己找得到的图片{ background-image: url('../images/icon.png'); }
    通过给--生产环境下-- 配置css-loader webpcss,再打包一套css

    这个loader的逻辑也很简单,用到背景图片的地方就给多打了一套类名 .webp的样式
        /* Source */
        .icon { background-image: url('../images/icon.png'); }

        /* Result */
        .icon { background-image: url('../images/icon.png'); }
        .webp .icon { background-image: url('../images/icon.webp'); }
    
      /webpack.pro配置/
      const webpcss = require('webpcss').default;
      postcss: {
        plugins: [
        webpcss({
          webpClass: '.webp',
          noWebpClass: ''
         })
        ]
      }
      /写js判断浏览器是否支持webp,追加.webp类名渲染/
      var i=new Image;
      i.onload=i.onerror=function(){
          document.body.classList.add(i.height==1?"webp":"no-webp")};
      i.src="data:image/webp;base64,UklGRhoAAABXRUJQVlA4TA0AAAAvAAAAEAcQERGIiP4HAA==";
      
    2.自己先打包一套图片到相应文件夹下面
    
    
    html =>img标签(场景二)

    也可以写自定义指令去根据浏览器替换webpc,亦可自己去写全局替换img标签的逻辑,这个方案就多了


        Vue.directive('webp', {
          bind: function (el, binding) {
            var img = new Image();
            img.onload = function () {
              if (img.height > 0 && img.width > 0) {
                el.src = el.getAttribute('data-webp');
              } else {
                el.src = binding.value;
              }
            };
            img.onerror = function () {
              el.src = binding.value;
            };
            img.src = el.getAttribute('data-webp');
          }
        });

    使用    

        <img v-webp="image.png" data-webp="image.webp" />    
    

开发环境配置方案

imagemin imagemin-webp

这两插件配合一下,写个简单的node程序,基本逻辑就是在dev环境就打包图片一次到src/assets下面,在相同的目录下生成一套webp格式的图片

1.在项目目录下新建一个webpmin.js文件,

/*
 imagemin 用来压缩图片的 例子是7.0.1这个版本
 imageminWebp 一个插件,用来吧图片转成webp
 path NodeJS ’path’ module 

 默认imagemin,在多目录情况下是不保存目录结构的,有可能新版本会支持吧
 使用最终你的destination决定输出文件夹
 基本逻辑就是拿到所有的文件夹路径,遍历去写入到相应的文件目录下
*/

const imagemin = require('imagemin');
const imageminWebp = require('imagemin-webp');
const path = require('path');

(async () => {
    //拿到满足匹配规则的文件信息 file  sourcePath  destinationPath
    const files = await imagemin(['src/assets/**/*.{jpg,png}'], {});
    /*
     自定义目录 打包到源文件夹目录  让destinationPath等于sourcePath就可以了
    */
    files.map(item => {
        let sourcePath = item.sourcePath
        let destinationPath = path.dirname(sourcePath)
            imagemin([sourcePath], {
                destination: destinationPath,
                plugins: [
                imageminWebp({
                    quality: 75
                })
                ]
            });
    })
})();

2.node webpmin.js 命令执行就行了

3.也可以在package.json把命令加进去

  "scripts": {
    "dev": "node webpmin.js&&vue-cli-service serve",
    "build:prod": "vue-cli-service build",
    "build:stage": "vue-cli-service build --mode staging",
    "webpmin": "node webpmin.js",  
  },


4. src/assets 有相应的文件了,就好办了


css 背景图片(场景一)

可以手写写一套兼容的样式,不想手写的话,通过postcss参照上面的wepcss插件也能自己打包一套样式进去


逻辑用到背景图片的地方就给多打了一套类名 .webp的样式
/* Source */
.icon { background-image: url('../images/icon.png'); }
 
/* Result */
.icon { background-image: url('../images/icon.png'); }
.webp .icon { background-image: url('../images/icon.webp'); }



     /webpack.dev配置/ postcss wepcss
      const webpcss = require('webpcss').default;
      postcss: {
        plugins: [
        webpcss({
          webpClass: '.webp',
          noWebpClass: ''
         })
        ]
      }
      /写js判断浏览器是否支持webp,追加.webp类名渲染/
      var i=new Image;
      i.onload=i.onerror=function(){
          document.body.classList.add(i.height==1?"webp":"no-webp")};
      i.src="data:image/webp;base64,UklGRhoAAABXRUJQVlA4TA0AAAAvAAAAEAcQERGIiP4HAA==";
      

    html =>img标签(场景二)

    也可以写自定义指令去根据浏览器替换webpc,亦可自己去写全局替换img标签的逻辑,这个方案就多了


        Vue.directive('webp', {
          bind: function (el, binding) {
            var img = new Image();
            img.onload = function () {
              if (img.height > 0 && img.width > 0) {
                el.src = el.getAttribute('data-webp');
              } else {
                el.src = binding.value;
              }
            };
            img.onerror = function () {
              el.src = binding.value;
            };
            img.src = el.getAttribute('data-webp');
          }
        });

    使用    

        <img v-webp="image.png" data-webp="image.webp" />