当前位置: 首页 > news >正文

深度解读Webpack中的loader原理

一、前言

webpack 是一个现代 JavaScript 应用的静态模块打包器。那么 webpack 是怎样实现不同种类资源模块加载的呢?

没错就是通过 loader。loader 用于对模块的源代码进行转换。loader 可以使你在 import 或加载模块时预处理文件。

我们带着下面几个问题,彻底吃透 loader ~

二、为什么要使用 loader

webpack 是如何加载资源模块的呢?我们先试着用 webpack 直接打包项目中的 css 文件。

初始化一个 webpack 项目,目录如下:

在 src 目录下新建了一个 index.css 文件,这里新建这个文件的目的就是以 css 文件为入口,尝试使用 webpack 单独打包它。

/* index.css */
body {margin: 0 auto;padding: 0 20px;width: 1000px;background-color: #ccc;
} 

调整下 webpack 配置,让入口文件路径指定为 index.css 的路径。

// webpack.config.js
module.exports = {entry: "./src/index.css",output: {filename: "bundle.js",},
}; 

然后我们到终端运行 npx webpack 命令,你会发现命令行会提示 Module parse failed: Unexpected token (1:5) 模块解析错误。

细心的同学会发现后面还紧跟着一句解决方案:You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file.

大致的意思就是说,您可能需要适当的 loader 来处理此文件类型,目前没有配置 loader 来处理此文件。

这里,loader 的重要性就凸显出来了。

三、怎么配置 loader

还是接着刚才打包 index.css 报错的问题。想加载 css 文件,我们可以试试常用的 css-loader。

yarn add css-loader -D 

webpack 配置也同步改下:

// webpack.config.js
module.exports = {mode: "none", // 避免不指定打包模式时弹出警告...module: {rules: [{test: /\.css$/,use: "css-loader",},],},
}; 

webpack 配置中 module 属性添加 rules 对象数组。这里面的 test 属性值为一个正则表达式,匹配当前 loader 对应处理文件的格式。use 属性值为 loader 名称。

再打包就不会报错了。

如果想要 index.css 模块在页面中生效,只需要额外添加一个 style-loader,样式就 OK 了。

style-loader 的作用可以理解为:建立了一个 style 标签,这个标签里面带入了 css 样式。标签最后追加到页面上。##### 参考webpack视频讲解:进入学习

注意配置多个 loader 时,执行顺序是从后往前执行的:

  • 最后的 loader 最早调用,将会传入原始资源内容
  • 第一个 loader 最后调用,期望值是传出 JavaScript 和 source map(可选)
  • 中间的 loader 执行时,会传入前一个 loader 传出的结果

所以 css-loader 放在最后。具体配置如下:

// webpack.config.js
module.exports = {...module: {rules: [{test: /\.css$/,use: ["style-loader", "css-loader"],},],},
}; 

假如你还要用到 less-loader,同理可知 rules 中 use 属性值应该为:["style-loader", "css-loader", "less-loader"]

四、怎么写一个 loader

想要实现的大致流程:

接下来,我们尝试实现上图 css-loader 和 style-loader 的简单版本。

4.1 创建 loader

我们在项目根目录下创建好 css-loader.js 和 style-loader.js 文件。

主要代码如下:

├── src ····································· source dir│ ├── index.css ······················· css module
+ │ └── index.js ························ entry module
+ ├── css-loader.js ······················· css loader├── package.json ························ package file
+ ├── style-loader.js ····················· style loader└── webpack.config.js ··················· webpack config file 
/* index.css */
body {margin: 0 auto;padding: 0 20px;width: 1000px;background-color: #ccc;
} 
// index.js
import "./index.css";
console.log("loader ok!"); 

每个 webpack 的 loader 都需要导出一个函数,这个函数就是我们这个 loader 对资源的处理过程,它的输入就是加载到的资源文件内容,输出就是我们加工后的结果。我们通过 source 参数接收输入,通过返回值输出。这里我们先尝试打印一下 source,然后在函数的内部直接返回一个字符串 hello webpack css-loader!,具体代码如下所示:

// css-loader.js
module.exports = (source) => {console.log(source);return "hello webpack css-loader!";
}; 

我们回到 webpack 配置文件中调整一下加载器规则,调整之后使用的加载器就是我们刚刚编写的这个 css-loader.js 模块,具体代码如下:

