引言
什么是loader?
众所周知,webpack是个只能识别js和json文件的小笨蛋,所以就要有loader来转换,让文件能被webpack识别到,从而顺利打包,loader还能对资源进行优化,如压缩图片,代码分割等
常见的loader?
-
babel-loader:把新版的语法(如ES6)降级成低版本代码,让老不死的,IE等浏览器也能识别
-
css-loader:把css代码转成webpack能识别的js格式
-
style-loader: 把解析后的css注入到DOM中
基本上是见名知意,** -loder,就是处理 **的
loader的基本使用
直接一手module.rules,test来筛选要load的文件,如:
const path = require('path'); module.exports = {entry: './src/index.js',output: {filename: 'bundle.js',path: path.resolve(__dirname, 'dist')},module: {rules: [{test: /\.js$/, // 匹配所有 .js 文件exclude: /node_modules/, // 排除 node_modules 目录use: 'babel-loader' // 使用 babel-loader},{test: /\.css$/, // 匹配所有 .css 文件use: ['style-loader', 'css-loader'] // 使用 style-loader 和 css-loader}]} };
单loader和多loader
单loader:
module: {rules: [{test: /\.js$/,exclude: /node_modules/,use: 'babel-loader'}] }
或者:
module: {rules: [{test: /\.js$/,exclude: /node_modules/,use: {loader: 'babel-loader',options: {presets: ['@babel/preset-env']}}}] }
多loader:
``
module: {rules: [{test: /\.css$/,use: ['style-loader', 'css-loader']}] }
或者
module: {rules: [{test: /\.css$/,use: [{loader: 'style-loader',options: {// style-loader 的选项}},{loader: 'css-loader',options: {// css-loader 的选项}}]}] }
Loader 的工作流程
Webpack 的核心功能之一是将各种类型的资源转换为可以在浏览器中运行的模块。Loader 是实现这一功能的关键组件。以下是 Webpack 如何解析文件并将它们传递给 Loader 处理的详细工作流程:
1. 解析入口文件
Webpack 从配置的入口文件开始解析。入口文件通常是 JavaScript 文件,但也可以是其他类型的文件。
2. 依赖分析
Webpack 会分析入口文件及其依赖关系,构建一个依赖图(Dependency Graph)。对于每个模块,Webpack 会检查其 import
或 require
语句,解析出依赖的模块。
3. 匹配 Loader
对于每个模块,Webpack 会根据 module.rules
中的规则匹配相应的 Loader。规则通常基于文件路径的正则表达式。
4. 应用 Loader
一旦匹配到相应的 Loader,Webpack 会按照配置的顺序应用这些 Loader。Loader 的执行顺序是从右到左,从下到上。
5. 处理模块
每个 Loader 都会对模块进行处理,将其转换为新的模块。Loader 可以对模块进行各种操作,如转换、压缩、解析等。
6. 生成最终模块
所有 Loader 处理完成后,Webpack 会生成最终的模块,并将其添加到依赖图中。
7. 重复上述过程
Webpack 会重复上述过程,直到所有模块都被处理完毕。
8. 生成输出文件
最后,Webpack 会根据 output
配置生成输出文件,并将所有模块打包到输出文件中。
扩展:Loader 执行顺序的控制
1. 配置文件中的顺序
在 webpack.config.js
文件中,module.rules
数组中的规则是按顺序匹配的。Loader 的执行顺序是从右到左,从下到上。
例如:
module.exports = {module: {rules: [{test: /\.css$/,use: ['style-loader', 'css-loader']}]} };
在这个例子中,css-loader
会先执行,然后是 style-loader
2. 使用 enforce
属性
enforce
属性可以用来指定 Loader 的执行阶段。它可以设置为 'pre'
、'post'
或默认(不设置)。
-
'pre'
:高优先级,Loader 会先于普通 Loader 和 Inline Loader 执行。 -
默认(不设置):普通优先级,Loader 会执行在
pre
Loader 之后,Inline Loader 之前。 -
'post'
:低优先级,Loader 会执行在所有其他 Loader 之后。
例如:
module.exports = {module: {rules: [{test: /\.js$/,enforce: 'pre',use: 'eslint-loader'},{test: /\.js$/,use: 'babel-loader'},{test: /\.js$/,enforce: 'post',use: 'some-post-loader'}]} };
在这个例子中,执行顺序将是:
1.eslint-loader
(enforce: 'pre'
)
2.babel-loader
(普通 Loader)
3.some-post-loader
(enforce: 'post'
)
3. 使用 Inline Loader
在代码中直接使用 Inline Loader 可以覆盖配置文件中的设置。语法是在 import
语句中使用 !
来分隔不同的 Loader。
例如:
import Styles from 'style-loader!css-loader?modules!./styles.css';
在这个例子中,我们使用了 style-loader
和 css-loader
,并为 css-loader
传递了 modules
参数。
4.inline Loader 使用前缀
在 Inline Loader 中,我们可以使用特定的前缀来进一步控制 Loader 的执行:
-
!
:禁用配置文件中的所有 普通Loader,除了inlineLoader只使用 带pre和post的。 -
!!
:禁用所有 Loader,只使用 Inline Loader。 -
-!
:禁用pre
和普通 Loader,只使用post
Loader 和 Inline Loader。
Loader 的分类
在 Webpack 中,Loader 可以按执行方式分为同步 Loader 和异步 Loader:
-
同步 Loader:同步 Loader 是通过
this.callback
函数或直接返回值完成数据的处理。大部分 Loader 都是同步的,适用于不需要异步操作的场景,比如简单的字符串转换。 -
异步 Loader:异步 Loader 使用
this.async()
方法来通知 Webpack 处理是异步的,这样可以支持异步操作(例如读取文件、访问网络资源)。调用this.async()
会返回一个callback
函数,Loader 执行完毕后调用该函数传递处理结果。
-
raw loader
:处理原始的二进制数据
raw loader
允许直接处理非文本数据,如图片或其他二进制文件。要将 Loader 设置为 raw
型, 可以在 Loader 函数中指定 this.raw = true
,这样 Webpack 会将文件内容以 Buffer
形式传 递给 Loader,而非字符串。
示例:
module.exports = function (source) {if (this.raw) {// source 是 Buffer,可以处理二进制数据const transformedSource = Buffer.from(source).toString('base64');return `module.exports = "${transformedSource}"`;} }; module.exports.raw = true; // 设置为 raw loader
-
pitching loader
:理解 pitch 的概念和作用
Pitch 是 Loader 的一个特殊功能,用于控制 Loader 执行的顺序和中间的交互。通常,Loader 是按照配置的顺序依次执行,但通过 pitch
函数,可以改变 Loader 执行顺序或中断流程。
Pitch 的作用
-
提前处理:在 Loader 开始处理之前做一些预处理工作。
-
跳过后续 Loader:
pitch
方法返回值时,会跳过当前 Loader 及其后的 Loader,直接将结果传递给前面的 Loader。 -
中断或优化加载流程:可以用于缓存、绕过 Loader 或添加额外的前置逻辑。
Pitch 示例
module.exports = function (source) {return source; }; module.exports.pitch = function (remainingRequest, previousRequest, data) {if (/* 某个条件满足 */) {return `module.exports = "跳过其他 loader";`;}// 否则继续执行下一个 loader };
在这个例子中,当 pitch
函数的条件满足时,会返回一个结果从而跳过当前及后续的所有 Loader,从而直接返回给 Webpack。
Loader 的实现原理
在 Webpack 中,Loader 是一个导出函数,通过该函数可以对输入的文件内容进行处理并输出。Loader 本质上是一个函数,接受输入内容并返回处理后的内容,最终让 Webpack 能够理解并打包各种文件类型。Loader 可以通过 module.exports
导出,在 Webpack 构建过程中会自动调用这个函数处理指定类型的文件。
module.exports = function(content, map, meta)
参数说明
module.exports
中导出的函数的主要参数有三个:
-
content
:文件的内容,这是 Loader 接收到的待处理的原始内容。对于文本文件,这通常是字符串;对于raw
类型的 Loader,它可以是Buffer
(用于处理二进制文件)。 -
map
:可选参数,表示文件的 Source Map。当源文件已经包含 Source Map 时,Webpack 会将它作为map
传入,以便 Loader 能在转换内容的同时,修改 Source Map。生成和维护 Source Map 可以帮助更好地调试代码。 -
meta
:可选参数,用于传递 Loader 之间的元数据。多个 Loader 可能需要共享或传递信息给下一个 Loader。该参数通常在复杂场景中使用,例如需要共享状态的 Loader。
总结
loader像是个翻译官,把各种各样的文件翻译成webpack看得懂的样子,实际上是个导出函数