You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
this.hooks = {
shouldEmit: new SyncBailHook(["compilation"]),
done: new AsyncSeriesHook(["stats"]),
additionalPass: new AsyncSeriesHook([]),
beforeRun: new AsyncSeriesHook(["compilation"]),
run: new AsyncSeriesHook(["compilation"]),
emit: new AsyncSeriesHook(["compilation"]),
afterEmit: new AsyncSeriesHook(["compilation"]),
thisCompilation: new SyncHook(["compilation", "params"]),
compilation: new SyncHook(["compilation", "params"]),
normalModuleFactory: new SyncHook(["normalModuleFactory"]),
contextModuleFactory: new SyncHook(["contextModulefactory"]),
beforeCompile: new AsyncSeriesHook(["params"]),
compile: new SyncHook(["params"]),
make: new AsyncParallelHook(["compilation"]),
afterCompile: new AsyncSeriesHook(["compilation"]),
watchRun: new AsyncSeriesHook(["compiler"]),
failed: new SyncHook(["error"]),
invalid: new SyncHook(["filename", "changeTime"]),
watchClose: new SyncHook([]),
// TODO the following hooks are weirdly located here
// TODO move them for webpack 5
environment: new SyncHook([]),
afterEnvironment: new SyncHook([]),
afterPlugins: new SyncHook(["compiler"]),
afterResolvers: new SyncHook(["compiler"]),
entryOption: new SyncBailHook(["context", "entry"])
};
webpack-loader
@(前端)[webpack]
[toc]
1.任务
解题思路
延伸
2.关于loader
1.什么是loader
loader 用于对模块的源代码进行转换。
可以允许webpack去处理那些非js文件webpack 自身只理解js。loader 可以将所有类型的文件转换成webpack能够处理的有效模块。比如css、font、各种image、xml等
2.loader特性
3.loader在webpack内部是如何工作的
或者说webpack是如何调用loader的
以下都是重点都是在loader相关的方向
1. 从头分析webpack
这部分就必须去分析webpack源码了。首先我们知道loader是为了处理模块而产生的,那么目标就很明确了,我们猜想webpack应该是在打包过程中,生成最终模块之前引入模块之后这段时间开始使用loader的,因为这个时候正是处理模块的时候。所以我们首先尝试去找到webpack中引入模块的地方
从头说起,我们在启动一个项目的时候使用的命令是webpack所以,自然的想到从bin/webpack开始。这里是以当前的版本4.6.0的master开始的。
bin/webpack非常简单仅仅是简单的分析了如果有webpck-cli就去require否则就让用户去安装。
ps: 4.0的webpack将cli拆分出一个独立的库去维护了
pps: 源码比较简单的地方就不管了 只标出一些值得注意的地方,也是为了标记下回头查的方便
接下来在webpack-cli源码中,(通过package.json知道入口是bin/webpack.js)。这里代码可以看到使用了yargs 一个node的库用来处理命令行的参数。然后调用
convert-argv
来获取到你的webpack.config.js文件中的配置,然后去处理下参数。一直到434行左右,可以看到require了webpack并且传递配置开始编译,最后调用了processOptions()
这个方法就作用是处理了输出相关的参数,并且执行了编译函数。然后根据初始化compiler的代码,我们先回到了webpack的入口文件
"main": "lib/webpack.js"
。同样也是引入了一些文件然后就是最核心的webpack的定义,最后export了很多的自带的Plugin,源码也比较简单。回到cli文件最后的run这里很容易看出来最主要的东西就是这个Compiler文件,打开Compiler文件后我们会看到Compiler文件的所有的hooks。
这里官方文档有一些简单解释
https://webpack.js.org/api/compiler-hooks/
另外在顶部可以看到引入了tapable,这个是webpack里非常重要的一个库。
2. tapable
可以看到整个Compiler都是继承自Tapable
这个库的用法我理解起来比较费劲,因为完全不了解Hook机制,所以又花时间去研究了下hook机制。
这个库现在的版本是1.0.2 在webpack发布4.0后这个库同时进行了很大的升级,以至于网络上的大部分文章都不合适了(我没有找到一个分析1.x版本的)。
对于tapable只是大概读懂了一部分,花了点时间写了个例子。感觉以后如果有机会写大型的库可以考虑用tapable或者他的这种思想,这里只提一下他的大概的用法,具体等我例子完成了研究下源码在分享。因为和本篇关系不大放到另一个文章中了。
3. 调试webpack
插播一条如何去调试webpack,因为在看webpack源码的时候不懂tapable又不懂hook看起来非常费劲,所以知道怎么调试webpack省去了很多力气。
比较简单的调试方式:
chrome://inspect/#devices
Open dedicated DevTools for Node
"debug": "node --inspect-brk node_modules/.bin/webpack --config webpack.config.js"
4. webpack流程图(loader相关)
这里根据我打了一堆debugger和console后得出的结论来绘制了一个loader相关的流程图,不包括其他webpack流程。请配合源码食用。
github 不支持 flow写法 补上图
额外需要仔细研究的:AST,工厂模式,
4.如何使用loader
loader有2个属性
module 对象下面的rules对象接收数组,表示可以定义多个rule,每一个rule必须包含test和use属性
同时use属性可以是一个数组 允许配置多个loader,以及这些loader需要的配置参数
你可能需要首先安装这些loader
以及如果不需要配置额外参数,可以简写
5. 如何写一个loader
说了这么多,如何写一个loader呢?
官方给了很明确的例子和开发方式:https://webpack.js.org/contribute/writing-a-loader/
这里基本没什么可说的,比较重要的一点是:webpack对于开发loader的很多建议同样也适用于我们开发组件。
loader的处理方式大致可以分成2类:
.hlj
就可以使用loader来处理。6. 写一个loader
因为没有合适的业务需求,所以这个反而是最难的一步:找一个需要写loader的业务场景。因为loader的作用是转化文件,让webpack可以处理。 最后只能自己创造一个假的场景来完成任务了,将来找到可以写loader的场景在写真的吧。
比如有一个场景是:我们很多旧图片的都是来自域名
hlj-img.b0.upaiyun.com/zmw
新的都是在
https://img-ucdn-static.helijia.com/zmw
那么假如我们需要替换这个图片域名可以怎么处理呢?
最彻底的解决办法当然是找到代码中的这些图片替换掉,但是比较消耗人力,或者写一个脚本扫一遍文件去替换?总之肯定是有办法的。
这个场景刚好可以来尝试写一个简单的loader。
首先我们搭一个项目,因为功能超级简单,所以手写就行。
src/loaders/hlj-img-url-loader
现在yarn start就可以打包出来最终的js了。我们的loader暂时没有做任何事情。
这里可以用console.log看到source返给我们的东西,但是由于引用了react,代码还是比较乱的。
接下来就是处理loader,方法很简单,replace一下就好了
我们的图片已经替换了url。齐活。
优化:如果我们有一天希望换个域名呢?所以最好能做到可配置。
这样就好了,因为是个无用的功能所以就不发布了。。
我们这个是例子,所以包放到了loaders文件夹,其实真是项目开发最好是创建一个单独文件夹来存放loader项目,配置上package.json,就和Npm包的开发一样。然后link到项目中测试。 这样发布比较方便。
发布方式和发布一个npm包一样 这里就不赘述了
The text was updated successfully, but these errors were encountered: