webpack原理解析(二)实现一个简单的Loader

简介: webpack中 loader 是一个非常重要的概念,loader 可以简单的理解成一个文件处理器,webpack使用 loader 来处理各类文件,比如 .scss转成成 css文件, 小图片转换成base64图片。

Loader是什么


webpack中 loader 是一个非常重要的概念,loader 可以简单的理解成一个文件处理器,webpack使用 loader 来处理各类文件,比如 .scss转成成 css文件, 小图片转换成base64图片。


本质上讲,loader 只是导出为函数的 JavaScript 模块,webpack打包的时候,会调用这个函数,把上一个loader产生的结果或资源文件(resource file)传入进去。

这次我打算开发一个把普通图片转换成 .webp 格式的 Loader,以达到减小图片大小的目的。


Loader 工具库


开发 loader 之前,先要了解两个 loader开发的工具包——loader-utilsschema-utils


  • loader-utils 用于获取 loader 的 options


  • schema-utils 用于校验 loader 的 optionsJSON Schema 结构定义的是否一致。


import { getOptions } from 'loader-utils';
import { validateOptions } from 'schema-utils';
const schema = {
  // ...
}
export default function(source) {
  // 获取 options
  const options = getOptions(this);
  // 检验loader的options是否合法
  validateOptions(schema, options, 'Demo Loader');
  // 在这里写转换 loader 的逻辑
  // ...
};


Loader 开发准则


  • 单一职责:一个 loader 只处理一件事情,保证简单和可维护,复杂场景可以用多个 loader 组合完成。


  • 模块化:保证 loader 是模块化的。loader 生成模块需要遵循和普通模块一样的设计原则。


  • 无状态:在多次模块的转化之间,我们不应该在 loader 中保留状态。每个 loader 运行时应该确保与其他编译好的模块保持独立,同样也应该与前几个 loader 对相同模块的编译结果保持独立。


总之一句话,我们在写一个 loader 的时候,保持其职责单一,只需要关心输入和输出就好。


同步 loader 和 异步 loader


loader之所以有同步和异步之分,是因为有些资源的处理比较耗时,需要异步处理,等待处理完成后再继续执行。loader 用 this.callback() 返回处理结果,如下:


this.callback(
  err: Error | null,
  content: string | Buffer,
  sourceMap?: SourceMap,
  meta?: any
);


  1. 第一个参数必须是 Error 或者 null


  1. 第二个参数是一个 string 或者 Buffer。


  1. 可选的:第三个参数必须是一个可以被这个模块解析的 source map。


  1. 可选的:第四个选项,会被 webpack 忽略,可以是任何东西(例如一些元数据)。


// 同步loader 返回多个处理结果
module.exports = function(content, map, meta) {
  this.callback(null, someSyncOperation(content), map, meta);
};


同步模式下,如果返回结果只有一个,也可以直接使用 return 返回结果。


// 同步loader 只返回一个处理结果
module.exports = function(content, map, meta) {
  return someSyncOperation(content);
};


异步模式下使用 this.async 来获取 callback 函数


module.exports = function(content, map, meta) {
  var callback = this.async();
  someAsyncOperation(content, function(err, result, sourceMaps, meta) {
    if (err) return callback(err);
    callback(null, result, sourceMaps, meta);
  });
};


开发自己的 Loader


项目目录结构


|--src


|   |--cjs.js  //commonJs 入口


|   |--index.js // loader 主文件


|   |--options.json // loader options 定义文件


|--babel.config.js


|--package.json


|--readme.md


定义 options


options 里只有一个属性 quality, 用来控制生成 .webp 文件的质量,定义如下:


{
  "additionalProperties": true,
  "properties": {
    "quality": {
      "description": "quality factor (0:small..100:big), default=75",
      "type": "number"
    }
  },
  "type": "object"
}


图片格式转换


cwebp 这个js模块提供了普通图片和.webp 之间相互转换的功能。


const CWebp = require('cwebp').CWebp
/**
 * 普通图片转 .webp图片
 * @param {string | buffer} img 图片绝对路径或二进制流
 * @param {number} quality 生成 webp 图片的质量,默认75
 * @returns .webp 文件流
 */
async function convertToWebp (img, quality = 75) {
  let encoder = new CWebp(img)
  encoder.quality = quality
  let buffer = await encoder.toBuffer()
  return buffer
}


编写 loader


import schema from './options.json'
export default async function loader (content) {
  // 异步模式
  let callback = this.async()
  // 获取 options
  const options = loaderUtils.getOptions(this) || {}
  // 验证 options
  validateOptions(schema, options, {
    name: 'webp Loader',
    baseDataPath: 'options'
  })
  try {
    // 普通图片转 .webp
    let buffer = await convertToWebp(content, options.quality)
    callback(null, buffer)
  } catch (err) {
    callback(err)
  }
}
// loader 接收文件流
export const raw = true


到这里这个 Loader 就基本完成了。


使用


// webpack.config.js
module.exports = {
  // 其他配置
  // ...
  module: {
    rules: [{
      test: /\.(png|jpg|gif)$/,
      use: [{
        loader: 'file-loader',
        options: {
          name: '[name].[ext].webp'
        }
      },{
        loader: 'webp-loader',
        options: {
          quality: 70 
        }
      }]
    }]
  }
}


