作用
- webpack只会处理js、json文件,当需要处理其它类型的文件就需要添加对应的loader
- 在使用require()/import语句时,先用对应的loader处理后,再加入打包后的boundle中
基本使用
- test:匹配要处理的文件
- /.txt$/:匹配任何以 .txt 结尾的文件
- “/.txt$/”: 匹配具有绝对路径 ‘.txt’ 的单个文件
- use:添加处理的loader
- 同一个use中loader处理顺序为从右到左,从下到上
module.exports = {
output: {
filename: 'my-first-webpack.bundle.js',
},
module: {
rules: [{ test: /\.txt$/, use: 'raw-loader' }],
},
};
- 为 import 语句添加前缀启动指定类型loader
- “!”禁止所有普通loader
- “!!”禁止preLoaders、loaders、postLoaders
- “-!”禁止preLoaders、loaders
// 禁用普通 loaders
import { a } from '!./file1.js';
// 禁用前置和普通 loaders
import { b } from '-!./file2.js';
// 禁用所有的 laoders
import { c } from '!!./file3.js';
内联loader
- 使用 ! 将资源中的 loader 分开。loader加载顺序和上方相同
- 传递loader参数使用?key=value&foo=bar或者{key":“value”,“foo”:“bar”}.
import Styles from 'style-loader!css-loader?modules!./styles.css';
- 为内联 import 语句添加前缀启动指定类型loader
- “!”禁止所有普通loader
- “!!”禁止preLoaders、loaders、postLoaders
- “-!”禁止preLoaders、loaders
import Styles from '!style-loader!css-loader?modules!./styles.css';
import Styles from '!!style-loader!css-loader?modules!./styles.css';
import Styles from '-!style-loader!css-loader?modules!./styles.css';
loader执行顺序
Loader 之间按照配置的顺序从前到后先执行 pitch 方法,再从后到前依次执行主方法
module.exports = {
module: {
rules: [
{
test: /\.less$/i,
use: [
"style-loader",
"css-loader",
"less-loader",
],
},
],
},
};
![在这里插入图片描述](https://img-blog.csdnimg.cn/c3cb801659e34cc5b69a6aa278db83fc.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/f0a8656950734732b0267668711a2e7c.png)
loader pitch
- loader.pitch 出现的原因:
- Loader 链条一旦启动之后,需要所有 Loader 都执行完毕才会结束,没有中断的机会 —— 除非显式抛出异常
- 某些场景下并不需要关心资源的具体内容,但 Loader 需要在 source 内容被读取出来之后才会执行
const loader = function (source){
console.log('后执行')
return source;
}
loader.pitch = function(remainingRequest: string, previousRequest: string, data) {
console.log('先执行')
}
module.exports = loader
- remainingRequest : 当前 loader 之后的资源请求字符串
- previousRequest : 在执行当前 loader 之前经历过的 loader 列表
- data : 与 Loader 函数的 data 相同,用于传递需要在 Loader 传播的信息
module.exports = {
module: {
rules: [
{
test: /\.less$/i,
use: [
"style-loader", "css-loader", "less-loader"
],
},
],
},
};
// css-loader.pitch 中拿到的参数依次为:
// css-loader 之后的 loader 列表及资源路径
remainingRequest = less-loader!./xxx.less
// css-loader 之前的 loader 列表
previousRequest = style-loader
// 默认值
data = {}
![在这里插入图片描述](https://img-blog.csdnimg.cn/59974589cdc74ad68fa025e60631142b.png)
-
pitch示例
- less-loader :将 less 规格的内容转换为标准 css
- css-loader :将 css 内容包裹为 JavaScript 模块
- style-loader :将 JavaScript 模块的导出结果以 link 、style 标签等方式挂载到 html 中,让 css 代码能够正确运行在浏览器上
- style-loader 只是负责让 css 能够在浏览器环境下跑起来,本质上并不需要关心具体内容,很适合用 pitch 来处理
//style-loader pitch处理后结果,可以看到具体内容的转换交给其他loader进行处理
var api = require('xxx/style-loader/lib/runtime/injectStylesIntoLinkTag.js')
var content = require('!!css-loader!less-loader!./xxx.less');
![在这里插入图片描述](https://img-blog.csdnimg.cn/f6532815795f4fbeb07166636a46d739.png)
- 所以从 webpack 的角度看,实际上对同一个文件调用了两次 loader 链,第一次在 style-loader 的 pitch 中断,第二次根据 inline loader 的内容跳过了 style-loader。
自定义loader
// 方法1:直接给loader指定绝对路径
const path = require('path')
module: {
rules: [
{
test: /\.js$/,
loader: path.resolve(__dirname, 'loader/babel-loader.js'),
exclude: /node_modules/
}
]
}
// 方法2:配置resolveLoader的别名与其绝对路径,然后在rules中直接使用别名
const path = require('path')
resolveLoader: {
alias: {
'babel-loader': path.resolve(__dirname, 'loader/babel-loader.js')
}
},
module: {
rules: [
{
test: /\.js$/,
use: 'babel-loader',
exclude: /node_modules/
}
]
}
// 方法3:配置resolveLoader的模块,通过修改loader查找的目录(默认在node_modules文件中查找)
const path = require('path')
resolveLoader: {
// 优先使用我们自定义的loader目录中的loader
modules: [path.resolve(__dirname, 'loader'), path.resolve(__dirname, 'node_modules')]
},
module: {
rules: [
{
test: /\.js$/,
use: 'babel-loader',
exclude: /node_modules/
}
]
}
module.exports = function(source, sourceMap?, data?) {
// source 为 loader 的输入,可能是文件内容,也可能是上一个 loader 处理结果
return source;
};
-
source:资源输入,对于第一个执行的 loader 为资源文件的内容;后续执行的 loader 则为前一个 loader 的执行结果
-
sourceMap: 可选参数,代码的 sourcemap 结构
-
data: 可选参数,其它需要在 Loader 链中传递的信息,比如 posthtml/posthtml-loader 就会通过这个参数传递参数的 AST 对象
-
同步loader
-
return方式
export default function rawLoader(source) {
// ...
const json = JSON.stringify(source)
.replace(/\u2028/g, '\\u2028')
.replace(/\u2029/g, '\\u2029');
const esModule =
typeof options.esModule !== 'undefined' ? options.esModule : true;
return `${esModule ? 'export default' : 'module.exports ='} ${json};`;
}
export default function loader(content, map) {
// ...
linter.printOutput(linter.lint(content));
this.callback(null, content, map);
}
// this.callback 的完整签名如下
this.callback(
// 异常信息,Loader 正常运行时传递 null 值即可
err: Error | null,
// 转译结果
content: string | Buffer,
// 源码的 sourcemap 信息
sourceMap?: SourceMap,
// 任意需要在 Loader 间传递的值
// 经常用来传递 ast 对象,避免重复解析
data?: any
);
import less from "less";
async function lessLoader(source) {
// 1. 获取异步回调函数,this.async 返回的异步回调函数签名与 this.callback 相同
const callback = this.async();
// ...
let result;
try {
// 2. 调用less 将模块内容转译为 css
result = await (options.implementation || less).render(data, lessOptions);
} catch (error) {
// ...
}
const { css, imports } = result;
// ...
// 3. 转译结束,返回结果
callback(null, css, map);
}
export default lessLoader;
-
缓存
- 默认情况下 Webpack 会缓存 Loader 的执行结果直到资源或资源依赖发生变化
- 必要时可以通过 this.cachable 显式声明不作缓存
module.exports = function(source) {
this.cacheable(false);
// ...
return output;
};
const loaderContext = {
// 获取当前 Loader 的配置信息
getOptions: schema => {},
// 添加警告
emitWarning: warning => {},
// 添加错误信息,注意这不会中断 Webpack 运行
emitError: error => {},
// 解析资源文件的具体路径
resolve(context, request, callback) {},
// 直接提交文件,提交的文件不会经过后续的chunk、module处理,直接输出到 fs
emitFile: (name, content, sourceMap, assetInfo) => {},
// 添加额外的依赖文件
// watch 模式下,添加的依赖文件发生变化时会触发资源重新编译
addDependency(dep) {},
};
-
addDependency 在 less loader的使用
try {
result = await (options.implementation || less).render(data, lessOptions);
} catch (error) {
// ...
}
const { css, imports } = result;
imports.forEach((item) => {
// 调用 this.addDependency 函数将 import 到的其它资源都注册为依赖,之后这些其它资源文件发生变化时都会触发重新编译。
this.addDependency(path.normalize(item)); // /Users/xx/Desktop/webpack/wb/src/css/5.less"
});
-
loader常用工具
-
loader-utils
- 提供了一系列诸如读取配置、requestString 序列化与反序列化、计算 hash 值之类的工具函数
-
schema-utils