一、初始化一个webpack项目
二、src同级目录下新建loaders文件夹
新建markLoader.js
loader就是一个函数,注意不能写箭头函数,因为要使用this。
module.exports = function(source) {
return source.replace('hello', 'helloword');
}
webpack配置
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: [
// 不传参数
path.resolve(__dirname, './loaders/markLoader.js')
]
}
]
}
三、loader如何接收webpack配置的参数
loader:
module.exports = function(source) {
console.log(this.query) // 通过this可以拿到配置中的参数
console.log(this.query.name) // 拿到loader下options参数的配置
return source.replace('hello', 'helloword');
}
webpack.config.js:
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: [
{
loader: path.resolve(__dirname, './loaders/markLoader.js'),
options: { // 传递参数
name:'helloword'
}
}
]
}
]
}
通过loader-utils来处理参数
loader:
// 如果参数不好解析,可以使用loader-utils
const loaderUtils = require('loader-utils');
module.exports = function(source) {
// console.log(this.query) // 通过this可以拿到配置中的参数
const option = loaderUtils.getOptions(this)
return source.replace('hello', option.name);
}
通过schema-utils来验证参数
schema.json
{
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "名称"
}
},
"additionalProperties": true // 可以有多个,如果是false,json定义几个参数,外部只能传几个参数
}
const { validate } = require('schema-utils')
const schema = require('/schema');
module.exports = function(source) {
validate(schema, source, {
name: 'lodaler1' // 报错的lodaler
})
}
四、loader中传递源代码的同时想要带参数
// this.callback()
const loaderUtils = require('loader-utils');
module.exports = function(source) {
// console.log(this.query) // 通过this可以拿到配置中的参数
const option = loaderUtils.getOptions(this)
const result = source.replace('hello', option.name);
this.callback(null, result);
}
// 此外 this.callbak还可以传递sourceMap等等
五、如何编写异步loader
const loaderUtils = require('loader-utils');
module.exports = function(source) {
const option = loaderUtils.getOptions(this)
const callback = this.async();
// this.async() 就是一个callback
setTimeout(() => {
const result = source.replace('hello', option.name);
callback(null, result)
}, 1000)
}
六、多个loader配合使用
新建两个loader
webpack.config.js:
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
// 新使用markLoader1进行处理,处理完成之后,交给markLoader2处理
use: [
{
loader: path.resolve(__dirname, './loaders/markLoader2.js'),
options: { // 传递参数
name:'helloword'
}
},
{
loader: path.resolve(__dirname, './loaders/markLoader1.js'),
options: { // 传递参数
name:'helloword'
}
}
]
}
]
}
loader执行顺序
如果有多个loader,是把loader放在数组中,loader是从数组的后面开始执行
loader上有个pitck方法,是从前向后执行
七、写loader的时候,去掉path.resolve
webpack.config.js:
resolveLoader: {
// 定义loader先去node_modules中查找,如果没有,就去自定义的loader文件夹下查找
modules: ['node_modules', './loaders']
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
// 新使用markLoader1进行处理,处理完成之后,交给markLoader2处理
use: [
{
loader: 'markLoader2',
options: { // 传递参数
name:'helloword'
}
},
{
loader: 'markLoader1',
options: { // 传递参数
name:'helloword'
}
}
]
}
]
}
八、项目中用到的自定义loader
1、jquery代码中添加异常捕获
如果一个一个在jq代码中添加异常捕获,这样太麻烦
可以使用loader
loader:
const loaderUtils = require('loader-utils');
module.exports = function(source) {
// source就是源代码,拿到源代码之后,通过ast进行分析
// 找到function,并对function进行处理
// 将function都放在try-catch中执行
try{
function(){}
}catch(e) {
console.log(e)
}
}
2、网站国际化
loader:
module.exports = function(source) {
if (Node全局变量 == '中文'){
source.repalce('{{title}}', '中文')
}else {
source.repalce('{{title}}', 'en')
}
}