// webpack.config.js
module.exports = {mode: "none",// 入口改为 index.jsentry: "./src/index.js",output: {filename: "bundle.js",},module: {rules: [{test: /\.css$/,// 改下这里use: ["./css-loader"],},],},
}; 

温馨提示:这里的 use 中不仅可以使用模块名称,还可以使用模块文件路径,这点与 Node 中的 require 函数相同。

配置完成后,我们再次打开命令行终端运行打包命令,如下图所示:

从报错信息可以看出,loader 函数的参数就是文件的内容。

错误提示说: You may need an additional loader to handle the result of these loaders. (我们可能还需要一个额外的加载器来处理当前加载器的结果)

温馨提示:其实 webpack 加载资源文件的过程最后的结果必须是一段标准的 JS 代码字符串。

正常流程:

我们现在应该想到是 css-loader 出了问题。

4.2 css-loader

css-loader 主要作用就是将多个 css 模块整合到一起。

module.exports = (source) => {// 匹配 url(xxx) 类似结构const reg = /url((.+?))/g;// 位置下标let pos = 0;// 当前匹配的代码片段let current;const arr = ["let list = []"];while ((current = reg.exec(source))) {const [matchUrl, g] = current;const lastPos = reg.lastIndex - matchUrl.length;arr.push(`list.push(${JSON.stringify(source.slice(pos, lastPos))})`);pos = reg.lastIndex;arr.push(`list.push('url(' + require('${g}') + ')')`);}arr.push(`list.push(${JSON.stringify(source.slice(pos))})`);arr.push(`module.exports = list.join('')`);// 每行代码之间增加一个回车return arr.join("\n");
}; 

大致思路:

  • 整个 css 代码片段以 url(xxx) 类似结构为节点分成多个部分
  • url 里的路径改为 require 引入
  • 用数组的形式将 css 代码拼凑起来最后形成一个整体

loader 打包结果如下图:

这是输出的 bundle.js 的片段,就是把我们刚刚返回的字符串直接拼接到了该模块中。这里也解释了刚才打包语法报错的问题(loader 处理完必须返回 JS 代码)。

4.3 style-loader

style-loader 会把整合的 css 部分挂载到 head 标签中。

代码如下:

module.exports = function (source) {return `const styleElement = document.createElement('style');styleElement.innerHTML = ${JSON.stringify(source)}document.head.appendChild(styleElement);`;
}; 

4.4 写 loader 之后的总结

loader 就是一个函数,一旦有模块被 import 或者 require 时它就会去拦截这些模块的源码,对其进行改造,然后输出到另一个模块中,循环往复,最终输出到入口文件中,形成最终的代码。

也正是有了 loader 机制,我们才能通过 webpack 去加载任何我们想要加载的资源。

最后

最近还整理一份JavaScript与ES的笔记,一共25个重要的知识点,对每个知识点都进行了讲解和分析。能帮你快速掌握JavaScript与ES的相关知识,提升工作效率。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

相关文章:

深度解读Webpack中的loader原理

一、前言 webpack 是一个现代 JavaScript 应用的静态模块打包器。那么 webpack 是怎样实现不同种类资源模块加载的呢? 没错就是通过 loader。loader 用于对模块的源代码进行转换。loader 可以使你在 import 或加载模块时预处理文件。 我们带着下面几个问题&#…...

2023年全国最新二级建造师精选真题及答案

