loader的配置,执行顺序,和loader中的pitch
这一节看一下loader的配置
- loader的调用顺序
- 前置loader、 pre
- 后置loader、post
- 正常loader、normal
- 行内loader、直接写在代码里
- loader的阻断,pich
loader的执行顺序
前置工作,新建loader1、loader2、loader3
新建loader1
// webpack\webpack-loader\loaders\loader1.js
// loader其实就是一个构造函数
function loader(source) { //loader的参数就是源代码
console.log('loader1 执行了');
return source
}
module.exports = loader
新建loader2
// webpack\webpack-loader\loaders\loader2.js
// loader其实就是一个构造函数
function loader(source) { //loader的参数就是源代码
console.log('loader2 执行了');
return source
}
module.exports = loader
新建loader3
// webpack\webpack-loader\loaders\loader3.js
// loader其实就是一个构造函数
function loader(source) { //loader的参数就是源代码
console.log('loader3 执行了');
return source
}
module.exports = loader
默认的顺序
从下到上,从右到左
从右向左
修改配置文件
// webpack\webpack-loader\webpack.config.js
let path = require('path')
module.exports = {
mode: 'development',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js'
},
module: {
rules: [
{
test: /\.js$/,
use: ['loader3', 'loader2', 'loader1'] // loader从右向左执行
},
]
},
resolveLoader: {
// 找loader的时候,先从node_modules中找,找不到再从我们的loaders目录下找
modules: ['node_modules', path.resolve(__dirname, 'loaders')]
/* alias: { // loader的别名
loader1: path.resolve(__dirname, 'loaders', 'loader1.js')
} */
}
}
这时候运行一下,发现是从右向左执行loader,npx webpack
从下向上
修改配置文件
// webpack\webpack-loader\webpack.config.js
let path = require('path')
module.exports = {
mode: 'development',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js'
},
module: {
rules: [
// 从下向上执行 所以 应该是 loader3 loader2 loader1
{
test: /\.js$/,
use: {
loader: 'loader1'
}
},
{
test: /\.js$/,
use: {
loader: 'loader2'
}
},
{
test: /\.js$/,
use: {
loader: 'loader3'
}
},
]
},
resolveLoader: {
// 找loader的时候,先从node_modules中找,找不到再从我们的loaders目录下找
modules: ['node_modules', path.resolve(__dirname, 'loaders')]
/* alias: { // loader的别名
loader1: path.resolve(__dirname, 'loaders', 'loader1.js')
} */
}
}
执行看下结果
改变执行顺序,enforce
pre、post
// webpack\webpack-loader\webpack.config.js
let path = require('path')
module.exports = {
mode: 'development',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js'
},
module: {
rules: [
// 从下向上执行 所以 应该是 3 2 1
// 但是可以强制改变执行顺序 pre normal post
// 改变之后就变成了 1 2 3
{
test: /\.js$/,
use: {
loader: 'loader1'
},
enforce: 'pre', // 最先执行
},
{
test: /\.js$/,
use: {
loader: 'loader2'
},
},
{
test: /\.js$/,
use: {
loader: 'loader3'
},
enforce: 'post', // 最后执行
},
]
},
resolveLoader: {
// 找loader的时候,先从node_modules中找,找不到再从我们的loaders目录下找
modules: ['node_modules', path.resolve(__dirname, 'loaders')]
/* alias: { // loader的别名
loader1: path.resolve(__dirname, 'loaders', 'loader1.js')
} */
}
}
执行一下看下结果 npx webpack
另一种loader,行内loader,inline
新建一个loader
// webpack\webpack-loader\loaders\inline-loader.js
// loader其实就是一个构造函数
function loader(source) { //loader的参数就是源代码
console.log('inline-loader 执行了');
return source
}
module.exports = loader
新建一个模块
// webpack\webpack-loader\src\a.js
module.exports = 'aaa'
行内loader的几种写法
index.js中引入这个模块,使用行内loader的方式加载这个模块
使用inline-loader加载这个a.js这个模块
// webpack\webpack-loader\src\index.js
console.log('cheny && xzz');
// 使用! 表示将 a.js 这个模块 导给前面的loader
// 加载loader时的顺序 pre、normal、inline、post
require('inline-loader!./a.js')
这时候看一下结果
所以loader的执行顺序为,pre、normal、inline、post
-! 会排除掉pre和normal,只执行inline和post
// webpack\webpack-loader\src\index.js
console.log('cheny && xzz');
// 使用! 表示将 a.js 这个模块 导给前面的loader
// 加载loader时的顺序 pre、normal、inline、post
// require('inline-loader!./a.js')
// -! 会排除掉 pre和normal 只执行 inline、post
require('-!inline-loader!./a.js')
! 会排除掉normal,只执行 pre、inline、post
// webpack\webpack-loader\src\index.js
console.log('cheny && xzz');
// 使用! 表示将 a.js 这个模块 导给前面的loader
// 加载loader时的顺序 pre、normal、inline、post
// require('inline-loader!./a.js')
// -! 会排除掉 pre和normal 只执行 inline、post
// require('-!inline-loader!./a.js')
// ! 会排除掉 normal 只执行 pre inline、post
require('!inline-loader!./a.js')
!! 会排除掉 pre、normal、post,只执行inline
// webpack\webpack-loader\src\index.js
console.log('cheny && xzz');
// 使用! 表示将 a.js 这个模块 导给前面的loader
// 加载loader时的顺序 pre、normal、inline、post
// require('inline-loader!./a.js')
// -! 会排除掉 pre和normal 只执行 inline、post
// require('-!inline-loader!./a.js')
// ! 会排除掉 normal 只执行 pre inline、post
// require('!inline-loader!./a.js')
// !! 会排除掉 pre、normal和post 只执行 inline
require('!!inline-loader!./a.js')
loader的Pitch,有一个阻断的作用
假设loader是 ['loader3','loader2','loader1']
如果Loader的Pitch方法没有返回值时,会先按顺序执行,3,2,1,加载到资源后,再将资源一次传入1,2,3
但是当loader的Pitch有返回值时,就不一样了,比如
loader2有返回值,然后就直接执行前一个loader3,不再继续向下执行了。
例子
其实看一下上面的图就知道结果了,就是当有PItch方法时,loader的返回值就直接是Pitch中的返回值,并不继续向下执行了
修改配置文件
// webpack\webpack-loader\webpack.config.js
let path = require('path')
module.exports = {
mode: 'development',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js'
},
module: {
rules: [
{
test: /\.js$/,
use: ['loader3', 'loader2', 'loader1']
}
]
},
resolveLoader: {
// 找loader的时候,先从node_modules中找,找不到再从我们的loaders目录下找
modules: ['node_modules', path.resolve(__dirname, 'loaders')]
/* alias: { // loader的别名
loader1: path.resolve(__dirname, 'loaders', 'loader1.js')
} */
}
}
修改三个loader
loader1
// webpack\webpack-loader\loaders\loader1.js
// loader其实就是一个构造函数
function loader(source) { //loader的参数就是源代码
console.log('loader1 执行了');
return source
}
loader.pitch = function () {
return '111'
}
module.exports = loader
loader2
// webpack\webpack-loader\loaders\loader2.js
// loader其实就是一个构造函数
function loader(source) { //loader的参数就是源代码
console.log('loader2 执行了');
return source
}
loader.pitch = function () {
return '222'
}
module.exports = loader
loader3
// webpack\webpack-loader\loaders\loader3.js
// loader其实就是一个构造函数
function loader(source) { //loader的参数就是源代码
console.log('loader3 执行了');
return source
}
loader.pitch = function () {
return '333'
}
module.exports = loader
修改index.js
// webpack\webpack-loader\src\index.js
console.log('cheny && xzz');
配置文件中我们配置的use: ['loader3', 'loader2', 'loader1']
,按照正常顺序,会从右向左执行,但是因为loader3的pitch有返回值,所有直接就返回了结果。
最后打包的结果就是loader3中pitch的返回值
假如把loader3的pitch注释掉,loader2和loader2的pitch有返回值,我们看下效果
// webpack\webpack-loader\loaders\loader3.js
// loader其实就是一个构造函数
function loader(source) { //loader的参数就是源代码
console.log('loader3 执行了');
return source
}
/* loader.pitch = function () {
return '333'
} */
module.exports = loader
看到loader3是正常执行了,但是因为loader2的pitch有返回值,所有代码最终的打包结果是loader2中的返回值
所以,loader的pitch方法实际就是一个阻断的作用,可以让loader提前返回结果,不再向下执行。
总结
webpack中可以自定义loader来实现解析其他后缀的文件,比如css、less等。
自己写一个最简单的loader
js// webpack\webpack-loader\loaders\loader1.js // loader其实就是一个构造函数 function loader(source) { //loader的参数就是源代码 console.log('loader1 执行了'); return source } module.exports = loader
在webpack的配置文件中,想要加载自定义loader有三种方式(上一节的内容)
- 写loader的时候直接写全局路径
- 给loader起别名
- 告诉webpack加载loader的时候,如果node_modules没有,就去自己定义loader的目录下找
webpack中的loader执行顺序,默认是从下向上,从右向左,不过可以通过配置enforce来改变执行顺序
- 默认啥也不配的loader执行顺序就是默认顺序(从下向上,从右向左),normal
- enforce: 'pre',最先执行的loader
- enforce: 'post',最后执行的loader
还有一种loader叫做内联loader,是在代码内部嵌套着
代码中加载某个模块的时候,直接指定使用某个loader加载
js// 使用! 表示将 a.js 这个模块 导给前面的loader // 加载loader时的顺序 pre、normal、inline、post require('inline-loader!./a.js')
如果引入了内联loader,那么loader的执行顺序就变成了
pre、normal、inline、post
屏蔽pre和normal,只执行inline和post的内联loader
js// -! 会排除掉 pre和normal 只执行 inline、post require('-!inline-loader!./a.js')
屏蔽normal,只执行pre、inline和post的内联loader
js// ! 会排除掉 normal 只执行 pre inline、post require('!inline-loader!./a.js')
屏蔽所有,只执行inline的内联loader
js// !! 会排除掉 pre、normal和post 只执行 inline require('!!inline-loader!./a.js')
webpack中自定义的loader还可以在构造方法中,挂载一个pitch方法,起到一个阻断的作用
- 如果配置文件中loader的配置顺序为
use: ['loader3','loader2','loader1']
- 默认上面的配置,会从右向左执行loader
- 假如loader3中有pitch方法,并且有返回值,所有的loader都不会再执行,直接返回这个返回值
- 如果loader3的pitch没有返回值,loader2有返回值,那么会只执行loader3,loader3接收的代码是loader2中pitch的返回值
- 其他同理
- 如果配置文件中loader的配置顺序为
参考
https://www.bilibili.com/video/BV1a4411e7Bz?p=41&spm_id_from=pageDriver