Skip to content

自创一个banner-loader

本章节我们自己创造一个loader。

自创banner-loader功能介绍

在打包的代码中生成一些额外的注释,比如作者,打包时间等。

写的稍微复杂一点,配置一些属性。

安装插件,校验自己的属性,看配置的对不对

shell
yarn add schema-utils@^1.2.3 -D

代码

添加banner-loader

js
// webpack\webpack-loader\loaders\banner-loader.js
let loaderUtils = require('loader-utils') // 获取loader的配置参数,options等
let validateoptions = require('schema-utils') // 校验数据格式的

let fs = require('fs')

function loader(source) {
    console.log('banner-loader 加载了');

    // 打包的时候开启缓存(默认是开启的,如果传入false 就是关闭缓存)
    // this.cacheable(false)
    this.cacheable && this.cacheable()

    let cb = this.async() // 异步回调返回结果的回调函数

    // 获取loader配置的options
    let optios = loaderUtils.getOptions(this)

    // 校验options数据格式
    let schema = {
        type: 'object',
        properties: {
            text: {
                type: 'string'
            },
            filename: {
                type: 'string'
            }
        }
    }

    // 比对 schema 和 optios 数据格式是否一致,不一致就会报错
    // banner-loader 是标识
    validateoptions(schema, optios, 'banner-loader')

    /* 
        如果有filename,就用filename里的文本
        如果没有,就用text中的文本
    */
    if (optios.filename) {
        // 把这个文件增加到webpack打包依赖中,一旦变更 可以出发重新打包
        this.addDependency(optios.filename) // 自动添加文件依赖

        fs.readFile(optios.filename, 'utf8', (err, data) => {
            cb(err, `/**${data} ${new Date().toLocaleString()}*/ ${source}`)
        })
    } else {
        cb(err, `/**${optios.text} ${new Date().toLocaleString()}*/ ${source}`)
    }

    return source
}

module.exports = loader

修改配置文件

js
// webpack\webpack-loader\webpack.config.js

let path = require('path')

module.exports = {
    mode: 'development',

    entry: './src/index.js',

    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'bundle.js'
    },

    watch: true, // 边写边打包
    module: {
        rules: [
            {
                test: /\.js$/,
                use: {
                    loader: 'banner-loader', // 自创一个banner-loader
                    // 给所有匹配到的js模块,增加一个额外的注释
                    // 比如 /** cheny && xzz 2022-02-06 17:08 */
                    options: {
                        text: 'cheny && xzz', // 默认作者的名字
                        filename: path.resolve(__dirname, 'banner.txt'), // 如果没有给text,那么就读取这个文件中的内容
                    }
                }
            }
        ]
    },

    resolveLoader: {
        // 找loader的时候,先从node_modules中找,找不到再从我们的loaders目录下找
        modules: ['node_modules', path.resolve(__dirname, 'loaders')]
        /* alias: { // loader的别名
            loader1: path.resolve(__dirname, 'loaders', 'loader1.js')
        } */
    }
}

添加banner.txt

cheny hhhh

打包看下结果 npx webpack,成功

image-20220206174143065

总结

本节编写了一个自创的loader,banner-loader,功能是给打包后的代码添加一段额外的注释,创建时间和作者名,为了复杂点,还增加了一些配置项,在外部创建一个txt文本,如果有文本,作者名就以文本中的内容为准,涉及到下面几个技术点。

  1. 配置方式遵循规范,根babel-loader的配置类似,配置项也一样

    js
    module: {
        rules: [
            {
                test: /\.js$/,
                use: {
                    loader: 'banner-loader', // 自创一个banner-loader
                    // 给所有匹配到的js模块,增加一个额外的注释
                    // 比如 /** cheny && xzz 2022-02-06 17:08 */
                    options: {
                        text: 'cheny && xzz', // 默认作者的名字
                        filename: path.resolve(__dirname, 'banner.txt'), // 如果没有给text,那么就读取这个文件中的内容
                    }
                }
            }
        ]
    },
    
        resolveLoader: {
            // 找loader的时候,先从node_modules中找,找不到再从我们的loaders目录下找
            modules: ['node_modules', path.resolve(__dirname, 'loaders')]
            /* alias: { // loader的别名
                loader1: path.resolve(__dirname, 'loaders', 'loader1.js')
            } */
        }
  2. 引入了 schema-utils 来对配置项进行校验,校验的数据格式如果根自己定义的规则不同,会直接抛出错误

    js
    let loaderUtils = require('loader-utils') // 获取loader的配置参数,options等
    let validateoptions = require('schema-utils') // 校验数据格式的
    
    // 获取loader配置的options
    let optios = loaderUtils.getOptions(this)
    
    // 校验options数据格式
    let schema = {
        type: 'object',
        properties: {
            text: {
                type: 'string'
            },
            filename: {
                type: 'string'
            }
        }
    }
    
    // 比对 schema 和 optios 数据格式是否一致,不一致就会报错
    // banner-loader 是标识
    validateoptions(schema, optios, 'banner-loader')
  3. 在编写loader的时候,如果想实现配置文件变更,也能触发重新打包,需要将配置文件增加到webpack依赖中

    js
    // 把这个文件增加到webpack打包依赖中,一旦变更 可以出发重新打包
    this.addDependency(optios.filename) // 自动添加文件依赖
  4. 默认loader是开启缓存的,也可以关闭缓存,一般都是开启的

    js
    // 打包的时候开启缓存(默认是开启的,如果传入false 就是关闭缓存)
    // this.cacheable(false)
    this.cacheable && this.cacheable()
  5. banner-loader的全部代码

    js
    // webpack\webpack-loader\loaders\banner-loader.js
    let loaderUtils = require('loader-utils') // 获取loader的配置参数,options等
    let validateoptions = require('schema-utils') // 校验数据格式的
    
    let fs = require('fs')
    
    function loader(source) {
        console.log('banner-loader 加载了');
    
        // 打包的时候开启缓存(默认是开启的,如果传入false 就是关闭缓存)
        // this.cacheable(false)
        this.cacheable && this.cacheable()
    
        let cb = this.async() // 异步回调返回结果的回调函数
    
        // 获取loader配置的options
        let optios = loaderUtils.getOptions(this)
    
        // 校验options数据格式
        let schema = {
            type: 'object',
            properties: {
                text: {
                    type: 'string'
                },
                filename: {
                    type: 'string'
                }
            }
        }
    
        // 比对 schema 和 optios 数据格式是否一致,不一致就会报错
        // banner-loader 是标识
        validateoptions(schema, optios, 'banner-loader')
    
        /* 
            如果有filename,就用filename里的文本
            如果没有,就用text中的文本
        */
        if (optios.filename) {
            // 把这个文件增加到webpack打包依赖中,一旦变更 可以出发重新打包
            this.addDependency(optios.filename) // 自动添加文件依赖
    
            fs.readFile(optios.filename, 'utf8', (err, data) => {
                cb(err, `/**${data} ${new Date().toLocaleString()}*/ ${source}`)
            })
        } else {
            cb(err, `/**${optios.text} ${new Date().toLocaleString()}*/ ${source}`)
        }
    
        return source
    }
    
    module.exports = loader

参考

https://www.bilibili.com/video/BV1a4411e7Bz?p=43&spm_id_from=pageDriver