【Webpack】预处理器 - loader配置介绍

预处理器 (loader) ,的主要功能是赋予了 Webpack 可处理不同资源类型的能力,极大丰富了其可扩展性。

一个Web工程通常会包含HTML、JS、CSS、模板、图片、字体等多种类型的静态资源,并且这些资源之间都存在着某种联系。对于 Webpack 来说,所有这些静态资源都是模块,可以像加载一个JS文件一样去加载它们,如在index.js中加载style.css:

dart 复制代码
//index.js
import './style.css'

这个style.css虽然是被加载在js文件中,但其实是可以被打包并生成在输出资源目录下,对index.js 文件也不会产生质性的影响。这句引用的实际意义是描述了JS 文件与 CSS 文件之间的依赖关系。

在实际开发中,有时某个页面用到了组件,不光要加载JS文件,还要加载样式,而通过Webpack我们可以采用一种更简洁的方式来表达这种依赖关系

dart 复制代码
// 。/u1/calendar/index.js
1mport './style.scss'; //引用组件自身样式

// ./page/home/index.js
import Calendar from './ui/calendar/index.js';
import './styles.css' ;// 引用页面自身样式

可以看到,在calendar的JS中加载了其组件自身的样式,而对于页面来说只要载calendar/index.js 即可(以及页面自身的样式),不需要额引入组件的样式。让Webpack维护模块间的关系可以使工程结构更加直观,代码的可维护性更强。

loader 概述

每个loader本质上都是一个函数。在 Webpack 4之前,函数的输人和输出都必须为字符串; 在Webpack 4之后,loader也同时支持抽象语法树 (AST)的传递,通过这种方法来减少重复的代码解析。用公式表达 loader的本质则为以下形式:

output = loader(input)

举一个例子,当我们使用babel-loader将ES6+的代码转化为ES5时,上面的公式如下:

dart 复制代码
ES5 =babel-loader(ES6+)

loader 可以是链式的。我们可以对一种资源设置多个loader,第一个loader 的输入是文件源码,之后所有 loader 的输入都为上一个loader 的输出。公式如下:

output = loaderA(loaderB(loaderC(input)))

如在工程中编译SCSS时,我们可能需要如下loader:

Style 标签=style-loader(css-loader(sass-loader(SCSS)))

loader 的配置

要注意loader 做的实际上是一个预处理的工作。

loader的引入

假设我们要处理CSS,首先依照 Webpack"一切皆模块"的思想,从一个JS文件加载一个CSS文件。

dart 复制代码
// app.js
import './style.css';

// style.css
body
	text-align; center;
	padding: 100px;
	color: #fff;
	background-color: #09c;
}

此时工程中还没有任何 loader,如果直接打包会看到报错提示

Webpack 无法处理 CSS语法,因此抛出了一个错误,并提示需要使用一个合适loader来处理这种文件。

下面把css-loader加到工程中。loader都是一些第三方npm模块,Webpack身并不包含任何loader,因此使用loader的第一步就是先从npm安装它。在工程目下执行命令:

dart 复制代码
npm install css-loader

接下来我们将 loader引人工程中,具体配置如下:

dart 复制代码
module.exports = {
	// ...
	module: {
		rules: {
			test: /\.csss/,
			use: {'css-loader'},
		}
	}
}

loader相关的配置都在module对象中 ,其中module.rules 代表了模块的处理规则 。每条规则内部可以包含很多配置项,这里我们只使用了最重要的两项一testuse

test
test 可接收一个正则表达式或者一个元素为正则表达式的数组,只有正则配上的模块才会使用这条规则。在本例中是匹配所有以css 结尾的文件。

use

use可接收一个数组,数组包含该规则所使用的 loader。在本例中只配置了一个css-loader,在只有一个loader 时也可以简化为字符串"css-loader"。

此时我们再进行打包,之前的错误应该已经消失了,但是 CSS 的样式仍然没有在页面上生效。这是因为css-loader 的作用仅仅是处理CSS 的各种加载语法 ,如果要使样式起作用还需要 style-loader来把样式插人页面。css-loade与style-loader通常是配合在一起使用的

链式loader

在处理某一类资源时我们都需要使用多个 loader。就比如上面的例子,用css-loader处理CSS的各类加载语法,再使用style-loader 来将样式字符串包装成style标签插入页面。

配置如下:

