1. loader 开发场景
当在项目中需要对我们的文件进行处理,但是现有loader无法满足要求的时候, 那么自己开发一个loader,就显得比较重要了。比如,我们在开发组件库中,要想使用markdown组成网站的一个个功能介绍页面。在我们的markdown文件中,需要新创建一个自定义标签,用于国际化,比如必须使用一个<chn>
标签, 但这个标签,实际上现有的markdown loader是不支持的, 那么就需要新加一个loader,来进行标签的解析。
2. 本文的讨论深度
本文并不是介绍webpack loader的源码实现, 重点放在我们怎么开发一个可正常运行的loader。 所以下面开始对loader进行一些分析。
3. webpack中loader的分类
在webpack的loader中,其实是分为这几类的:
- pre 前置, 会优先执行
- post 后置, 会最后执行
- normal 普通
- inline 行内
涉及的是loader的执行顺序。 比如:
module: {
rules: [
{
test: /.less$/,
use: 'style-loader'
},
{
test: /.less$/,
use: 'css-loader'
},
{
test: /.less$/,
use: 'less-loader'
}
]
},
这是我们经常会用的loader, 它的执行顺序其实是自下往上
(或者说从右向左)。 所以执行的顺序是:
如果我们设置 enforce
, 则会明确自定义的执行顺序, 比如:
module: {
rules: [
{
test: /.less$/,
use: 'less-loader',
enforce: 'pre'
},
{
test: /.less$/,
use: 'css-loader'
},
{
test: /.less$/,
use: 'style-loader',
enforce: 'post'
}
]
},
像上面这种写法,则手动确定执行顺序:
normal
是我们正常在rules中引用loader
而 inline
是另外一种写法:
style-loader!css-loader!stylus-loader
当然目前大家用inline的场景有限,因为很多时候对loader要传入各种参数。
好, 基础用法和不常用的enforce
讲完, 下面,拿normal
出来,进行重点讲解
4. Normal Loader 和 Pitching Loader
4.1 Loader的执行总结构
Loader的总体结构是将一个函数 exports出去,供webpack的 runtime(我自己抽象的)
使用。
4.2 Normal Loader的开发方式和执行
先把最基础的展示:
// vue-pre-loader.js
const vuePreLoader = (content, map, meta) => {
console.log('vue PreLoader获取的')
console.log('vue PreLoader逻辑执行');
return content;
}
module.exports = vuePreLoader;
在webpack中的使用:
const {resolve} = require('path');
// ....
rules: [
{
test: /\.vue$/,
use: [
{
loader: 'vue-loader'
},
{
loader: resolve(__dirname, './loader/vue-pre-loader.js')
}
]
},
]
在编译.vue
文件的时候, 就会先执行我们自己写的loader, 而且会把content
打印出来。 这个content是字符串,我们可以对数据进行二次处理。
好了,现在我们再开发一个loader, 用于 vue-loader执行后。
// vue-after-loader.js
const vueAfterLoader = (content, map, meta) => {
// 比如可以把content中的html注释部分给删除掉
const regExp = /<!--((\s|\r|\n)*((?!-->).)*\s|\r|\n)*-->/;
if(regExp.test(content)) {
content = content.replace(content.match(regExp)[0], '');
}
console.log('vueAfterLoader 逻辑执行');
return content;
}
module.exports = vueAfterLoader;
同样,更新webpack中的配置:
const {resolve} = require('path');
// ....
rules: [
{
test: /\.vue$/,
use: [
{
loader: resolve(__dirname, './loader/vue-after-loader.js')
},
{
loader: 'vue-loader'
},
{
loader: resolve(__dirname, './loader/vue-pre-loader.js')
}
]
},
]
重新执行的时候,注意以下两点:
- content 的内容可以进行处理,处理成我们想要的
- 执行顺序: 先执行vue-pre-loader, 再执行vue-arger-loader
4.3 Pitching Loader是什么
这个概念在我处理的很多项目中并没有用到, 所以,更需要研究一下。 经过研究发现,这个pitching
其实是跟熔断
相关的。
首先加上这个pitch
试试
// vue-pre-loader.js
const vuePreLoader = (content, map, meta) => {
console.log('vue PreLoader逻辑执行');
return content;
}
vuePreLoader.pitch = function(remainingRequest, precedingRequest, data) {
console.log('执行vuePreLoader pitching');
}
module.exports = vuePreLoader;
// vue-after-loader.js
const vueAfterLoader = (content, map, meta) => {
// 比如可以把content中的html注释部分给删除掉
const regExp = /<!--((\s|\r|\n)*((?!-->).)*\s|\r|\n)*-->/;
if(regExp.test(content)) {
content = content.replace(content.match(regExp)[0], '');
}
console.log('vueAfterLoader 逻辑执行');
return content;
}
vueAfterLoader.pitch = function(remainingRequest, precedingRequest, data) {
console.log('执行vueAfterLoader pitching');
}
module.exports = vueAfterLoader;
再次执行, 我们会发现,执行顺序是这样的:
也就是说: pitch的执行是从前向后, pitch执行完毕后,再从后向前执行loader
那么这个pitching 的应用是什么呢?一个重要功能就是前面说的熔断
。 当pitch 返回非undefined, 那么就会阻断之前的进程。 比如, 我在vue-pre-loader.js 中做一个return操作
vuePreLoader.pitch = function(remainingRequest, precedingRequest, data) {
console.log('执行vuePreLoader pitching');
return '熔断流程';
}
那么再看执行结果:
看到了吧? 它把后面的流程给熔断了, 所以 vue PreLoader逻辑执行
这个逻辑就没有执行,就返回到了 vue-after-loader
整体流程是这样的:
画的不是很好,但是尽量体现他们之间的关系。希望对大家有那么一点点启发。
上面是今天我要表达的全部内容, 在分享给大家的同时,自己对其中的一些原理也有了更深一些的认识, 希望对大家有用。喜欢的话别忘了点个赞喔~~
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!