webpack图片打包问题

最近终于讲完了Gemba Walk,终于有时间大把的时间好好补补最近落下的知识了。

背景描述

最近需要给项目中加上一个icon,第一反应就是问UX要个png的icon图片,图片拿上之后,上手就开始做。

这是第一次在某个repo工作,看完这个库的pattern之后,猛然发现整个库没有一个png文件,全是svg,出于懒惰心里,全然没有管,直接用了component中用了png文件。写完发现都没啥问题,行吧部署staging,等待第二天showcase。

第二天,果然,icon出不来了。。打开控制台network:

  • 图片请求403,并且请求路径是s3
  • 手动打开aws看到这个bucket下竟然没有这个图片文件(原来是被打包坑了的。。。)
  • 我气冲冲的打开webpack配置文件,发现:
    • png的loader是存在的。。。。
  • 行8,本地build一下吧,发现,果然和webpack里配置的一样,在build的结果目录下一个images目录下孤零零的躺着一个我的png icon

------------懵逼分割线

不得以,开始看部署文件。。。

  • 发现package步骤不仅有webpack打包,还有gulp publish
  • 果然在gulpfile.js中发现,他们竟然只把我打包结果中的js和css文件作为result扔到s3上,根本没有管images

本想气冲冲的把打包结果中的images目录扔到s3上,但是猛然觉得有点不对。。。诺大的项目中没有一个png只有svg,这才是人家的pattern,然后引发了我几个问题:

Q1: svg和png图片的优劣都是啥,为什么有些项目不管什么类型的图片都可以接受,但是有些项目必须要svg?

Q2: 使用webpack打包svg和png的异同?

Q3: 那么svg打包的结果也是单独文件吗?

.......

学习过程

浏览器对图片的处理

对于浏览器而言,可以支持多种类型的文件:css/html/image ,那么图片一般通过两种方式其嵌入HTML:

  • HTML tag
  • 通过css中 backgroung: url(***)

那么src或者说url的参数中应该填写什么样的format呢?

  • src/url的参数可以是Http URL
  • src/url的参数也可以是Data URL

什么是Data URL?开发的时候应该选择Http URL还是Data URL?

DataURL
  • What

    DataURL:将文件通过某种编码方式(可以使base64编码)转化成一串字符,浏览器能够通过直接读取字符还原文件。换句话说此处的URL不代表资源的地址,而直接是资源。

  • How
    Data URLs 由四个部分组成:

    • 前缀(data:)
    • 指示数据类型的MIME类型
    • 如果非文本则为可选的base64标记
    • 数据本身

    data:[][;base64],
    data:image/gif;base64,**********

  • Why

    我们所看到的网页上的每一个图片,都是需要消耗一个 http 请求下载而来的, 使用DataURL,图片就可以跟随HTML()或者css (background:url())一起被拿回来,不用重新发送请求了。

  • Pros

    • 节省http请求(虽然CssSprites也可以)
    • 没有跨域问题
  • Cons

    • 图片被编码之后,生成的字符串编码大小一般而言都会比原文件大30%。如果把大图片编码到 html / css 中,会造成后者体积明显增加,明显影响网页的打开速度。
    • base64 无法缓存,要缓存只能缓存包含 base64 的文件(HTML/CSS文件)

综上所述,如果图片足够小(比如icon)且无法被制作成雪碧图(CssSprites),base64是个很好的选择。

svg和png以及jpg的优劣

我们都知道,一个web项目能够支持JPG/PNG/SVG多种图片文件格式,那么当我们需要图片时候应该选用哪一种format呢?

