webpack系列-loader

栏目: CSS · 发布时间: 5年前

内容简介:loader是导出为一个函数的node模块。该函数在loader转换资源的时候调用。给定的函数将调用loader API,并通过this上下文访问。pre => normal => inline => postloader执行首先会加载pitch-loader(书写loader的顺序),然后加载资源resource,最后执行normal-loader(正常加载loader的顺序) 如果pitch-loader有返回值,则会跳过后面的加载,直接走到上一层的normal-loader里面。

loader是导出为一个函数的node模块。该函数在loader转换资源的时候调用。给定的函数将调用loader API,并通过this上下文访问。

function loader(source){
        return source
    }
    loader.pitch = function(){
        console.log('pitch')
    }
    module.exports = loader
复制代码

加载自定义loader的几种方式

  • 匹配单个loader(使用绝对路径)
{
        test:/\.js$/,
        use:[
            loader:path.resolve('path/loaderjs'),
            options
        ]
    }
复制代码
  • alias
resolveLoader:{
        alias:{
            'loader1':path.resolve('path/loader1')
        }
    },
    module:{
        rules:[
            {
                test:/\.js$/,
                use:[
                    loader:loader1,
                    options
                ]
            }
        ]
    }
复制代码
  • 配置多个loader
resolveLoader:{
        modules:[
            path.resolve('node_modules'), 
            path.resolve(__dirname, 'src', 'loaders')
        ]
    }
复制代码

loader的分类

  • 在前面 pre
  • 正常 normal
  • 在后面 post

loader的顺序

pre => normal => inline => post

// index.js  加载顺序为 pre + normal + inline + post
    let str = require('inline-loader!./a.js')
    
    // index.js  加载顺序为 inline + post
    // -! 不会让文件 再去通过pre+normal loader 来处理了
    // ! 没有normal
    // !! 什么都没有 只有自身
    let str = require('-!inline-loader!./a.js')
    
复制代码

loader的组成

loader执行首先会加载pitch-loader(书写loader的顺序),然后加载资源resource,最后执行normal-loader(正常加载loader的顺序) 如果pitch-loader有返回值,则会跳过后面的加载,直接走到上一层的normal-loader里面。

  • pitch-loader
  • normal-loader
webpack系列-loader

loader的特点

  • 最后加载的loader必须返回一个js脚本
  • 每一个loader都是一个模块
  • 每一个loader都是无状态的,确保loader在不同模块转换之间不保存状态。

各种loader的实现

babel-loader

需要安装@babel/core、@babel/preset-env

let babel = require('@babel/core');
    <!--loader 的 工具 库-->
    let loaderUtils = require('loader-utils')
    function loader(source){
        <!--处理异步-->
        let cb = this.async();
        <!--this loaderContext-->
        let options = loaderUtils.getOptions(this);
        <!--babel 转化源码-->
        babel.transform(source,{
            ...options,
            sourceMap:true,
            filename:this.resourcePath.split('/').pop() // 文件名
        },function(err,result){
            cb(null,result.code,result.map)
        })
    }
    
    module.exports = loader
复制代码

banner-loader

use:{
        loader:'banner-loader',
        options:{
            text:'xx',
            filename:path.resolve(__dirname,'banner.js')
        }
    }
复制代码
let loaderUtils = require('loader-utils')
    let fs = require('fs')
    <!--验证传递参数-->
    let validateOptions = require('schema-utils')
    function loader(source){
        <!--添加缓存-->
        this.cacheable && this.cacheable()
        let options = loaderUtils.getOptions(this)
        let cb = this.async();
        let schema = {
            type:'object',
            properties:{
                text:{
                    type:'string'
                },
                filename:{
                    type:'string'
                }
            }
        }
        validateOptions(schema,options,'banner-loader')
        if(options.filename){
            <!--添加监听 当文件内容变化 自动打包-->
            this.addDependency(options.filename)
            fs.readFile(options.filename,'utf8',function(err,data){
                cb(err,`/**${data}**/${source}`)
            })
        }else{
            cb(null,`/**${options.text}**/${source}`)
        }
    }
    
    module.exports = loader
复制代码

file-loader && url-loader

import p from './public.jpg'
    let img = document.createElement('img');
    img.src = p;
    document.body.appendChild(img)
复制代码

file-loader

  • 现将图片生成一个md5 发射到dist目录下
  • 然后返回当前图片的路径
// file-loader
    let loaderUtils = require('loader-utils')
    function loader(source){
        <!--生成md5文件-->
        let filename = loaderUtils.interpolateName(this,'[hash].[ext]',{content:source})
        this.emitFile(filename,source)
        return `module.exports = "${filename}"`
    }
    // 将source 转化为二进制buffer
    loader.raw = true 
    module.exports = loader
    
    
    // url-loader
    let loaderUtils = require('loader-utils')
    let mime = require('mime')
    function loader(source){
        let {limit} = loaderUtils.getOptions(this);
        if(limit && limit > source.length){
            return `module.exports = "data:${mime.getType(this.resourcePath)};base64,${source.toString('base64')}"`
        }else{
           return require('./file-loader').call(this,source) 
        }
    }
    loader.raw = true;
    module.exports  = loader;
    
复制代码

less-loader && style-loader && css-loader

// less-loader
    let less = require('less')
    function loader(source){
        let css;
        less.render(source,function(err,r){
            css = r.css
        })
        // 交给css-loader处理
        return css; 
    }
    
    module.exports = loader
    
    // style-loader
    
    function loader(source){
        
    }
    loader.pitch = function(request){  // 这个request的就是当前路径 没有包含当前
      //  css-loader less-loader
      console.log(request);
      let script = `
        let style = document.createElement('style');
        <!--返回相对路径  只执行行内loader-->
        style.innerHTML = require(${loaderUtils.stringifyRequest(this, '!!' + request)});
        document.head.appendChild(style);
      `
      // 返回的结果 会在浏览器中运行
      return script;
    
    }
    module.exports = loader
    
    
    // css-loader
    // css-loader的作用就是把所有url的内容 都变成require('文件名的形式')
    function loader(source) {
      let reg = /url\((.*?)\)/g;
      let current;
      let pos = 0;
      let arr = [`let lists = []`];
      while (current = reg.exec(source)) { //lastIndex
        // 数组类型 [匹配的字符串,分组中的内容]
        let [matchUrl, p] = current;
        let index = reg.lastIndex - matchUrl.length
        // lastIndex就是匹配结束的位置
        arr.push(`lists.push(${JSON.stringify(source.slice(pos, index))})`);
        arr.push(`lists.push("url("+require(${p})+")")`)
        pos = reg.lastIndex;
      }
      arr.push(`lists.push(${JSON.stringify(source.slice(pos))})`);
      arr.push(`module.exports = lists.join('')`);
      console.log(arr.join('\r\n'));
      return arr.join('\r\n');
    }
    module.exports = loader;
复制代码

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

产品经理的20堂必修课

产品经理的20堂必修课

徐建极 / 人民邮电出版社 / 2013-9-1 / 59.00元

《产品经理的20堂必修课》以作者八年的产品经理工作实践为基础,通过系统的理论结合丰富的实例的方法,全面地总结了作为一名互联网产品经理所应掌握的知识。 《产品经理的20堂必修课》分为三大部分。 讲产品:深入剖析互联网产品成功的要素,分别从需求导向、简单原则、产品运营、战略布局等维度,分析如何让产品在残酷的互联网竞争中脱颖而出。 讲方法:着重分析优秀的产品团队运作的工作方法和程序,详......一起来看看 《产品经理的20堂必修课》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

SHA 加密
SHA 加密

SHA 加密工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换