Webpack Tapable Source Code
Introduction
Webpack 作为主流的打包工具,提供了自定义扩展的loader
和plugin
,丰富了周边生态。如果想自己写一个plugin
,需要对相关的hooks
有所了解,而 webpack 对hooks
的实现则是建立在tapable
这个库上的,本篇文章希望通过对tapable
源码的梳理,以加深webpack
的相关知识以及部分设计模式的理解。
Webpack 作为主流的打包工具,提供了自定义扩展的loader
和plugin
,丰富了周边生态。如果想自己写一个plugin
,需要对相关的hooks
有所了解,而 webpack 对hooks
的实现则是建立在tapable
这个库上的,本篇文章希望通过对tapable
源码的梳理,以加深webpack
的相关知识以及部分设计模式的理解。
Babel 在 2021 年一共进行了 2 个minor
版本的更新,增加了一些Stage 4 proposals
的支持,以及一些Top-level
的配置项(targets, assumptions)。伴随着这些更新,结合babel-loader和babel-preset-react-app我们来探究一下在 2021 年该如何使用 Babel。
@babel/preset-env
是官方推荐的preset
,只需要配置相关的targets
就可以转换当前代码到目标环境的代码,遵循browserslist的相关配置,主要配置项如下:
配置目标环境,如果不指定,则会转换所有 ES2015-ES2020 的代码到 ES5.而不是使用 browserslist 的defaults
配置(> 0.5%, last 2 versions, Firefox ESR, not dead)。
配置@babel/preset-env
如何处理polyfills
,可选项为"usage"
|"entry"
|false
"entry"
这个配置会自动将import "core-js/stable";
和import "regenerator-runtime/runtime"
转换为目标环境的按需引入,举个例子:
1 | import 'core-js/stable'; |
在不同环境下可能转换为:
1 | import 'core-js/modules/es.string.pad-start'; |
但是有个缺点是用不到的 polyfill 也可能会引入进来,因为entry
配置只针对目标环境,而不是具体代码
"usage"
这个配置则会自动引入代码中需要的 polyfill,且不需要显示声明import core-js
,推荐使用该配置
false
不自动添加 polyfill,也不自动转换import core-js
为按需引入
当 useBuiltIns 配置项为entry
或usage
时生效,默认值为"2.0"
,建议配置为minor version
的具体版本号
最初的 JavaScript 设计时没有模块化相关的概念,但是随着前端的发展及其工程化的引进和借鉴,相关的模块化思想也被引入了前端领域,其中CommonJS
的模块化解决方案一直屹立不倒。为了更好的理解CommonJS
,本篇文章依据Module:CommonJS modules相关文档,借鉴loader.js的相关源码,自己手动实现一个CommonJS module
;
每个被 require 的模块,在执行之前都被一个函数包裹,类似于:
1 | (function (exports, require, module, __filename, __dirname) { |
这样做可以防止模块内的定义的变量提升到全局作用域,同时提供了module
,exports
等变量供当前模块使用
require()
does:require()
加载模块的顺序具体可以参考这段伪代码,简单概括如下:
path
,fs
等核心模块/
, ./
, ../
开头的文件,如果不带文件后缀,则按照.js
, .json
,.node
依次尝试,有的话加载对应的文件内容/
, ./
, ../
开头的文件夹,先查找文件夹下的package.json
,如果package.json
定义了”main”,则加载”main”对应的内容,没有则寻找对应的文件夹下的 index 文件,然后按照第三步的加载文件顺序依次查找并加载node_modules
文件夹下的内容对于最新版本的Node.js
则增加了ECMAScript modules相关的加载规则,有兴趣的可以了解一下。
在日常的前端开发中,涉及到的工作内容大多和 UI 有关,比如说页面样式调整之类的基础工作。但是随着前端的发展,很多业务逻辑都放到了前端,例如文件生成和下载,图片处理等功能,这时候就涉及到了前端的二进制相关的内容,这篇文章从二进制相关内容和 API 出发,探究前端二进制相关的用途。
ArrayBuffer 是一段基础的,固定长度的二进制数据,类似于其他语言的byte array
。不能直接修改相关的内容,但是可以通过TypedArray
和DataView
进行读写。
1 | const buffer = new ArrayBuffer(8); |
如上所示,可以通过 new ArrayBuffer 创建新的 buffer, slice 截取 buffer 内容,slice 的操作类似于Array.prototype.slice
TypedArray 提供了多种类型用来处理和操作二进制数据,如下所示[1]:
Uint8Array 在处理小数位的时候采用的是向下取整,Uint8ClampedArray 则是采用四舍五入的形式取整,举个例子:
1 | Uint8Array([0.9]); // 0 |
Uint8ClampedArray 当赋值在区间[0,255]
之外,则只有取值为 0 或者 255 的两种情况,所以更多的运用于防止溢出的情况,例如增加图片的亮度[2]
成熟的编程语言一般都有相应的包管理工具,比如说 Python 中的 pip,Java 中的 Maven,PHP 中的 composer 等等。
对于 Node.js 来说,可选择的包管理工具比较多,比较有名的包括 npm,yarn 和 pnpm。
作为 Node.js 包管理系列文章的第一篇,这里先简单介绍 package 及其相关的周边内容
package 和 module 是相对的概念,官方文档上是这么定义的:
A package is a file or directory that is described by a
package.json
file. A package must contain apackage.json
file in order to be published to the npm registry.
A module is any file or directory in the node_modules directory that can be loaded by the Node.js require() function
可以看出来 package 和 module 相互纠缠,相互包含,共同组成了 Node.js 的生态
在日常的工作中,很多场景下需要知道一个元素的位置信息与尺寸信息,但是涉及到这方面的属性与方法很多,有时候难以抉择使用哪个方法或属性比较合适,这就需要我们详尽掌握元素位置与尺寸相关的知识,才能熟能生巧,灵活运用。
clientHeight&clientWidth
这两个属性都是整数形式的只读的属性,其中:
1 | clientHeight = CSS height + CSS padding - height of horizontal scrollbar |
如下图所示:
offsetHeight&offsetWidth
这两个属性也是整数形式的只读的属性,其中:
1 | offsetHeight = CSS height(include horizontal scrollbar if rendered) + CSS padding + CSS borders (可以理解为元素包括边框的高度) |
如下图所示:
正则表达式(Regular Expression)是使用单个字符串来描述、匹配一系列符合某个句法规则的一串字符。我在之前的学习工作中,遇到正则表达式,往往都是直接搜索相关问题的结果,或者尝试用其他方法解决。也尝试过学习相关的规则,但是过一段时间不用之后,往往会生疏乃至忘记。这篇文章尝试着理解并消化正则表达式相关的知识。
正则表达式是匹配模式,不是匹配字符,就是匹配位置
正则表达式除了匹配常规的 a-z,A-Z,0-9 等字符外,还存在着一些特殊字符,如下所示
字符 | 记忆方法 |
---|---|
\t | tab |
\v | vertical tab |
\f | form feed |
\r | return |
\n | new line |
虽然叫字符组,但是只匹配字符组中的某个字符,比如[abc]
只匹配 a,b,c 中的一个。对应的如果不想匹配某几个字符,则需要在字符组最前面加上**脱字符(^),形如[^abc],则表示匹配除 a,b,c 之外的其他字符。使用连字符(-)**则可以匹配连续的一段字符,形如 a-z,0-9。另外有如下相关的简写形式来表示对应的字符区间。
正则表达式 | 匹配区间 | 记忆方法 |
---|---|---|
\d | [0-9] | digit |
\D | [^0-9] | opposite to \d |
\w | [0-9a-zA-Z_] | word**(注意有下划线_)** |
\W | [^0-9a-za-z_] | opposite to \w |
\s | [\t\v\n\r\f] | space character |
\S | [^\t\v\n\r\f] | opposite to \s |
. | [^\n\r\u2028\u2029] | 匹配除换行符之外的所有字符 |