总结


其实写一个 Loader 并没有想象中的那么复杂,只要掌握了基本要点,你也可以拥有自己的 Loader。


相关文章
|
3月前
|
安全 算法 网络协议
解析:HTTPS通过SSL/TLS证书加密的原理与逻辑
HTTPS通过SSL/TLS证书加密,结合对称与非对称加密及数字证书验证实现安全通信。首先,服务器发送含公钥的数字证书,客户端验证其合法性后生成随机数并用公钥加密发送给服务器,双方据此生成相同的对称密钥。后续通信使用对称加密确保高效性和安全性。同时,数字证书验证服务器身份,防止中间人攻击;哈希算法和数字签名确保数据完整性,防止篡改。整个流程保障了身份认证、数据加密和完整性保护。
|
5月前
|
存储 缓存 算法
HashMap深度解析:从原理到实战
HashMap,作为Java集合框架中的一个核心组件,以其高效的键值对存储和检索机制,在软件开发中扮演着举足轻重的角色。作为一名资深的AI工程师,深入理解HashMap的原理、历史、业务场景以及实战应用,对于提升数据处理和算法实现的效率至关重要。本文将通过手绘结构图、流程图,结合Java代码示例,全方位解析HashMap,帮助读者从理论到实践全面掌握这一关键技术。
164 14
|
6月前
|
前端开发
在Webpack配置文件中,如何配置loader以处理其他类型的文件,如CSS或图片
在Webpack配置文件中,通过设置`module.rules`来配置loader处理不同类型的文件。例如,使用`css-loader`和`style-loader`处理CSS文件,使用`file-loader`或`url-loader`处理图片等资源文件。配置示例:在`rules`数组中添加对应规则,指定`test`匹配文件类型,`use`指定使用的loader。
|
6月前
|
运维 持续交付 云计算
深入解析云计算中的微服务架构:原理、优势与实践
深入解析云计算中的微服务架构:原理、优势与实践
240 3
|
6月前
|
JavaScript 前端开发
Webpack中loader的使用场景
Webpack中的Loader用于处理和转换模块文件,如将TypeScript转为JavaScript、CSS预处理等,通过配置不同的Loader,可以灵活地支持多种文件类型和语言,实现模块化开发与构建优化。
|
6月前
|
前端开发 JavaScript
webpack 中 loader 和 plugin 的区别
在 webpack 中,loader 用于转换模块的源代码,如将 TypeScript 转为 JavaScript;而 plugin 则扩展了 webpack 的功能,可以执行更复杂的任务,如优化打包文件、注入环境变量等。两者共同作用于构建流程的不同阶段。
|
2月前
|
机器学习/深度学习 数据可视化 PyTorch
深入解析图神经网络注意力机制:数学原理与可视化实现
本文深入解析了图神经网络(GNNs)中自注意力机制的内部运作原理,通过可视化和数学推导揭示其工作机制。文章采用“位置-转移图”概念框架,并使用NumPy实现代码示例,逐步拆解自注意力层的计算过程。文中详细展示了从节点特征矩阵、邻接矩阵到生成注意力权重的具体步骤,并通过四个类(GAL1至GAL4)模拟了整个计算流程。最终,结合实际PyTorch Geometric库中的代码,对比分析了核心逻辑,为理解GNN自注意力机制提供了清晰的学习路径。
293 7
深入解析图神经网络注意力机制:数学原理与可视化实现
|
2月前
|
机器学习/深度学习 缓存 自然语言处理
深入解析Tiktokenizer:大语言模型中核心分词技术的原理与架构
Tiktokenizer 是一款现代分词工具,旨在高效、智能地将文本转换为机器可处理的离散单元(token)。它不仅超越了传统的空格分割和正则表达式匹配方法,还结合了上下文感知能力,适应复杂语言结构。Tiktokenizer 的核心特性包括自适应 token 分割、高效编码能力和出色的可扩展性,使其适用于从聊天机器人到大规模文本分析等多种应用场景。通过模块化设计,Tiktokenizer 确保了代码的可重用性和维护性,并在分词精度、处理效率和灵活性方面表现出色。此外,它支持多语言处理、表情符号识别和领域特定文本处理,能够应对各种复杂的文本输入需求。
283 6
深入解析Tiktokenizer:大语言模型中核心分词技术的原理与架构
|
2月前
|
传感器 人工智能 监控
反向寻车系统怎么做?基本原理与系统组成解析
本文通过反向寻车系统的核心组成部分与技术分析,阐述反向寻车系统的工作原理,适用于适用于商场停车场、医院停车场及火车站停车场等。如需获取智慧停车场反向寻车技术方案前往文章最下方获取,如有项目合作及技术交流欢迎私信作者。
154 2
|
3月前
|
机器学习/深度学习 算法 数据挖掘
解析静态代理IP改善游戏体验的原理
静态代理IP通过提高网络稳定性和降低延迟,优化游戏体验。具体表现在加快游戏网络速度、实时玩家数据分析、优化游戏设计、简化更新流程、维护网络稳定性、提高连接可靠性、支持地区特性及提升访问速度等方面,确保更流畅、高效的游戏体验。
118 22
解析静态代理IP改善游戏体验的原理

推荐镜像

更多