透过现象看webpack处理css文件中图片路径转换的具体过程
webpack是目前使用比较流行的一个前端模块打包器,前端的任何资源都被当成一个模块来处理,如图片、css文件等等。在基于webpack构建的前端项目中,一般都会配置有关css文件处理的规则,这其中也包括css文件中图片资源的处理,那么webpack到底是怎么处理它的呢?笔者之前也遇到过类似图片路劲的问题,为此还写过一篇博文webpack生成的css文件background-image url图片无法加载。今天就来说说webpack是怎么处理css文件中的图片路径的,首先上一个具体的例子。
一个具体问题
最近使用umi搭建前端的一个项目,在使用过程可能遇到一个umi的bug,为此还提出了一个issue 项目配置css module影响到css-loader对第三方库css文件中图片url的处理。顺便在简述下:
在项目中通过设置
cssLoaderOptions.modules为true来开启css module项目中引入了第三方库kindeditor的css文件。
import 'kindeditor/themes/default/default.css'
该default.css文件中有通过
url引入图片资源,并且图片资源非相对路径写法,例如其中一处的写法:.ke-toolbar-icon-url {
background-image: url(background.png);
}
然后通过npm start开启本地服务进行预览时,编译报错,如下图:

奇怪,明明对应的图片资源是存在的,webpack编译时为啥找不到呢?苦苦寻思了一番没有找到答案,于是一头扎进webpack和css-loader源码的海洋中开启"寻宝"之旅。
不卖关子了,导致上述的直接原因:
css-loader没有对css文件的
url方法进行处理(转化为相对路径)
这样导致webpack在整合经过loader处理后的default.css模块时,因为模块用到require(background.png)来引用图片资源,此时就用到Nodejs的模块加载机制,其具体可以查看本博客另一篇文章谈谈npm依赖管理,也可以查看nodejs官网module章节。nodejs在解析background.png图片路径时,会将其解析为第三方模块,这样会从node_modules中查找,通过在webpack中打印错误日志,可以从其中看出一些端倪,如下图,missing字段表示查找过的路径均没有找到对应的资源文件。

umi内部其实使用css-loader-1(fork css-loader@1.x而来)来处理css文件的, 导致css-loader没有对css文件图片路径进行处理的底层原因:
项目开启css module后,不该影响到node_modules中css文件的css module的情况而实际上产生了影响;导致没有对第三方库中的css文件中图片路径进行处理
webpack是怎么转化css中的图片路径的?
如果单纯为了解决上面问题就可以到此为止,但是处于好奇,毕竟被坑了几次,想知道webpack是怎么处理css文件中的图片路径的。例如我们在项目中这样写过css:
.xxa {
background: url(background.png)
}
或者这样:
.xxb {
background: url(~alias/background.png)
}
在项目中,不论我们用less、stylus还是sass等css预处理库编写css,其最终是通过对应的loader如less-loader将编写的样式转换变换为css,然后通过css-loader来处理css中有关路径的转换,其作用拿其官网的介绍来说:
The
css-loaderinterprets@importandurl()likeimport/require()and will resolve them.
最常见处理css样式的项目,一般经过以下几个loader从右到左顺序执行,拿less编写的样式来说,以内联loader的展示形式来说明:
!!css-loader!post-loader!less-loader!./xxx/xx.less
当然css-loader处理后还要经过style-loader或者mini-css-extract-plugin提供的loader处理,但是这不在本次谈论范围。
下面通过一幅图来看看经过webpack解析模块到css产出这一过程,webpack帮我们做了什么。

