持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第13天,点击查看活动详情
实现自定义的loader
loader是什么?
让webpack支持非js、json模块编译的机制,当遇到非js、json的时候,会通过module去进行配置, 会把相应的模块丢给相应的loader去进行编译,loader编译之后的内容会交给webpack做进一步的处理。
loader 本质上是导出为函数的 JavaScript 模块。loader runner 会调用此函数,然后将上一个 loader 产生的结果或者资源文件传入进去。
起始 loader 只有一个入参:资源文件的内容。compiler 预期得到最后一个 loader 产生的处理结果。这个处理结果应该为 String 或者 Buffer(能够被转换为 string)类型,代表了模块的 JavaScript 源码。另外,还可以传递一个可选的 SourceMap 结果(格式为 JSON 对象)
如何自己编写一个Loader
Loader就是⼀个函数, 声明式函数,不能⽤箭头函数
示例:
- 创建一个替换源码中字符串的loader
// index.js
console.log('Hello webpack')
// frllk-loader.js
module.exports = function (source) {
return source.replace('Hello', this.query.name)
}
编写loader需要处理的问题:
* 官方文档:https://webpack.js.org/contribute/writing-a-loader/
* 接口文档:https://webpack.docschina.org/api/loaders/
* loader的结构:
* 官方约定:
* 一个loader只能做一件事情
* 不要用箭头函数
* 1. loader就是一个函数,但是不可以是箭头函数?
* 2. loader必须有返回值,string or buffer, 如果没有返回值就会出错 "didn't return a Buffer or StringFinal loader (./myLoaders/frllk-loader.js) didn't return a Buffer or String"
* 3. loader如何接收配置?
* 通过loader API, 获取外部参数
* this.query:
* 如果这个 loader 配置了 options 对象的话,this 就指向这个对象。
* 如果 loader 中没有 options,而是以 query 字符串作为参数调用时,this.query 就是一个以 ? 开头的字符串。
* 4. 如何返回多个信息?
* this.callback有同步调用和异步调用两种方式
* 5. loader有异步逻辑如何处理?
* 需要通过一个接口告诉loader runner是这个loader内部是有异步逻辑或者回调的
* 6. 多个loader之间是如何配置的呢?
* 7. 如何处理路径问题
* webpack.config.js文件中配置resolveLoader
- 新建文件frllk-loader-async.js
module.exports = function (source) { // 问题1
// return source.replace('Hello', this.query.name)
// 问题2、3
// const info = source.replace('Hello', this.query.name)
// this.callback(null, info)
// 问题4
// setTimeout(() => {
// const info = source.replace('Hello', this.query.name)
// return info // Final loader (./myLoaders/frllk-loader.js) didn't return a Buffer or String
// }, 2000);
// 解决问题5
const callback = this.async()
setTimeout(() => {
const info = source.replace('Hello', this.query.name)
callback(null, info)
}, 2000);
}
- 新建文件frllk-loader.js
module.exports = function (source) {
return source.replace('webpack', 'webpack!!!')
}
- 修改配置文件webpack.config.js
// 7. 如何处理路径问题: 解决了问题7
resolveLoader: {
modules: ["./node_modules", "./myLoaders"]
},
module: {
rules: [
{
test: /\.js$/, // 如果遇到js后缀的文件,用自己写的loader进行处理
// 使用第三方的loader默认去node_modules去查找,如果是使用自己写的loader,则是通过path,生成绝对路径
// use: resolve(__dirname, "./myLoaders/frllk-loader.js")
// 配置化需求:解决了问题6
// use: [
// {
// loader: resolve(__dirname, "./myLoaders/frllk-loader-async.js"), // 需要使⽤node核⼼模块path来处理路径
// options: {
// name: 'frllk'
// }
// // console.log('frllk webpack!!!')
// },
// resolve(__dirname, "./myLoaders/frllk-loader.js") // console.log('Hello webpack!!!')
// ]
// 路径处理:解决问题7
use: [
{
loader: "frllk-loader-async",
options: {
name: 'frllk'
}
// console.log('frllk webpack!!!')
},
"frllk-loader" // console.log('Hello webpack!!!')
]
},
]
},