Open xiaochengzi6 opened 2 years ago
loader 是对非 js 文件的处理 一般可分为
针对 css 文件需要去查看是否使用到了 less 或 sass
module.exports = {
module: {
rules: [
{
test: /\.less$/i,
use: [
'style-loader',
'css-loader',
'less-loader',
],
},
],
},
};
loader
其实就是其中的 less-loader
、css-loader
、style-loader
使用 use
属性来使用, test
属性来匹配文件
执行时机是后序遍历,类似于[].pop()
,每一个 loader 处理完就会输出,下一个 loader 接收到后继续处理完输出
在一个 loader 在使用的时候,loader 函数只接受一个参数,一个包含内容的字符串
同步 loader 可以 return 一个代表已转换模块(transformed module)的单一值。在更复杂的情况下,loader 也可以通过使用 this.callback(err, values...) 函数,返回任意数量的值。错误要么传递给这个 this.callback 函数,要么抛给(thrown in)同步 loader 。 loader 会返回一个或者两个值。第一个值的类型是 JavaScript 代码的字符串或者 buffer。第二个可选值是 SourceMap,它是个 JavaScript 对象。
在链式调用多个 loader 时
最后的 loader 最早调用,将会传入原始资源(raw resource)内容。 第一个 loader 最后调用,期望值是传出 JavaScript 和 source map(可选)。 中间的 loader 执行时,会传入前一个 loader 的结果。
loader 的形式大致就可以等同于这样
function loader_1 (source) {
// ....
return source
}
loader 有两种执行方式 同步
和异步
在整个 loader 生命周期中分为两个执行阶段 picth
和 normal
loader 会先执行 pitch,然后获取资源再执行 normal loader。如果 pitch 有返回值时,就不会走之后的 loader,并将返回值返回给之前的 loader。这就是为什么 pitch 有 熔断 的作用!
function loader(source) {
}
loader.pitch = function (res) {
// 先执行 pitch 阶段
}
// 获取资源后才会触发 normal 阶段
loader.normal = function (res) {
// 再执行 normal 阶段
}
如果是链式调用就 先前序编列 以此触发 pitch
拿到资源后会后续遍历 依次触发 normal
可以使用 return 或 this.callback() 两种形式返回结果
this.callback(error, content, sourceMap, meta)
如果希望在 loader 之间共享公共的 AST,可以将抽象语法树 AST(例如 ESTree)作为第四个参数(meta)传递,以加快构建时间。
function loader (source, map, meta) {
// 注意:当调用 callback() 时,始终返回 undefined this.callback(null, source, map, meta) return }
> 参考:https://webpack.docschina.org/api/loaders#thiscallback
2. 异步方式
告诉 loader-runner 这个 loader 将会异步地回调。返回 this.callback。
> loader-runner 是 loader 调用函数
~~~js
function loader (source) {
// this.async() 返回 this.callback() 函数
const callback = this.async()
setTimeout(() => {
callback(null, source)
}, 1000)
}
module.exports = loader
(一)Plugins
一个最基础的 插件可能是这样的形式
webpack 在运行的生命周期中会广播很多事件 插件就会监听这些事件 在恰当的时机调用回调函数
在使用的时候可以像 webapck 那样配置
这里定义了一个
apply
方法 接受一个 compiler 的对象在 hook 上去监听了 emit 的事件 使用异步的方式tapAsync
在编写 Plugins 的时候最重要的就是 compiler 和 compilertion 这两个对象
1、
Compiler
对象包含 Webpack 环境的所有配置 是webpack 的主要引擎 用来注册和调用事件2、
Compilation
包含了当前模块资源、编译生成资源、变化的文件,当 webpack 运行时 每一次的文件的变动 都会创建一次 Compilation这两者明显的区别的在于 Compiler 它在webapck 整个生命周期的过程都始终存在 后者 每一次的资源变动都会重新编译进而重新创建一个 compilation
这就是一次在 compiler 的 emit 钩子上绑定的 当emit 事件触发 回调函数调用,使用的是 同步的方式 接收两个参数 一个是插件名另一个是 回调函数
compiler.hook.emit.tap(name, ()=>{})
类似的
compilation.hook.optimize.tap(name, ()=>{})
(二)loader
webpack 处理的是 js 的文件资源 如果想要处理其他的 比如 css 或者 图片就要使用到 loader 它主要的作用就是将 webpack 不能处理的资源进而转换成能处理的
loader 比较特殊 它支持链式调用 从右往左执行 loader 的链式调用 这样也决定了 只要不是最后一个调用的 loader 它就不需要返回 js 格式的数据 可以返回任意类型的数据。
可以简单的将 loader 看作是一个导出的函数
如果使用 一个 loader 来处理文件只能传入一个参数 一个用于包含资源文件内容的字符串 return 返回一个被处理过单一值 也可以使用 this.callback(err, values...) 返回任意数量值
loader 最终会 返回一个或 两个值 一个是js 代码的字符串 或者是 buffer 第二个是 scourceMap
参考
1、webpack 官网
2、如何写 loader