具体就来简单分析整个流程,可能分析有不正确的地方,还请大家批评指正
NormalModuleFactory解析并创建模块
首先从入口文件(entry配置的文件)开始构建,使用NormalModuleFactory来解析并创建模块
NormalModuleFactory使用
enhance-resolve来解析依赖的模块绝对地址,如果模块地址解析错误就会如文章开头的问题抛出错误,解析正确则会创建依赖模块。如上图中的./index.css,模块地址解析成功后,webpack为index.css创建的模块属性如下图:
创建的一个模块,一般包括模块的type、context、request、userRequest、rawRequest、resource、dependencies和loaders等模块相关信息。
模块创建后,会用其依赖处理的loader来编译模块内容,模块依赖的loader存放在模块的loader属性数组中;对于css文件最后是用
css-loader来处理。
css-loader编译css文件
css-loader官网说的会对css文件的url/@import进行处理,但是具体实现细节并没有详细阐述。下面来简单说说对css-loader的主要功能:
转换css中的
url和@import为require/import;例如
url中的地址(绝对地址除外)会被解析为相对地址,防止webpack在解析模块地址时出错;这其中包括webpack alias别名组成的地址和node_moduels库中地址。顺便说下:css-loader内部是通过
postcss生成css的ast并遍历找出其url方法来完成转换的。
按comonjs模块的形式生成css文件模块内容
css文件最终转换后的commonjs模块形式,模块的后缀还是.css,其内容如下图所示:

css-loader还处理css module,也是通过遍历css的ast来完成转换
这样通过css-loader完成了css文件中图片url路径的转换,有助于webpack寻找图片资源的具体位置。
url-loader处理图片资源
其实,在css-loader处理完css模块过程中,会再次通过NormalModuleFactory来解析并创建其内部的图片模块,webpack模块对应的属性如下图:

生成图片对应的commonjs模块内容可能为base64的内容,如下图:

也可能为图片资源产出的引用地址,如下图:

这主要取决于url-loader在处理图片资源时是否指定limit配置项值,该值会跟图片内容大小进行比较。在limit值小于图片内容大小时,则使用file-loader来实现图片提出到webpack编译产出的对应位置下。
上面图片模块内容为图片产出地址,正是file-loader处理的结果,其实现以下几项功能:
图片内容会抽离到webapck的编译产出位置。
按照loader的
name配置和webpack的publicPath配置项生成最终的url。因为图片的内容被抽离掉,那么webpack生成的图片模块内容应该为该图片的引用地址。这涉及到两部分
根据file-loader的name配置项生成相对地址部分。
如下file-loader配置项:
{
test: /\.(png|jpe?g|gif)$/i,
loader: 'file-loader',
options: {
name: 'static/[name].[hash:8].[ext]',
},
}
然后根据
loader-utils的interpolateName方法解析对应的url。例如上面css文件的图片地址转换结果:./background.png会转换为:static/background.a9153e95.png根据
webpackConfig.output.publishPath生成图片的引用地址。最终生成的地址为:
__webpack_public_path__ + "static/background.a9153e95.png";
经过上面步骤的处理,我们看到产出的最终css文件的效果如下图:

顺便说一下,如果产出的css文件经过mini-css-extract-plugin提供的loader进行统一抽离,那么它也可能会影响css文件中图片的引用路径,尤其该loader配置了publicPath内容,如下面loader的配置:
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: 'public/path/to/'
}
}
那么css文件中图片的路径最终结果如下图:

这就是webapck通过各种loader处理css中图片路劲的过程,通过这一过程我们可能只是大概对这一过程有一个大概的认知,如果要深入理解还是需要花时间研究。
参考文献
透过现象看webpack处理css文件中图片路径转换的具体过程的更多相关文章
- webpack打包 css文件里面图片路径 替换位置
{ test: /\.css$/, use: ExtractTextPlugin.extract({ use: ['css-loader?minimize', 'autoprefixer-loader ...
- 用extract-text-webpack-plugin提取出来的css文件中背景图片url的不正确的问题
在一个main.js中require一个scss文件,scss文件中用了背景图片,图片url是用的相对路径,用extract-text-webpack-plugin插件提取出的css文件背景图片路径不 ...
- webpack模块加载css文件及图片地址
webpack支持css文件加载并打包,只需安装相应加载器并在配置文件中配置 . 加载的css文件内容会与该模块里的js内容混合封装,这样做的好处是一个js文件包含了所有的css与js内容,有效减少了 ...
- webpack抽取CSS文件与CSSTreeShaking
webpack抽取CSS文件 CSSTreeShaking 一.webpack抽取CSS文件 抽取CSS文件的插件:mini-css-extract-plugin npm install --save ...
- webpack(5)webpack处理css文件
css文件处理-准备工作 (以下项目配置都是基于上一篇webpack(4)的基础上) 在项目开发中,我们必然需要添加很多的样式,而样式我们往往写到一个单独的文件中. 这里我们就在src目录中创建一个n ...
- 怎样将多个CSS文件导入一个CSS文件中
问题: 在HTML中引入css的其中的两个方法: 导入式和链接式的目的都是将一个独立的css文件引入一个文件中,二者的区别不大,事实上,二者最大的区别在于链接式使用html的标记引入外部css文 ...
- webpack快速入门——CSS分离与图片路径处理
1.在终端安装extract-text-webpack-plugin 2.引入插件 const extractTextPlugin = require("extract-text-webpa ...
- JAVA文件中获取路径及WEB应用程序获取路径方法
JAVA文件中获取路径及WEB应用程序获取路径方法 1. 基本概念的理解 `绝对路径`:你应用上的文件或目录在硬盘上真正的路径,如:URL.物理路径 例如: c:/xyz/test.txt代表了tes ...
- css和javascript中图片路径的不同
之前在写前端代码时,在图片路径的设置那里经常会遇到一个问题.比方说,我 (1)在根目录下面新建了个"images"文夹,里面放了张图片top.gif (2)在根目录下另外新建了两个 ...
随机推荐
- Redisson实现Redis分布式锁的底层原理
一.写在前面 现在面试,一般都会聊聊分布式系统这块的东西.通常面试官都会从服务框架(Spring Cloud.Dubbo)聊起,一路聊到分布式事务.分布式锁.ZooKeeper等知识.所以咱们这篇文章 ...
- 使用eclipse创建第一个SpringBoot项目
1.new->maven->maven project, 勾选 Create a simple project, 下一个页面中填入group id(项目组织唯一标识, 如org.ap ...
- 菜鸟系列Fabric源码学习 — committer记账节点
Fabric 1.4 源码分析 committer记账节点 本文档主要介绍committer记账节点如何初始化的以及committer记账节点的功能及其实现. 1. 简介 记账节点负责验证交易和提交账 ...
- vue学习笔记(六)表单输入绑定
前言 在上一章vue学习笔记(四)事件处理器这一篇博客的内容中,我们已经了解vue是如何绑定事件的,而本篇博客主要讲解的是vue中表单输入的绑定,通常我们自己提交信息的时候都是通过表单将信息到服务器的 ...
- $Noip2018/Luogu5019/Luogu1969$ 铺设道路
$Luogu$ 去年$Noip$的时候我并没有做过原题,然后考场上也没有想出正解,就写了个优化了一点的暴力:树状数组+差分,然后就$A$了$ovo$. $Sol$ 只要$O(N)$扫一遍,只要当前值比 ...
- Django 博客实现简单的全文搜索
作者:HelloGitHub-追梦人物 文中所涉及的示例代码,已同步更新到 HelloGitHub-Team 仓库 搜索是一个复杂的功能,但对于一些简单的搜索任务,我们可以使用 Django Mode ...
- Java对象头与锁
对象由多部分构成的,对象头,属性字段.补齐区域等.所谓补齐区域是指如果对象总大小不是4字节的整数倍,会填充上一段内存地址使之成为整数倍. 后面两个很好理解,今天我主要想总结一下对象头: 对象头这部分在 ...
- Numpy常用方法及应用总汇
目录 Numpy 1.基本操作 1.1数组转换 1.2数组生成 1.3文件读取 1.4查看操作 2.数据类型 2.1指定数据类型: 2.2查看数据类型 2.3数据类型转换 3.数组运算 3.1数组间运 ...
- SQL 配置管理器无法连接到WMI
在解决之前,需要注意一般出现这个问题是你的SQL SERVER安装有误. 这个问题是SQL 安装路径下sqlmgmproviderxpsp2up.mof的问题. 一般在C盘Program files( ...
- Maven 基础(一) | 使用 Maven 的正确姿势
一.什么是 Maven? Maven 是一个项目管理工具,它的本质是一个项目对象模型(POM),体现在配置中就是我们常见的 pom.xml 文件,而这个 pom 文件就是 Maven 的核心,它管理了 ...