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;
复制代码

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

查看所有标签

猜你喜欢:

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

Introduction to Programming in Java

Introduction to Programming in Java

Robert Sedgewick、Kevin Wayne / Addison-Wesley / 2007-7-27 / USD 89.00

By emphasizing the application of computer programming not only in success stories in the software industry but also in familiar scenarios in physical and biological science, engineering, and appli......一起来看看 《Introduction to Programming in Java》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

html转js在线工具
html转js在线工具

html转js在线工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具