webpack实战,手写loader和plugin
序言
对于 webpack
来说, loader
和 plugin
可以算是需求程度最为广泛的配置项了。但是呢,单单止步于配置可能还不够。如果我们自己有时候想要 diy
一个需求,但是 webpack
又没有相关的 loader
和 plugin
。那这个时候我们可能就得开始造点轮子来供给自己使用了。
因此,在今天的文章当中,将带领大家手写一个简易的 loader
和 plugin
,并学会如何在项目中运用自己所编写的 loader
和 plugin
。
一起来学习吧~📢
一、如何编写一个Loader
1. 碎碎念
之前的文章中我们讲到了关于 loader
的一些配置。那如果把那些引用的 loader
改为我们写的 loader
,该怎么处理呢?
现在,我们来了解一下,如何手写一个简易的 loader
,并运用到我们的项目当中。
2. 项目结构
首先用一张图,来看我们的项目结构。如下图所示:
其中 loaders
文件夹下放置我们想要写的 loader
,同时里面的 replaceLoader.js
文件放置我们即将要写的 loader
的代码逻辑。之后,index.js
文件是我们的入口文件,放置我们的业务逻辑。 webpack.config.js
文件放置关于 webpack
的相关配置,而 dist
文件夹内的内容,放置的是我们通过 webpack
打包后,生成的打包文件。
3. 业务代码编写
(1)入口文件代码
现在,我们先来编写入口文件 index.js
的代码。具体代码如下:
console.log('hello monday');
(2)编写loader
入口文件的内容很简单,我们想要达到的目的就是输出 hello monday
这个语句。现在,我们来编写 loader
的内容,已达到对入口文件 index.js
的内容进行修改。 replaceLoader.js
文件的代码具体如下:
module.exports = function(source) {const result = source.replace('monday', 'mondaylab');this.callback(null, result);
}
以上的代码意思为,将入口文件 index.js
文件中的 monday
替换为 mondaylab
。这样写似乎没啥问题,但是大家有没有想过,我们有时候传的属性可能会很诡异,不一定每次都能像这样以字符串的形式来替换。
所以,我们引用 webpack
官方推荐的 loadertils
这个工具,来解决这个问题。
第一步: 安装 loader-utils
插件。具体命令如下:
npm install loader-utils --save-dev
第二步: 改造 loader
文件。接下来,我们对 replaceLoader.js
文件进行改造升级,具体代码如下:
const loaderUtils = require('loader-utils');//用function的原因在于为了业务层可以调用this
//source为引入文件的源代码
module.exports = function(source) {//getOptions会自动地帮我们分析this.query,然后把参数的所有内容放在options里面去const options = loaderUtils.getOptions(this);const result = source.replace('monday', options.name);this.callback(null, result);
}
大家可以看到,通过使用 loaderUtils
插件,间接地,调用 getOptions
方法,来自动的帮我们分析 this.query
,从而取到我们想要的内容。
值得注意的是,我们还需要再了解一下 this.callback
的内容。
一般情况下,如果我们接收到了源代码 source
,那么现在我们只能对源代码做处理。但是呢,有的时候,我们想要使用一些 sourceMap
,或者对源代码分析好了之后,我们不仅想要返回源代码,还要把 sourceMap
也带回去。
因为我们 return
的时候只能 return
一个参数,其余的一些额外的内容就带不出去了。这个时候呢,我们就需要 this.callback
来帮我们把 sourceMap
给带出去。因此,一般用 this.callback
来返回内容。
(3)引用loader
现在,我们在 webpack.config.js
中,来引入我们上面的 loader
。具体配置如下:
const path = require('path');module.exports = {mode: 'development',entry: {main: './src/index.js'},module: {rules: [{test: /\.js/,use: [{loader: path.resolve(__dirname, './loaders/replaceLoader.js'),//上面的options.name中的nameoptions: {name: 'mondaylab'}} ]}]},output: {path: path.resolve(__dirname, 'dist'),filename: '[name].js' }
}
通过以上方式,我们写了一个简易的 loader
,这个 loader
实现了将 monday
替换为 mondaylab
的功能。并且供我们在 webpack
中使用自己书写的 loader
。
(4)在loader里面做一些异步的操作
好了现在,如果我们想要给 loader
做一些异步操作,该怎么实现呢?
在我们所写的 loader
当中,加入异步操作,那么我们需要调用官方提供给我们的 this.async()
这个 API
来实现。现在,我们来改造一下 replaceLoader.js
文件的代码。具体代码如下:
const loaderUtils = require('loader-utils');module.exports = function(source) {const options = loaderUtils.getOptions(this);//调用this.async()这个API,来给异步代码使用const callback = this.async();setTimeout(() => {const result = source.replace('monday', options.name);callback(null, result);}, 1000);
}
通过这种方式,我们就可以在 loader
中编写异步代码,来达到我们想要的效果。
(5)loader路径自定义
有一个很小的注意点就是,当我们在配置 webpack.config.js
文件中, loader
的路径时,每回都要 path.resolve
去寻找路径文件。文件少的时候还好,但如果遇到多文件的时候呢?岂不是会很麻烦。
所以,我们引用 resolveLoader
来简化它。现在我们在 webpack.config.js
文件中进行改造。具体配置如下:
const path = require('path');module.exports = {// 先到node_modules中去找,找不到则去./loaders目录下去找resolveLoader: {modules: ['node_modules', './loaders']},module: {rules: [{test: /\.js/,use: [{loader: 'replaceLoader'}]}]}
}
参考 前端进阶面试题详细解答
通过配置 resolveLoader
,来对文件文件目录进行查找,从而简化了路径内容。
二、如何编写一个Plugin
1. 碎碎念
在讲解 plugin
之前,我们先来了解 loader
和 plugin
的区别。
当我们在源代码里面,去引入一个新的 js
文件,或者是一个其他格式的文件时,这个时候我们可以借用 loader
,来帮我们处理我们引用的 loader
文件。 loader
的作用就在于,帮助我们处理引用的模块。
而 plugin
呢,是当我们在做打包的时候,在某些具体时刻上,比如说,当我们打包结束之后,我们要生成一个 html
文件,这个时候,我们就可以使用一个 htmlWebpackPlugin
的插件。使用它之后,他就会在打包结束之后,帮我们生成对应的 html
文件。
再比如,我们要在打包之前,把 dist
目录进行清空,这个时候我们就可以使用 cleanWebpackPlugin
来帮助我们做这件事情。
所以, plugin
插件,在什么时候生效呢?
它在我们打包过程中的某些时刻里,就是插件生效的场景。
plugin
的编写相对于 loader
来说,会难一点点。但是呢,如果有看过 webpack
源码的小伙伴们可能会知道, webpack
的一些底层原理都是依据 plugin
来进行编写的。所以,我们还是有必要来学习一下 plugin
的编写。
下面就带领大家来编写一个简易的 plugin
~
2. 项目结构
对于 webpack
的 plugin
来说,它是是基于发布者订阅的设计模式,也可以说是基于事件驱动来实现的。在这个事件驱动里,代码之间的执行,是通过事件来进行驱动的。
接下来,我们就来写一个简易的 plugin
。
首先用一张图,来看我们的项目结构。如下图所示:
其中 plugins
文件夹下放置我们想要写的 plugin
,同时里面的 copyright-webpack-plugin.js
文件放置我们即将要写的 plugin
的代码逻辑。之后,index.js
文件是我们的入口文件,放置我们的业务逻辑。 webpack.config.js
文件放置关于 webpack
的相关配置,而 dist
文件夹内的内容,放置的是我们通过 webpack
打包后,生成的打包文件。
3. 业务代码编写
(1)入口文件代码
现在,我们先来编写入口文件 index.js
的代码。具体代码如下:
console.log('hello monday');
(2)编写plugin
现在,我们来编写 plugin
的内容, copyright-webpack-plugin.js
文件的代码具体如下:
class CopyrightWebpackPlugin {//编写一个构造器constructor(options) {console.log(options)}apply(compiler) {//遇到同步时刻compiler.hooks.compile.tap('CopyrightWebpackPlugin',() => {console.log('compiler');});//遇到异步时刻//当要把代码放到dist目录之前,要走下面这个函数//Compilation存放打包的所有内容,Compilation.assets放置生成的内容compiler.hooks.emit.tapAsync('CopyrightWebpackPlugin', (Compilation, cb) => {debugger;// 往代码中增加一个文件,copyright.txtCompilation.assets['copyright.txt'] = {source: function() {return 'copyright by monday';},size: function() {return 19;}};cb();})}
}module.exports = CopyrightWebpackPlugin;
上面的这个插件中想要实现的功能就是,获取版权信息。
(3)引用plugin
现在,我们在 webpack.config.js
中,来引入我们上面的 plugin
。具体配置如下:
const path = require('path');
const CopyrightWebpackPlugin = require('./plugins/copyright-webpack-plugin');module.exports = {mode: 'development',entry: { main: './src/index.js'},plugins: [new CopyrightWebpackPlugin({name: 'monday'})],output: {path: path.resolve(__dirname, 'dist'),filename: '[name].js'}
}
通过上述代码,我们可以了解到,在(2)中,我们首先需要定义一个类,之后呢,在类中写一个构造器和一个 apply()
方法来调用。然后呢,大家看到(3),通过 require
的方式,来进行 new 实例 ,实例化一个插件,从而在项目中使用这个插件。
最终,我们项目进行打包时,就会生成一个 dist
目录,并且在目录下增加一个 copyright.txt
文件,并且文件中的内容就是 copyright by monday
。
三、结束语
在上面的文章中,讲解了关于loader和plugin的基本编写思路,以及如何在项目中对他们进行运用,相信大家对这一块内容有了基础的认识。
到这里,loader和plugin的编写讲解就结束啦!希望对大家有帮助~
相关文章:
webpack实战,手写loader和plugin
序言 对于 webpack 来说, loader 和 plugin 可以算是需求程度最为广泛的配置项了。但是呢,单单止步于配置可能还不够。如果我们自己有时候想要 diy 一个需求,但是 webpack 又没有相关的 loader 和 plugin 。那这个时候我们可能就得开始造点轮…...
STM32CubeMX按键模块化 点灯
本文代码使用 HAL 库。 文章目录前言一、按键原理图二、CubeMX 创建工程三、代码讲解:1. GPIO的输入HAL库函数:2. 消抖:3. 详细代码四,实验现象:总结前言 我们继续讲解 stm32 f103,这篇文章将详细 为大家讲…...
C#专栏目录(长期更新)
文章目录C# 基础C#进阶C#应用WPF基础WPF 3D小游戏C# 基础 1996年,微软用年薪三百万美刀的价格从Borland挖来了大神海尔斯伯格,开始了J开发,用以对抗Java。但SUN公司认为此举违反了Java开发平台的中立性,对微软提出诉讼。C#正是在…...
BurpSuite配置抓取HTTPS数据包
简介 我们在渗透测试的过程中,经常会遇到HTTPS的网站,Burp默认是没有办法抓取HTTPS的包的,想要让Burp抓取Https的包也很好办,只需要浏览器安装相关的证书即可,接下来将配置过程做一个记录。 前置条件: 1.J…...
图片转base64格式返回给前端,前端如何展示?
图片以base64形式在页面上展示出来在这里要说到Data URI scheme,它可以直接将一些小的数据直接嵌入到网页中,不需要再引入。支持格式如下data:, 文本数据data:text/plain, 文本数据data:text/html, HTML代码data:text/html;base64, base64编码的HTML代码…...
C++入门知识【超详解】
目录1.认识Chello worldC关键字2.命名空间3.std标准库4.输入输出5.缺省参数6.函数重载7.引用7.1引用的概念7.2引用的场景1.作参数2.作返回值7.3引用的注意点7.4指针和引用的区别8.auto关键字9.基于范围的for循环10.内联函数10.1概念10.2特征11. C98中的指针空值1.认识C hello …...
零基础、非计算机系学Python该如何上手?
首先我觉得要放平心态,不用过多去纠结是不是专业出身这回事。 想学那就认真去学,我们最终目标是掌握Python这门技能。 非计算机专业同时零基础,想自学Python该如何上手?分享我自学Python的几点建议吧。 1、重视基础 Python是一…...
关于 vue3 模板引用
文章目录前言1.访问模板引用2.v-for中的模板引用3.组件上的ref前言 如果我们需要直接访问组件中的底层DOM元素,可使用vue提供特殊的ref属性来访问 1.访问模板引用 在视图元素中采用ref属性来设置需要访问的DOM元素 a. 该ref属性可采用字符值的执行设置 b. 该ref属…...
Redis | 安装Redis和启动Redis服务
目录 一、Redis简介 1.1 简介 二、Redis安装 2.1 Windows安装Redis 2.2 Linux安装Redis 三、Redis服务启动和停止 3.1 Windows启动Redis服务 3.2 Linux启动Redis服务 四、Redis设置密码远程连接 4.1 为Redis登陆设置密码 4.2 设置Redis允许远程连接 五、Redis常…...
博客要考虑的最佳WordPress主题
有太多的选择会瘫痪你做决定的能力。有太多的WordPress主题,但仅仅只需要一个并且它是要合适的。我们建立了数十个 WordPress 博客并安装了数百个主题。根据我们所有的经验,我们发现Newspaper是大多数用户的最佳WordPress博客主题。这个自适应、强大的主…...
C 学习笔记 —— 函数指针
函数指针 上面的第二个char (* f) (int);写法就是函数指针的声明; 首先,什么是函数指针?假设有一个指向 int类型变量的指针,该指针储存着这个int类型变量储存在内存位置的地址。 同样,函数也有地址,因为函…...
FastDDS-3. DDS层
3. DDS层 eProsima Fast DDS公开了两个不同的API,以在不同级别与通信服务交互。主要API是数据分发服务(DDS)数据中心发布订阅(DCPS)平台独立模型(PIM)API,简称DDS DCPS PIM…...
9.2 IGMPv2
实验目的 (1) 熟悉IGMPv2的应用场景 (2) 掌握IGMPv2的配置方法 实验拓扑 实验拓扑如图9-17所示: 图9-17:IGMPv2 实验步骤 配置IP地址(请参考上一个实验)运行IGPÿ…...
巨头混战,抢着“兜底”自动驾驶安全
诚然,中国汽车行业的发展绝对不会拘泥于电动化,必定会在电动化的基础上,迎接下半场的快速智能化。 2021年6月,长城汽车线控底盘全球首次发布。 彼时,长城汽车技术副总裁宋东先宣布,整合了线控转向、线控制…...
RightCapital 第一轮面试题
现在我们就马上开始吧! 答案在文末 JavaScript 是一门单线程的静态类型语言(单选题) 正确 错误 在 JavaScript 中下面哪种类型的值是不可变的(immutable)(单选题) Object Symbol Array Date …...
Python曲线肘部点检测-膝部点自动检测
文章目录一. 术语解释二. 拐点检测肘部法则是经常使用的法则。很多时候,可以凭人工经验去找最优拐点,但有时需要自动寻找拐点。最近解决了一下这个问题,希望对各位有用。一. 术语解释 **肘形曲线(elbow curve)**类似人胳膊状的曲线ÿ…...
【算法题】最大矩形面积,单调栈解法
力扣:84. 柱状图中最大的矩形 给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。 求在该柱状图中,能够勾勒出来的矩形的最大面积。 题意很简单,翻译一下就是:求该图中…...
活动策划|深度分析年货节活动该如何策划!
四月初,不平凡的初春开始恢复往日的平静。对于新零售行业,疫情的缓解也逐渐平稳生态链的运转。2020年新零售的格局在洗礼后,业务的聚焦点也从前端促销转移到后端履约的体验闭环,同时很大程度的推进企业在危机公关下的应对。618大促…...
Idea启动遇到 Web server failed to start. Port 8080 was already in use. 报错
Idea启动遇到问题-记录 报错英文提示: APPLICATION FAILED TO START Description: Web server failed to start. Port 8080 was already in use. Action: Identify and stop the process that’s listening on port 8080 or configure this application to liste…...
Python3中zip()函数知识点总结
1.引言 在本文中,我将带领大家深入了解Python中的zip()函数,使用它可以提升大家的工作效率。 闲话少说,我们直接开始吧! 2. 基础知识 首先,我们来介绍一些基础知识点: Python中的某些数据类型是不可变的…...
过滤器,监听器,拦截器的原理与在Servlet和Spring的应用
在Java Web的开发中,最原始和初期的学习都是从Servlet开始的,Servlet是Java最为耀眼的技术,也是Java EE的技术变革。目前大火主流的框架spring boot也的spring mvc部分也是基于拓展servlet完成的。回到之前的文章spring 实现了对servlet的封装…...
minio spring boot 秒传、分片上传、断点续传文件实现
此处后端使用的是前期封装的自定义starter,具体链接可参考:minio对象存储spring boot starter封装组件 这里主要针对前期封装的组件,做一个简单的应用,前端直传可查看之前的文章 秒传 秒传的逻辑比较简单,在前传上传…...
MTK平台使用Omnipeek分析空口协议讲解
讲解这个之前,我们先来了解下beacon/robe Request/Probe Response 三种帧 beacon帧 信标帧,由AP以一定的时间间隔周期性发出,以此来告诉外界自己无线网络的存在。 Beacon帧作为802.11中一个周期性的帧,Beacon周期调高,对应睡眠周期拉长,故节能(即越来休息100ms再起来…...
string和自动推断类型
欢迎来观看温柔了岁月.c的博客目前设有C学习专栏C语言项目专栏数据结构与算法专栏目前主要更新C学习专栏,C语言项目专栏不定时更新待C专栏完毕,会陆续更新C项目专栏和数据结构与算法专栏一周主要三更,星期三,星期五,星…...
【软件测试】从功能到自动化测试,测试人的进阶之路细节,这些必不可少......
目录:导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜)前言 测试流程࿰…...
C语言青蛙跳台阶【图文详解】
青蛙跳台阶前言1. 题目介绍2. 解题思路3. 利用图片来演示青蛙跳台阶的原理4. 如何用C语言实现青蛙跳台阶前言 在本文,我们要与一只活泼可爱的小青蛙合作,带领着它跳上台阶,这个小家伙精力充沛,特别擅长于跳跃。我们要让它做我们的…...
笔记(五)——list容器的基础理论知识
list容器是一个双向链表容器,可以高效地进行插入删除元素,但是不能随机存取元素(不支持at()和[]操作符)。一、list容器的对象构造方法list对象采用模板类的默认构造形式例如list<T> lst;#include<iostream>…...
浅谈网络中接口幂等性设计问题
所谓幂等性设计,就是说,一次和多次请求某一个资源应该具有同样的副作用。用数学的语言来表达就是:f(x) f(f(x))。 在数学里,幂等有两种主要的定义。 在某二元运算下,幂等元素是指被自己重复运算(或对于函数…...
《C Primer Plus》第13章复习题与编程练习
《C Primer Plus》第13章复习题与编程练习复习题1. 下面的程序有什么问题?2. 下面的程序完成什么任务?(假设在命令行环境中运行)3. 假设程序中有下列语句:4. 编写一个程序,不接受任何命令行参数或接受一个命…...
计算机SCI论文应该怎么作图? - 易智编译EaseEditing
计算机SCI论文,作图时要注意以下几个方面的问题: 1.图片的格式要tiff或者eps; 2.文件大小不能超过10M; 3.长和宽也给出了具体要求; 4.色彩模式要RGB或者灰度图; 5.文中的文字字体和大小; …...
电商建站系统/宁波seo推荐推广平台
解题思路:最短路的模板题,注意一个细节处理即可。 见代码: 1 #include<cstdio>2 #include<cstring>3 #include<algorithm>4 using namespace std;5 #define inf 0x3f3f3f3f6 const int maxn 1005;7 int vis[maxn], w[maxn][maxn], d[…...
广东网站制作哪家强/外贸网站搭建推广
SSM养老院信息管理系统摘 要随着互联网趋势的到来,各行各业都在考虑利用互联网将自己推广出去,最好方式就是建立自己的互联网系统,并对其进行维护和管理。在现实运用中,应用软件的工作规则和开发步骤,采用Java技术建设…...
做电力招聘的有哪些网站/seopeixun
最近在面试,发现Java爬虫对于小数据量数据的爬取的应用还是比较广,抽空周末学习一手,留下学习笔记 Java网络爬虫 简单介绍 爬虫我相信大家都应该知道什么,有什么用,主要的用途就是通过程序自动的去获取获取网上的信息数…...
门户网站模板 免费/专业seo网站优化推广排名教程
好程序员web前端教程分享JavaScript验证API,小编每天会分享一下干货给大家。那么今天说道的就是web前端培训课程中的章节。JavaScript验证API约束验证DOM方法PropertyDescriptioncheckValidity()如果 input 元素中的数据是合法的返回 true,否则返回 fals…...
重庆做网站的/企业网络营销业务
php实现的简单日历代码。例子:复制代码 代码示例:/*** php简单日历* edit: www.jbxue.com*/if(empty($year))$yeardate("Y"); //初始化年份if(empty($month))$monthdate("n"); //初始化月份$wd_ararray("日","一","二…...
做网站需求文档/南宁整合推广公司
代码如下2113: 1). xml可能的中文编码错误处理 def xml_Error_C(filename): fp_xmlopen(filename) fp_x#中文乱5261码改正 for i in range(os.path.getsize(filename)): i1 afp_xml.read(1) if a&: fp_xml.seek(-1,1) if fp_xml.read(6) : i5 continue else: fp…...