loader
loader的本质是一个函数,它的作用是将一个源码字符串转换成另一个源码字符串。

执行时机
loader是在解析模块的过程中被调用的。
在编译过程中,我们知道webpack在读取了文件内容(也就是源码字符串)后会对其进行语法分析,然后将其转换成AST。
实际上更加详细的过程是,webpack会将读取的文件内容交给loader处理,loader处理完后会返回新的源码字符串,然后webpack再对新的源码字符串进行语法分析。

处理流程
- 在读取到文件内容后,webpack会根据loader配置的规则判断当前模块是否满足
- 如果满足,则会读取该规则中对应的loader,然后将读取到的loader函数依次放入到loaders数组中
- 如果不满足,那么loaders数组则为空
- 将源码字符串自右向左(或自下向上)经过loader函数处理得到最终的源码字符串

配置
我们可以通过module.rules字段来配置loader的匹配规则。
完整配置
module.exports = {
module: { // 针对模块的配置,目前版本只有两个配置,rules、noParse
rules: [ // 模块匹配规则,可以存放多个规则
{ // 每个规则对象
test: /\.js$/, // 匹配模块的正则表达式
use: [ // 匹配到后使用的规则模块
{
loader: '模块路径', // loader模块的路径,该字符串会放置到require中
options: {} // 向对应loader传递的额外参数
}
]
}
]
}
}简约配置
module.exports = {
module: {
rules: [
{
test: /\.js$/,
use: ["模块路径1", "模块路径2"]
}
]
}
}案例
处理图片
目录如下:
:::vue
├─loaders | ├─img-loader | | └index.js ├─src | ├─index.js | ├─assets | | └webpack.png | | └penguin.jpg ├─package.json | ├─loader-utils: ^1.2.3 | ├─webpack: ^4.36.1 | ├─webpack-cli: ^3.3.10 ├─webpack.config.js
:::
// img-loader.js
var loaderUtils = require('loader-utils');
function getBase64(buffer, ext) {
return `data:image/${ ext };base64,${ buffer.toString('base64') }`
}
function getFilePath(buffer, name) {
var filename = loaderUtils.interpolateName(this, name, {
content: buffer
});
this.emitFile(filename, buffer); // 生成一个文件
return filename
}
function imgLoader(buffer) {
var { limit = 1000, name = '[name].[ext]' } = loaderUtils.getOptions(this);
var content;
if (buffer.byteLength > limit) {
content = getFilePath.call(this, buffer, name);
} else {
var splitArr = this.resourcePath.split('.');
var ext = splitArr[splitArr.length - 1]; // 获取后缀名
content = getBase64(buffer, ext);
}
return `module.exports = \`${ content }\``
}
// 默认情况下,资源文件(即sourceCode入参)会被转换成utf-8字符串
// 通过设置静态属性raw为true,可以接收原始的Buffer
imgLoader.raw = true;
module.exports = imgLoader;// index.js
var imgSrc = require('./assets/webpack.png');
console.log(imgSrc);
var img = document.createElement('img');
img.src = imgSrc;
document.body.appendChild(img);// webpack.config.js
var path = require('path');
module.exports = {
mode: 'development',
entry: {
main: './src/index.js'
},
output: {
path: path.resolve(__dirname, './dist'),
filename: '[name].js'
},
module: {
rules: [
{
test: /\.(png)|(jpg)|(jpeg)|(gif)$/,
use: [
{
loader: './loaders/img-loader',
options: {
limit: 10000, // 超过10kb使用图片,否则使用base64
name: 'img-[contenthash:5].[ext]'
}
}
]
}
]
},
devtool: 'source-map'
}常用的 loader
1. babel-loader
babel-loader 基于 babel,用于解析 JavaScript 代码。Babel 是一个 JavaScript 编译器,可以将高级语法(主要是 ES6+)编译成浏览器支持的低版本语法,它可以让你使用最新版本的 JavaScript 语法来写代码,提升效率。
# 安装依赖
npm install -D babel-loader @babel/core @babel/preset-envBabel 配置里的两大核心:plugins(插件)和 presets(预设)
Babel 的预设可以被看作是一组 Babel 插件。
Babel 官方针对常用环境开发的一些预设:
- @babel/preset-env for compiling ES2015+ syntax
- @babel/preset-typescript for TypeScript
- @babel/preset-react for React
- @babel/preset-flow for Flow
插件和预设的执行顺序:
- 插件比预设先执行
- 插件执行顺序是插件数组从前向后执行
- 预设执行顺序是预设数组从后向前执行
webpack 配置代码:
// webpack.config.js
module: {
rules: [
{
test: /\.m?js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: [
['@babel/preset-env', { targets: "defaults" }]
],
plugins: ['@babel/plugin-proposal-class-properties'],
cacheDirectory: true,
}
}
}
]
}2. file-loader
file-loader 用于处理资源文件,如 png、gif、svg 等。
// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'file-loader',
options: {
name: 'assets/[name]_[hash:8].[ext]'
},
},
],
},
],
},
};// file.js
import img from './image/png';编译结果:
# result
assets/image_605dc7bf.png3. url-loader
url-loader 用于处理图片资源,根据设定的图片大小来决定将图片打包还是转换成 base64 字符。
// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.(png|jpg|gif)$/i,
use: [
{
loader: 'url-loader',
options: {
limit: 8192
}
}
]
}
]
}
}