loader 概述
到目前为止,我们的案例都是都是介绍的如何打包 js 文件,对于工程中的其他类型资源,如 CSS、图片、字体等, webpack 会如何处理呢?在实际的项目开发中,我们经常会用到 Sass 或者 Less 来编写样式,我们使用 Typescript 增加静态类型检查,我们使用浏览器不支持的 ECMAScript 新特性,如何让 webpack 来对所有的编译进行统一管理呢?
本章我们会介绍 loader(预处理器),它赋予了 webpack 可以处理不同资源的能力,极大丰富了其可扩展性。
loader 作用
在 webpack 中,一切皆模块,我们可以使用 import、require 等方式 在JavaScript 模块中导入 JS、CSS、图片、字体等多种类型的静态资源,loader 用于对模块的源代码进行转换。loader 可以使我们在导入模块时预处理文件。loader 可以将文件从不同的语言(如 TypeScript)转换为 JavaScript。loader 甚至允许我们直接在 JavaScript 模块中 import CSS 文件!
loader 本质上是 node module 导出的一个函数,当资源需要被转换时,调用这个函数。下面我们通过自定义 loader,来看 loader 的使用方法。
src/index.js
const demoName = 'webpack loader'
console.log(demoName)
webpack 默认支持解析 js 文件,我们增加解析 js 的 loader 只为展示 loader 是如何工作的
src/js-loader.js
module.exports = function (source) {
console.log(source)
return `module.exports=${JSON.stringify(source)}`
}
webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
mode: 'development',
entry: {
index: './src/index.js'
},
output: {
filename: '[name].js',
clean: true
},
plugins: [
new HtmlWebpackPlugin({
title: 'loader',
}),
],
module: {
rules: [
{
test: /\.js$/,
use: "./src/js-loader.js"
}
]
}
};
执行构建命令,在控制台可以看到 js-loader 文件的 console.log 输出了 index.js 文件内容,从上面的 简易版 js-loader.js 文件中可以看出,loader 本身就是一个函数,在该函数中对接收的内容进行转换,然后返回转换后的结果。
loader 使用方式配置
在我们的应用中,有两种使用 loader 的方式,分别是 配置方式(推荐),内联方式。
配置方式(推荐)
module.rules 允许我们在 webpack 配置中指定多个 loader。 这种方式是展示 loader 的一种简明方式,并且有助于使代码变得简洁和易于维护。同时让我们对各个 loader 有个全局概览:
loader 从右到左(或从下到上)地取值(evaluate)/执行(execute)。在下面的示例中,从 css-loader 开始执行,最后以 style-loader 为结束。
webpack.config.js
module.exports = {
...
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader','css-loader']
}
]
}
};
src/index.js
import './index.css';
src/index.css
body {
color: red;
padding: 20px;
text-align: center;
}
index.html
...
<body>
<div>import css</div>
<script src='./dist/index.js'></script>
</body>
webpack 无法处理 CSS 语法,此时我们执行打包命令 控制台会报 “请使用合适的loader来处理这个文件类型”
下面我们将 css-loader,style-loader 加到工程中,loader 都是一些第三方 npm 模块,webpack 本身不包含任何 loader, 所以使用前我们需要先安装这些 loader,在工程中执行以下命令安装。
npm install css-loader style-loader
安装成功后,在控制台执行打包命令,我们可以看到错误已经消失了,在浏览器打开index.html 文件我们可以看到,样式正常展示。
内联方式
loader 除了使用配置的方式,还有一种内联的用法,可以在 import 语句或任何 与 "import" 方法同等的引用方式 中指定 loader。使用 ! 将资源中的 loader 分开。每个部分都会相对于当前目录解析。
在上面的例子中,我们注释掉 webpack.config.js 中 module.rules 的配置,将引入方式改为内联方式。
src/index.js
import '!style-loader!css-loader!./index.css';
执行打包命令后,我们在浏览器中打开 index.html 文件,可以看到样式正常显示。我们在工程中尽可能使用 module.rules,因为这样可以减少源码中的代码量,并且可以在出错时,更快地调试和定位 loader 中的问题。
loader 特性
html-loader
html-loader 用于将 html 文件转换为字符串,支持压缩、导出、对内容预处理。下面让我们来看一个例子
使用
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>html-loader</title>
</head>
<body>
<img src="./src/assets/card-mark.png" />
</body>
</html>
webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
...
plugins: [
new HtmlWebpackPlugin({
// 使用 index.html 内容作为输出模版
template: "./index.html",
}),
],
在index.html 中我们使用 img 标签展示一张图片,图片为相对路径,在 src/assets 文件夹下增加名为 card-mark.png 的图片,在浏览器直接打开 index.html 我们可以看到,图片可以正常展示。
此时我们在控制台执行打包命令 npm run build,在 dist 文件夹中 输出了 index.html 文件,我们直接在浏览器打开 index.html 文件,此时图片无法打开。
图片打不开的原因为 src 地址使用了相对路径,dist 文件夹与 src 文件夹同目录,所以 src="./src/assets/card-mark.png" 这个地址无法找到图片,导致图片无法展示。此时我们就可以借助 html-loader 来帮我们解决这个问题。
安装 html-loader
npm install html-loader -D
安装成功后,将 html-loader 配置到 webpack.config.js 中
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
...
plugins: [
new HtmlWebpackPlugin({
template: "./index.html",
}),
],
module: {
rules: [
{
test: /\.html$/,
use: {
loader: 'html-loader',
}
}
]
}
};
此时在执行打包命令,可以看到在 dist 文件夹下除了index.html 文件和 index.js 文件,又多了一个 扩展名为 .png 的文件,我们打开 dist 文件夹下的 index.html 发现 src 的引用地址已修改,此时在浏览器中直接打开 dist 文件夹下的 index.html 发现图片可以正常显示。
配置项
html-loader 包含下面四个配置项
sources
sources 默认值为 true
webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.html$/,
loader: "html-loader",
options: {
// 设置为 false 则不会对可加载属性做任何处理
sources: false,
},
},
],
},
};
默认情况下,每个可加载属性(例如 img 图片导入)都将被导入( const img = require ('./image.png') 或 import img from "./image.png" )。 你可能需要为配置中的图片指定 loader(我们前面的例子,如果配置 html-loader 的参数 esModule: false,则需要使用 loader 对图片进行处理,否则打包报错)。
html-loader 支持处理的 可加载属性 包括:
source 设置为 Object
webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.html$/,
loader: "html-loader",
options: {
sources: {
list: [
{
tag: "img",
attribute: "data-src",
type: "src",
}
]
},
},
},
],
},
};
index.html
<body>
<img data-src="./src/assets/card-mark.png" src="./src/assets/card-mark.png" />
</body>
执行打包命令,看下 dist 文件夹下的 index.html 文件,发现 html-loader 只对 img 标签的 data-src 属性做了转换。
sources 对象中 支持 list 和 urlFilter 属性,详情可查看文档
preprocessor
允许在处理之前对内容进行预处理。
webpack.config.js
const Handlebars = require("handlebars");
module.exports = {
module: {
rules: [
{
test: /\.html$/,
use: {
loader: 'html-loader',
options: {
preprocessor: (content, loaderContext) => {
let result;
try {
result = Handlebars.compile(content)({
firstname: "Value",
lastname: "OtherValue",
});
} catch (error) {
loaderContext.emitError(error);
return content;
}
return result;
}
}
}
},
},
],
},
};
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>html-loader</title>
</head>
<body>
<p>{{firstname}} {{lastname}}</p>
<img src="./src/assets/card-mark.png" />
</body>
</html>
在 webpack.config.js 中我们使用了 handlebars ,需要先安装 handlebars。
Handlebars 是一种简单的模板语言。
它使用模板和输入对象来生成 HTML 或其他文本格式。Handlebars 模板看起来像带有嵌入式 Handlebars 表达式的常规文本。
<p>{{firstname}} {{lastname}}</p>
执行打包命令后,查看 dist 文件夹下的 index.html 文件,可以看到 p 标签内容已被替换。
minimize
告诉 html-loader 编译时需要压缩 HTML 字符串。
默认情况下,启用压缩的规则如下:
({
caseSensitive: true,
collapseWhitespace: true,
conservativeCollapse: true,
keepClosingSlash: true,
minifyCSS: true,
minifyJS: true,
removeComments: true,
removeRedundantAttributes: true,
removeScriptTypeAttributes: true,
removeStyleLinkTypeAttributes: true,
});
webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.html$/i,
loader: "html-loader",
options: {
// boolean
minimize: true,
// 对象
minimize: {
removeComments: false,
collapseWhitespace: false,
},
},
},
],
},
};
esModule
默认情况下, html-loader 生成使用 ES modules 语法的 JS 模块。 在某些情况下,使用 ES modules 会更好,例如在进行模块合并和 tree shaking 时。
你可以使用以下方法启用 CommonJS 模块语法:
webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.html$/i,
loader: "html-loader",
options: {
esModule: false,
},
},
],
},
};
总结
本节我们介绍了 html-loader 的使用方法和 html-loader 包含的 4 个参数 sources、preprocessor、minimize、esModule, 它们分别对应 html-loader 在项目实践中的 4 个重要功能:
url-loader
当我们在文件中加载图片、字体等资源时,webpack 无法直接处理以上资源,在 webpack 5 之前需要使用相应 loader 来处理资源文件,url-loader 可以将一个文件转换为 base64 编码来代替访问地址,这样做的好处是可以减少一次网络请求,下面我们来看看如何使用 url-loader 及 url-loader 有哪些常用配置。
使用
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>url-loader</title>
</head>
<body>
</body>
</html>
index.js
index.js 文件中引入一张图片,创建image标签后,将导入的图片赋值给 image 标签的 src 属性,将 image 标签添加到页面中
import Back from './img/back.png';
function component() {
var element = document.createElement('img');
element.src=Back
return element;
}
document.body.appendChild(component());
安装 url-loader
npm install url-loader -D
安装成功后,将 url-loader 配置到 webpack.config.js 中
module.exports = {
...
module: {
rules: [
{
test: /\.(png|jpg)$/,
use: [
{
loader: 'url-loader'
}
]
}
]
}
};
此时在执行打包命令,此时在浏览器中直接打开 dist 文件夹下的 index.html 发现页面中展示一张图片。
配置项
url-loader 包含下面 3 个配置项
limit
webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.(png|jpg)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 2048 // 2Kb
}
}
]
}
]
}
};
一般情况下,当资源文件大小小于 2Kb 时,我们需要将资源路径转换为 base64 的格式将资源打包到 bundle 中,这样可以减少一次网络请求,当一个页面中引入多个资源文件时可以明显减少请求次数,但这种方式带来了另外一个问题,如果资源文件体积较大,就会导致 bundle 的体积增大,体积大的情况下网络请求时间变长,会导致页面白屏时间变长,非常影响用户体验。所以在处理资源文件时,一般会加上 limit 配置,文件资源体积超过配置的大小后,更改资源文件的处理方式,默认使用 file-loader 来处理。
上面的配置在执行打包命令时会报 “Cannot find module 'file-loader'” 的错误,所以在使用 limit 配置时,我们先下载安装 file-loader。
安装 file-loader
npm install file-loader -D
再次执行打包命令,在 dist 文件夹下输出了一个扩展名为 .png 的图片,让我们来对比下增加 limit 配置前和增加 limit 配置后 dist 文件夹和 index.js 文件的变化。
增加 limit 配置前
dist 文件夹
index.js
增加 limit 配置后
dist 文件夹
index.js
mimetype
设置文件的转换类型。如果未指定,将使用文件扩展名来查找MIME 类型。
webpack.config.js
rules: [
{
test: /\.(png|jpg)$/,
use: [
{
loader: 'url-loader',
options: {
mimetype: 'image/jpg'
}
}
]
}
]
fallback
指定当目标文件的大小等于或超过限制选项中设置的限制时,使用的替代加载 loader,默认为 file-loader。
module: {
rules: [
{
test: /\.(png|jpg)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 2048,
fallback: 'responsive-loader'
}
}
]
}
]
}
总结
本节我们介绍了 url-loader 的使用方法和 url-loader 包含的 3 个参数 limit、minitype、fallback, url-loader 设置了 limit 参数后,超过设置的限制大小后,默认使用 file-loader 加载资源文件,所以 file-loader 的可配置参数在 url-loader 中也可配置生效,剩余可配置参数在 file-loader 中继续总结。
file-loader
在 webpack 5 之前处理图片、字体等资源,除了使用 url-loader 之外还经常使用 file-loader,file-loader 的处理方式和 url-loader 有些不同,url-loader 通过 limit 参数判断如果没有超过配置大小,则将文件转做 base64 编码,直接嵌入到 CSS/JS/HTML 代码中。而 file-loader 并不会对文件内容进行任何转换,只是复制一份文件内容,并根据配置为他生成一个唯一的文件名, 下面让我们梳理下 file-loader 如何使用及有哪些可配置参数。我们继续使用 url-loader 的例子, 只是对个别配置做些修改。
使用
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>file-loader</title>
</head>
<body>
</body>
</html>
index.js
index.js 文件中引入一张图片,创建 image 标签后,将导入的图片赋值给 image 标签的 src 属性,将 image 标签添加到页面中。
import Back from './img/back.png';
function component() {
var element = document.createElement('img');
element.src=Back
return element;
}
document.body.appendChild(component());
安装 file-loader
npm install file-loader -D
安装成功后,将 file-loader 配置到 webpack.config.js 中
module.exports = {
...
module: {
rules: [
{
test: /\.(png|jpg)$/,
use: [
{
loader: 'file-loader'
}
]
}
]
}
};
执行打包命令,此时在浏览器中直接打开 dist 文件夹下的 index.html 发现页面中展示一张图片,此时我们在 dist 目录下可以看到一张扩展名为 .png 的图片,直接点击图片打开,可以看到与我们引入的图片一致。
配置项
file-loader 包含下面几个配置项
name
可以使用查询参数名称为您的文件配置一个自定义的文件名模板。默认情况下,不配置 name 属性生成的文件的文件名就是文件内容的 MD5 哈希值与原始扩展名。name 属性支持传入字符串或函数配置。
webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.(png|jpg)$/,
use: [
{
loader: 'file-loader',
options: {
name: [name].[ext]
}
}
]
}
]
}
};
name 参数可以传入以下常用占位符
常见的打包命名方式是:assets/[name]-[hash].[ext],即将所有 file-loader 处理的图片按照 name 传入的文件名称 + hash 值.扩展名的方式打包到 assets 目录下。其中
context
修改打包文件生成路径,其实影响的 是 path 占位符,context 需要和 path 占位符同时配置才会影响文件生成路径。
webpack.config.js
{
loader: 'file-loader',
options: {
name: '[path][name].[ext]',
context: __dirname + '/../'
}
}
打包后,当前项目根文件夹和图片所在路径形成了打包文件的新路径,如果不设置 context 则打包路径相对于 webpack.config.js 的 context 的路径。
publicPath
publicPath 一般会用 webpack 本身配置的,和那个效果也一样,但假如你想单独配置,就用这个。设置 publicPath 后,文件的请求地址会被打包进 js 文件。
webpack.config.js
{
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'https://www.abc.cn/img/'
}
}
outputPath
outputPath 在文件前增加路径,也就是增加文件夹。
webpack.config.js
{
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'images/'
}
}
总结
本节我们介绍了 file-loader 的使用方法和 file-loader 包含的几个常用参数配置。file-loader 的可配置选项在 url-loader 中配置也可生效(limit 生效的情况下),在 webpack5 以前对于资源文件的处理一般使用这两种插件,webpack5 提供了一种模块Asset Modules,它允许人们在不配置额外加载器的情况下使用资源文件(字体、图标等)
阅读量:2007
点赞量:0
收藏量:0