dart 复制代码
module.exports = {
	// ...
	module: {
		rules: {
			test: /\.csss/,
			use: ['style-loader','css-loader'],
		}
	}
}

我们把style-loader加到了css-loader前面,这是因为在Webpack打包时是按照数组从后往前的顺序将资源交给 loader 处理的,因此要把最后生效的放在前面。

loader options

loader作为预处理器通常会给开发者提供一些配置项,在引入loader 的时候可以通过options将它们传人。

下面是一些场景下loader的相关配置

exclude与 include
excludeinclude是用来排除或包含指定目录下的模块,可接收正则表达式或者字符串(文件绝对路径),以及由它们组成的数组。如下例:

dart 复制代码
rules: {
	test: /\.csss/,
	use: ['style-loader','css-loader'],
	exclude: /node_modules/,
}

上面配置的含义是node_modules 中的模块不会执行这条规则。该配置项通常是必加的,否则可能拖慢体的打包速度。

include的例子如下:

dart 复制代码
rules: {
	test: /\.csss/,
	use: ['style-loader','css-loader'],
	include: /src/,
}

include代表该规则只对正则匹配到的模块生效。

exclude和include 同时存在时,exclude的优先级更高

由于exclude优先级更高,我们可以对include中的子目录进行排除。请看下面的例子:

dart 复制代码
rules: {
	test: /\.csss/,
	use: ['style-loader','css-loader'],
	exclude:/src\/lib/,
	include: /src/,
}

通过include,我们将该规则配置为仅对 src 目录生效,但是仍然可以通过exclude排除其中的src/lib目录。

resource与issuer
resourceissuer可用于更加精确地确定模块规则的作用范围。就比如下面的例子:

dart 复制代码
// index.js
import ./style.css';

在Webpack 中,一般认为被加载模块是 resource ,而加载者是 issuer。如上面的例子中,resource为/path/of/app/style.css,issuer 是/path/of/app/index.js。

如果想要对 issuer 加载者也增加条件限制,则要额外写一些配置。比如,如果我们只让/src/pages目录下的JS可以引用CSS,应该如何设置呢?可以这样:

dart 复制代码
issuer: {
	test: /\.js$/,
	include: /src/pages/,
}

可以看到,我们添加了issuer 配置对象,其形式与之前对resource条件的配置并无太大差异。

enforce

enforce用来指定一个loader的种类,只接收"pre"或"post"两种字符电类型的值。

请看下面的例子:

dart 复制代码
rules:[
	{
		test: /\.js$/,
		enforce: 'pre',
		use:'eslint-loader',
	}
]

可以看到,在配置中添加了一个eslint-loader来对源码进行质量检测,其enforce的值为"pre",代表它将在所有正常 loader之前执行 ,这样可以保证其检测的代码是被其他loader 更改过的。

类似的,如果某一个loader 是需要在所有 loader 之后执行的也可以指定其enforce为"post"

事实上,我们也可以不使用enforce而只要保证loader顺序是正确的即可

配置enforce 主要的目的是使模块规则更加清晰,可读性更强 ,尤其是在实际工程中,置文件可能达到上百行的情况,难以保证各个loader 都按照预想的方式工作,使用enforce可以强制指定 loader的作用顺序

相关推荐
王解2 分钟前
一篇文章读懂 Prettier CLI 命令:从基础到进阶 (3)
前端·perttier
乐闻x8 分钟前
最佳实践:如何在 Vue.js 项目中使用 Jest 进行单元测试
前端·vue.js·单元测试
檀越剑指大厂22 分钟前
【Python系列】异步 Web 服务器
服务器·前端·python
我是Superman丶24 分钟前
【前端】js vue 屏蔽BackSpace键删除键导致页面后退的方法
开发语言·前端·javascript
Hello Dam26 分钟前
基于 Spring Boot 实现图片的服务器本地存储及前端回显
服务器·前端·spring boot
小仓桑27 分钟前
利用 Vue 组合式 API 与 requestAnimationFrame 优化大量元素渲染
前端·javascript·vue.js
Hacker_xingchen28 分钟前
Web 学习笔记 - 网络安全
前端·笔记·学习
天海奈奈28 分钟前
前端应用界面的展示与优化(记录)
前端
多多*1 小时前
后端并发编程操作简述 Java高并发程序设计 六类并发容器 七种线程池 四种阻塞队列
java·开发语言·前端·数据结构·算法·状态模式
mubeibeinv1 小时前
列表代码思路
前端