百分百题库提供二级建造师考试试题、二建考试预测题、二级建造师考试真题、二建证考试题库等,提供在线做题刷题,在线模拟考试,助你考试轻松过关。 一、单选题 1.关于法人在建设工程中的地位的说法,正确的是(&#xff0…...

为什么现代企业发展离不开CRM系统的助力

如今的CRM系统对于任何企业来说都重要,因为它能帮助企业收获新客户,保留现有客户,并且将不同部门的信息全部汇集,实时提供关于每位客户整体全面的看法。因此,销售、市场营销和客户支持等领域的客户直接服务员工能够做出…...

vb.net计算之.net core基础(1)-获取农历和天气

目录 .net core 简介创建hello,world应用程序获取天气和农历.net core 简介 .NET Core是适用于 Windows、Linux 和 macOS 的免费、开源托管的计算机软件框架。 它是微软开发的第一个官方版本,具有跨平台能力的应用程序开发框架 (Application Framework),未来也将会支持 Free…...

设计模式之代理模式详解和应用

目录1 代理模式定义2 代理模式的应用场景3 代理模式的通用写法4 从静态代理到动态代理5 静态模式在业务中的应用6 动态代理在业务中的应用7 手写JDK动态代理实现原理7.1 JDK动态代理的实现原理7.2 CGLib动态代理容易踩的坑8 CGLib代理调用API及原理分析9 CGLib和JDK动态代理对比…...

JavaScript HTML DOM 节点列表

HTML DOM 是一种文档对象模型,它允许开发人员使用 JavaScript 来访问和修改网页的内容和结构。节点列表是 HTML DOM 中一个重要的概念,它允许开发人员以编程方式访问和操作文档中的节点元素。 在本文中,我们将探讨 JavaScript HTML DOM 节点…...

【音视频处理】码率、帧率越高越清晰?分辨率、像素、dpi之间是什么关系?码率的真实作用,I帧、B帧、P帧是什么

大家好,欢迎来到停止重构的频道。本期我们介绍一下视频的一些基础概念,如帧率、码率、分辨率、像素、dpi、视频帧、I帧、P帧、gop等。会解释多少码率是清晰的,是否帧率越高越流畅等问题。这些概念是比较杂乱的,我们按这样的顺序介…...

Java基础-认识注释、标识符关键字

注释 平时我们编写代码,当代码量较小时候,我们还可以看懂自己写的代码。但是当项目结构一旦复杂起来,我们就需要用到注释啦。注释并不会被执行,是写给我们开发者看的。 在java中的注释有三种 标识符 常见关键字 Java所有的组…...

【C#】静态扩展方法

静态类特征:1.不能用sealed或abstract修饰符;2.必须直接继承System.Object类型,不能试任何其他类的派生类;3.不能实现任何接口;4.不能包含任何操作符;5.不能使用protected或者protected internal修饰的静态成员&#x…...

医疗电子方案——血压计方案

高血压人群越来越多了,尤其是老人。高血压是一种十分常见的慢性疾病,同时也是引发心血管疾病最主要的因素。有关数据表明,我国每年因高血压死亡的病例竟然达到上百万之多,占到全部死亡比例的20%以上。所以大多数家庭都需要备有家用…...

深度分析React源码中的合成事件

热身准备 明确几个概念 在React17.0.3版本中: 所有事件都是委托在id root的DOM元素中(网上很多说是在document中,17版本不是了);在应用中所有节点的事件监听其实都是在id root的DOM元素中触发;React自…...

17.微服务SpringCloud

一、基本概念 Spring Cloud 被称为构建分布式微服务系统的“全家桶”,它并不是某一门技术,而是一系列微服务解决方案或框架的有序集合。它将市面上成熟的、经过验证的微服务框架整合起来,并通过 Spring Boot 的思想进行再封装,屏蔽…...

Java基础面试题——JavaWeb专题

文章目录1.HTTP响应码有哪些2.Forward和Redirect的区别?3.Get和Post请求的区别4.介绍下OSI七层和TCP/IP四层的关系5.说说TCP和UDP的区别6. 说下HTTP和HTTPS的区别7.说下HTTP、TCP、Socket的关系是什么?8. 说下HTTP的长链接和短连接的区别9.TCP原理10. Co…...

MySql数据库约束

概述、目的 概念:约束是作用于表中字段上的规则,用于限制存储在表中的数据。 目的:保证数据库中数据的正确性、有效性和完整性。 分类: 约束描述关键字非空约束限制该字段的数据不能为nullNOT NULL唯一约束保证该字段的所有数据都…...

TripleCross:一款功能强大的Linux eBPF安全研究工具

关于TripleCross TripleCross是一款功能强大的Linux eBPF安全研究工具,该工具提供了后门、C2、代码库注入、执行劫持、持久化和隐蔽执行等功能。 功能介绍 1、使用一个代码库注入模块通过往进程的虚拟内存中写入命令来执行恶意代码; 2、提供了一个行劫…...

2023最牛教程,手把手教你成为年薪30W的测试开发

随着互联网行业的高速发展,快速高质量的产品版本迭代成为企业始终立于不败之地的迫切需求,而在短期迭代的快节奏中,传统测试工作面对更大压力,无法持续提供高效率高质量的人力支撑,所以越来越多的企业需要技术更为全面…...

“深度学习”学习日记。--ImageNet、VGG、ResNet

2023.2.14 一、小历史: 在2012年的ILSVRC(ImageNet Large Scale Visual Recognitoin Chanllege),基于深度学习的方法AlexNet 以绝对优势获胜并且他颠覆了以前的图片识别方法,此后深度学习方法一直活跃在这个舞台。 二、ImageNet&#xff1…...

关于APP下载量提升的技巧

关于APP应用下载量提升,很多人都不是很了解。今天厦门巨神峰小编给大家说下关于APP下载量提升的几个技巧。 一、抓住流行趋势,提升APP下载量 1、利用社交媒体进行推广。社交媒体是当下最流行的推广手段,可以有效的将APP的消息传播到更多的用…...

以“大数据”赋能产业链精准招商

​ 随着我国产业发展的不断迭代升级,传统招商模式的不足逐步凸显,侧重土地与税费优惠的同质化竞争招商以及来者不拒的无门槛型招商已经遏制了区域产业的发展,导致各产业园区很难形成产业集聚及持续的吸引力。在这样的大环境下,产业…...

内存泄漏检测组件 -- hook

目录 hook malloc与free出现的问题 builtin_return_address(N) C/CLinux服务器开发/后台架构师【零声教育】-学习视频教程-腾讯课堂 hook malloc与free出现的问题 #define _GNU_SOURCE #include <stdio.h> #include <dlfcn.h> #include <stdlib.h> /****…...

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...

stm32G473的flash模式是单bank还是双bank?

今天突然有人stm32G473的flash模式是单bank还是双bank&#xff1f;由于时间太久&#xff0c;我真忘记了。搜搜发现&#xff0c;还真有人和我一样。见下面的链接&#xff1a;https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...

React Native 开发环境搭建(全平台详解)

React Native 开发环境搭建&#xff08;全平台详解&#xff09; 在开始使用 React Native 开发移动应用之前&#xff0c;正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南&#xff0c;涵盖 macOS 和 Windows 平台的配置步骤&#xff0c;如何在 Android 和 iOS…...

练习(含atoi的模拟实现,自定义类型等练习)

一、结构体大小的计算及位段 &#xff08;结构体大小计算及位段 详解请看&#xff1a;自定义类型&#xff1a;结构体进阶-CSDN博客&#xff09; 1.在32位系统环境&#xff0c;编译选项为4字节对齐&#xff0c;那么sizeof(A)和sizeof(B)是多少&#xff1f; #pragma pack(4)st…...

拉力测试cuda pytorch 把 4070显卡拉满

import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试&#xff0c;通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小&#xff0c;增大可提高计算复杂度duration: 测试持续时间&#xff08;秒&…...

分布式增量爬虫实现方案

之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面&#xff0c;避免重复抓取&#xff0c;以节省资源和时间。 在分布式环境下&#xff0c;增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路&#xff1a;将增量判…...

使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台

🎯 使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台 📌 项目背景 随着大语言模型(LLM)的广泛应用,开发者常面临多个挑战: 各大模型(OpenAI、Claude、Gemini、Ollama)接口风格不统一;缺乏一个统一平台进行模型调用与测试;本地模型 Ollama 的集成与前…...

Java毕业设计:WML信息查询与后端信息发布系统开发

JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发&#xff0c;实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构&#xff0c;服务器端使用Java Servlet处理请求&#xff0c;数据库采用MySQL存储信息&#xff0…...

基于IDIG-GAN的小样本电机轴承故障诊断

目录 🔍 核心问题 一、IDIG-GAN模型原理 1. 整体架构 2. 核心创新点 (1) ​梯度归一化(Gradient Normalization)​​ (2) ​判别器梯度间隙正则化(Discriminator Gradient Gap Regularization)​​ (3) ​自注意力机制(Self-Attention)​​ 3. 完整损失函数 二…...

Python+ZeroMQ实战:智能车辆状态监控与模拟模式自动切换

目录 关键点 技术实现1 技术实现2 摘要&#xff1a; 本文将介绍如何利用Python和ZeroMQ消息队列构建一个智能车辆状态监控系统。系统能够根据时间策略自动切换驾驶模式&#xff08;自动驾驶、人工驾驶、远程驾驶、主动安全&#xff09;&#xff0c;并通过实时消息推送更新车…...