那么问题应该什么样的图片能够提升浏览器性能?
  1. 降低图片的大小:

    如果图片使用HTTP URL,那么就意味着,浏览器需要发起HTTP请求获取图片,那么请求的response一定是尽可能的小才对。

    • 虽然对于浏览器而言,是异步发送图片请求(预加载),因此render tree的生成肯定不会等到图片拿回,但是图片如果很久之后才能获取,可能导致页面重新布局重新渲染。

    方案:
    可以选择使用svg格式的图片,svg生成的文件很小,下载很快

  2. 选择适当的图片宽度尺寸(即响应式图片)

    因为对于Mobile和Web端,图片的分辨率要求不同而且尺寸要求也不同,因此根据不同的设备请求不同的图片也是提升性能的一种方式。

    如何实现呢?

    • 通过css media实现
    • Img的srcset和sizes的方法
    • 通过picture元素,picturefill或平台判断来为不同终端平台输出不同的图片
  3. 减少HTTP的网络资源请求

    如果图片的总数量没法改变,一个一个请求就意味着要发很多次HTTP 请求,那么将多个图片作为一个response的结果就可以减少Http请求的数量,那么有什么方案能够做到呢?

    • 使用Data URL替代Http URL
    • 合并图片sprite(雪碧图))
  4. 图片延迟加载(懒惰加载)

    首屏不需要将所有图片取回而是只把视窗内的图片取回

不同的图片format
  • png:
    • pros:
      • 透明背景
      • 支持高级别无损耗压缩
    • cons:
      • 图片尺寸相对较大
  • svg:
    • pros:
      • 透明背景
      • 对于高分辨率设备表现很好
      • 可编程
  • jpg:
    • pros:
      • 可以把文件压缩到最小,适合应用于WEB图片,可减少图像的传输时间
      • 可利用可变的压缩比以控制文件大小
    • cons:
      • 不是透明背景,因此不适于做icon,线条
      • 会造成质量下降,当您每编辑和重新保存 JPEG 文件时,JPEG 会混合原始图片数据的质量下降。这种下降是累积性的、永久性的

看起来svg简直是完美,但是请注意png不能装成svg,但是svg可以转成png(质量降低)

------> 好了现在可以解释,为啥我们项目的icon要使用svg了,图片有小又是透明背景,秒杀我的png,那么为啥不选择使用jpg呢?

图片透明背景的意义

试想一个场景,一个icon他的格式是jpg(非透明背景),放在一个非白色背景上,然后出现这样的场景


左上角的icon是jpg格式

不对呀,怎么能是这样!应该长这样的啊


image.png
  • 因此当你的图中是icon或者是有镂空的部分,必须选用透明背景格式的图片
  • 但是,当你的图片是一张纯背景,没有镂空,就可以选用jpg,比如背景图片

webpack如何打包这些不同类型的图片呢?

我们需要loader去处理这些图片,不同的loader有不同的作用

url-loader:

将文件转成base64编码的DataUrl string, 根据上文所知:我们希望只有文件足够小的时候被转成base64,所以这个loader有两个参数很重要:

  • limit: 指明被转成base64的文件最大尺寸
    • 小于这个值的图片被转成base64,webpack会替换src的值成为base64编码
    • 大于这个值的图片会被file-loader处理,并将这个loader的options转给file-loader
  • fallback: 指定一个当图片尺寸大于limit时候使用的loader(不指定就是file-loader
file-loader:

将图片打包到某一个文件中,并替换src变成打包后图片的Http URL,可以自定义图片打包后的文件名和位置

svg-url-loader:

将文件转成utf-8编码的DataUrl string,和url-loader不同不会转成base64这样做的好处是:

  • 更小
  • 浏览器更快的读
  • 压缩的更好

URL-loader一样可以设置limit确定什么样大小的图片可以被转成DataURL什么样的图片使用file-loader

但是使用的过程中,这些option很重要:

  • noquotes:true:在转码成DataURL的时候不要带引号,保证DataURL一定能被浏览器解析成正确的svg图片
  • limit
  • iesafe:true:只有这个属性设置为true才能保证limit超过之后被file-loader解析

资料

https://www.itcodemonkey.com/article/3002.html

你可能感兴趣的:(webpack图片打包问题)