webpack loader解析及自定义loader

自定义实现webpack loader加载模块,解析指定的类型文件

loader

loader是一个导出为函数的node模块,可通过this访问上下文。

特点:

  • loader单一职责,只负责解决单一的功能。

  • 可链式调用,将多个单一任务的loader链式调用去解决文件。

    {
        test:/\.less$/,
        use:[
            'css-loader',
            'less-laoder',
        ]
    }
    

    执行顺序为栈调用顺序,先执行less-loader,后执行css-loader.

  • 模块化输出,保证内部无状态。

  • 使用loader-utils工具包,处理loader内部的字符串转化、方法参数解析、路径解析等。

  • 避免绝对路径,使用loader-utils可转换为相对路径。

  • 提取通用代码。

  • 依赖处理

基础概念

loader接收上一个loader处理后的结果字符串或者buffer

  1. 同步调用处理或者异步调用处理,返回处理结果。
    module.exports =  function(content,map,meta){
        let options = getOptions(this);
        /**
         * 同步调用
         * 1. 调用this.callback() 是,必须返回 undefined
         * 2. 直接返回执行结果 return someSyncOperation(content)
         */
        // this.callback(null,someSyncOperation(content),map,meta)
        // return;
        /**
         * 异步调用
         * 1. this.async() 获取异步调用的回调函数
         */
        let callback = this.async();
        someAsyncOperation(content,function(err,result){
            if (err) return callback(err)
    
            callback(null,result,map,meta)
        })
    }
    
  2. 通过定义pitch函数,链式调用loader时会先执行各个pitch函数,先执行的loader会受到后执行loaderpitch函数影响。
    如果pitch函数返回一个结果,则会跳过其他loader,直接从此处执行。
    //1. 正常 执行顺序  c-b-a
    use:[
        'a-loader',
        'b-loader',
        'c-loader'
    ]
    //2. 如果 a和b 中定义了pitch, 则在c-loader中可以拿到一些暴露的值; 执行顺序 c-b-a
    use:[
        'a-loader',       // 暴露了 属性 data.name="admin"
        'b-loader',     // 可以使用 data.name
        'c-loader'        // 可以使用data.name
    ]
    //3. 如果 b-loader pitch函数返回了一个值,则跳过c-loader执行 ,
    //   执行顺序为 b-a
    use:[
        'a-loader',
        'b-loader',            // pitch 中  return result
        'c-loader'
    ]
    // 在loader中设置pitch函数
    module.exports.pitch = function(remainRequest,precedingRequest,data){
        // ... 
        data.name = "admin"
    }
    
  3. 默认返回结果值为转换后的utf-8字符串,设置raw返回原始buffer.
    module.exports.raw = true;
    

API释义

通过this访问内部的属性、方法。

属性释义示例
.version版本号
.context模块所在的目录。
.request解析到的请求路径。
.query指向配置的options;或者指向请求路径的?后面部分
.callback调用返回结果的函数,可返回多个;直接使用return返回,只能返回一个。
.async异步执行回调。
.data执行阶段共享的数据data
.cacheable(true:Boolean)设置是否可被缓存,默认缓存
.loaders所有laoder组成的数组
.loaderIndex当前loader在loaders数组中的下标
.resourcerequest中的资源部分,包括query
.resourcePath资源文件的路径
.resourceQuery资源的query参数
.target编译目标,配置项配置,比如:web/node
.webpack标识是否是由webpack编译
.sourceMap
.emitWarning发出一个警告
.emitError标识是否是由webpack编译
.loadModule加载一个外部模块,并应用到所有loader
.resolve
.addDependency加入一个文件作为产生loader结果的依赖
.addContextDependency
.clearDependencies移除所有loader结果所有的依赖
.emitFile
.fs用于访问compilationinputFileSystem属性。

loader API地址

使用方式

  1. webpack 配置文件中配置loader
    module:{
        rules:[
            // ...
            {
                test:/\.pj$/,
                use:{
                    loader:path.resolve(__dirname,"./src/plugins/loader"),
                }
            }
        ]
    }
    
  2. 多个loader时,采用配置属性resolveLoader,加载文件下所有的loader包。
    module:{
        rules:[
            // ...
            {
                test:/\.pj$/,
                use:{
                    loader:'pj-loader',
                    options:{
                        // ... 
                    }
                }
            }
        ]
    },
    resolveLoader:{
        modules:[
            'node_modules',
            path.resolve(__dirname,"./src/plugins/loader")
        ]
    }
    
  3. npm-link 将独立的loader包关联到node_modules上,不需要【2】中的resolveLoader配置
    // 暂时没有测试成功
    
    npm link "./src/plugins/loaders"
    

自定义实现一个 loader

用于解析.pj后缀的模板文件,并替换里面的模板字符串。

/**
 * 自定义实现一个loader解析
 */
const {getOptions} = require('loader-utils');

module.exports =  function(content,map,meta){
    let options = getOptions(this);
    
    content = content.replace(/\{name\}/g,options.name);

    return `export default ${JSON.stringify(content)}`;
}

解析文件.pj长这样:

admin,{name}

配置webpack.dev.js文件,加入自定义loader配置解析.pj文件。

module:{
    rules:[
        // ... 
        {
            test:/\.pj$/,
            use:{
                loader:path.resolve(__dirname,"./src/plugins/loader"),
                options:{
                    name:"hello"          // 配置项,由 getOptions获取其中的属性值
                }
            }
        }
    ]
}

在主文件中导入使用index.pj,npm run dev查看输出。

import Text from "../plugins/loader/index.pj";
console.log(Text);          // 输出: admin,hello
©️2020 CSDN 皮肤主题: 书香水墨 设计师:CSDN官方博客 返回首页