环境搭建

  • 初始化项目
npm init -y
  • 安装依赖
npm i webpack@5 webpack-cli@4 -D
  • 目录结构
    webpack 学习 —— 深入 loader_webpack 深入

自定义 loader

  • 暴露 loader
// loaders/loader1.js

// loader 是一个函数,接收要处理的内容,返回处理后的内容
module.exports = function (content) {
    console.log(123)
    return content
}
  • 配置使用loader
// /webpack.config.js
const path = require('path')

// 默认情况下,webpack@5 会以 /src/index.js 为入口,并打包到 /dist/main.js
module.exports = {
    mode: 'development',
    module: {
        rules: [
            {
                test: /.js$/,
                loader: path.resolve(__dirname, 'loaders', 'loader1')	// 使用 自定义 loader
            }
        ]
    }
}
  • 运行测试:执行 npx webpack
    webpack 学习 —— 深入 loader_webpack_02
  • 可以看到我们自定义的loader执行了

配置 loader 查找路径

// /webpack.config.js
const path = require('path')

module.exports = {
    mode: 'development',
    module: {
        rules: [
            {
                test: /.js$/,
                loader: 'loader1'   // 只需要写 loader 的名字即可
            }
        ]
    },
    resolveLoader: {
        modules: [
            'node_modules', // webpack 默认寻找 loader 的位置
            path.resolve(__dirname, 'loaders')  // 将我们存放自定义 loader 的路径位置也配置进去
        ]
    }
}

loader 执行顺序

  • 创建多个loader并配置使用,如下
    webpack 学习 —— 深入 loader_webpack_03
module.exports = function (content) {
    console.log('loader 1')
    return content
}
...
const path = require('path')

module.exports = {
    mode: 'development',
    module: {
        rules: [
            {
                test: /.js$/,
                use: ['loader1', 'loader2', 'loader3']   // 使用多个 loader
            }
        ]
    },
    resolveLoader: {
		...
    }
}
  • 运行测试
    webpack 学习 —— 深入 loader_webpack_04

  • 可以看到, loader 是从右往左,从下往上依次执行的

  • 使用 pitch 函数,可以使得 loader 顺序执行,如下

module.exports = function (content) {
    console.log('loader 1')
    return content
}

module.exports.pitch = function () {
    console.log('pitch 1')
}
  • 运行测试
    webpack 学习 —— 深入 loader_webpack_05
  • 可以看出 webpack 会先从上往下、从左往右,依次执行 pitch ,然后再从下往上、从右往左,依次执行 loader

异步 loader

  • 使用 this.async()
// loader2.js
module.exports = function (content) {
    console.log('loader 2')
    const callback = this.async()

    setTimeout(()=>{
        // callback 执行后,loader 才会继续向下执行
        callback(null, content) // 参数分别是 错误信息、向下传递的内容
    }, 1000)
}
  • 运行测试
    webpack 学习 —— 深入 loader_webpack_06

获取Options

  • 配置 options
const path = require('path')

module.exports = {
    mode: 'development',
    module: {
        rules: [
            {
                test: /.js$/,
                use: [
                    'loader1', 
                    'loader2', 
                    {
                        loader: 'loader3',
                        // 配置 options
                        options: {
                            name: 'aa',
                            age: 17
                        }
                    }
                ]  
            }
        ]
    },
    resolveLoader: {
     	...
    }
}
  • 获取 options
// loader3.js

// loader-utils 由 webpack 提供
const { getOptions } = require('loader-utils')

module.exports = function (content) {

    console.log('loader 3')
	
	// 传入 this 并调用
    const options = getOptions(this)

    console.log(options)
    
    return content
}
  • 运行测试
    webpack 学习 —— 深入 loader_webpack_07

校验 Options

  • 制定校验规则
// loaders/scheme.json
{
    "type": "object",	// options 的类型
    "properties": {		// 可以配置的属性
        "name": {
            "type": "string",
            "description": "姓名"
        },
        "age": {
            "type": "number",
            "description": "性别"
        }
    },
    "additionalProperties": true	// 是否可以配置额外属性
}
  • 使用校验规则
// loader3.js

const { getOptions } = require('loader-utils')
// 引入并取出 validate
const { validate } = require('schema-utils')

// 读取校验规则
const schema = require('./scheme.json')

module.exports = function (content) {

    console.log('loader 3')

    const options = getOptions(this)

	// 验证
    // 校验规则、校验内容、loader的名字
    validate(schema, options, {name: 'loader3'})

    return content
}
  • 运行测试:故意出现类型错误,如 age: "17"
    webpack 学习 —— 深入 loader_webpack 深入_08