Infinite Entertainment, Zero Cost: Get Your Free Books, Music, and Videos Today!

前端工具鏈沒有說的秘密

Description
随缘更新。
不妨也关注作者 GitHub:https://github.com/g-plane
Advertising
We recommend to visit

Last updated 5 months, 1 week ago

唯一负责人: @hhhhub
吃瓜中心: @cgzx2

Last updated 1 month, 3 weeks ago

每日不停更新,点个关注吧

Last updated 6 months ago

hace 1 mes, 2 semanas

Flow 在 v0.209.0 版本(发布于 2023 年 6 月)新增一个语法支持:component syntax,这个语法专门针对编写 JSX 组件而设计。但这个语法曾在后续几个版本被临时关闭(能识别、解析语法,但会报错提示不支持),直到 v0.214.0 版本(发布于 2023 年 8 月)才重新开启。不过笔者粗略地浏览了这几个版本的更新日志,都没有看到有关 component syntax 的说明。 component syntax 大致像函数声明:通过 component 关键字(注意这只是…

Medium

New Flow Language Features for React

Write Safer and more Succinct React with Flow

Flow 在 v0.209.0 版本(发布于 2023 年 6 月)新增一个语法支持:component syntax,这个语法专门针对编写 JSX 组件而设计。但这个语法曾在后续几个版本被临时关闭(能识别、解析语法,但会报错提示不支持),直到 v0.214.0 版本(发布于 2023 年 8 月)才重新开启。不过笔者粗略地浏览了这几个版本的更新日志,都没有看到有关 component syntax 的说明。 …
hace 2 meses

Flow 在 v0.209.0 版本(发布于 2023 年 6 月)新增一个语法支持:component syntax,这个语法专门针对编写 JSX 组件而设计。但这个语法曾在后续几个版本被临时关闭(能识别、解析语法,但会报错提示不支持),直到 v0.214.0 版本(发布于 2023 年 8 月)才重新开启。不过笔者粗略地浏览了这几个版本的更新日志,都没有看到有关 component syntax 的说明。

component syntax 大致像函数声明:通过 component 关键字(注意这只是 Flow 自己的「软关键字」或「上下文关键字」),随后列出参数作为组件的 props:

```
component LargeHeader(color: string) {
return


}

```

另外,从 v0.218.0 版本(发布于 2023 年 10 月)起可以像指定函数返回类型那样,指定当前组件会渲染出什么组件:

```
component LargeHeader(color: string) renders Header {
return


}

```

也是从 v0.218.0 版本起,可以指定 props 传入什么组件:

```
component Layout(header: renders Header) {
return

{header};
}

```

它还有更多的特性,例如可选参数、类型限定等,详细可阅读 Flow 文档:
1. https://flow.org/en/docs/react/component-syntax/
2. https://flow.org/en/docs/react/render-types/

hace 4 meses, 3 semanas

通常的来说,我们对 V8 的认知便是性能优化极好的 JavaScript 运行引擎,但是我们可以来看一下这俩段代码。

- Object.defineProperty([], 'length', {value: \-1, configurable: true})
- Object.defineProperty([], 'len' + 'gth', {value: \-1, configurable: true})

从 JavaScript 的语义上来说,这俩段代码并没有什么不同,但是当我们将他们运行在 Chrome 或者 Node.js 中,我们便能得到俩个截然不同的错误。

`Object.defineProperty([], 'length', {value: -1, configurable: true})
VM8179:1 Uncaught RangeError: Invalid array length
at Function.defineProperty ()
at :1:8
(anonymous) @ VM8179:1

Object.defineProperty([], 'len' + 'gth', {value: -1, configurable: true})
VM8183:2 Uncaught TypeError: Cannot redefine property: length
at Function.defineProperty ()
at :2:8`

那这和 V8 性能优化极好又有什么关系呢?我们可以在他们的源码中看到如下内容:

https://github.com/v8/v8/blob/04f51bc70a38fbea743588e41290bea40830a486/src/objects/objects.cc#L3004-L3007

```
if (*name == ReadOnlyRoots(isolate).length_string()) {
// 2a. Return ArraySetLength(A, Desc).
return ArraySetLength(isolate, o, desc, should_throw);
}

```

简单理解一下,就是在这里直接使用了引用与系统内的常量字符串 "length" 引用进行了一个 O(1) 的快速匹配,从而优化了性能,但是也导致了我们上面的错误。

那么为什么 'length' 和 'len' + 'gth' 有区别呢?这个没有优化吗?我们可以在这Exploring V8's strings: implementation and optimizations》看到实际上在 V8 中存在着不同的字符串,当我们使用 %DebugPrint 对俩段内容进行输出的时候,我们可以发现:
- %DebugPrint('leng'+'th'):ONE_BYTE_STRING_TYPE- %DebugPrint('length'):ONE_BYTE_INTERNALIZED_STRING_TYPE
这也是为什么后者没办法作为一个常量字符串和全局只读常量字符串 "length" 进行比较的原因。

----
主题之外,其实我们刚刚的代码上面看到一段东西:

https://github.com/v8/v8/blob/04f51bc70a38fbea743588e41290bea40830a486/src/objects/objects.cc#L3003

```
// TODO(jkummerow): Check if we need slow string comparison.

```

#v8 #defineProperty #JavaScript

GitHub

v8/src/objects/objects.cc at 04f51bc70a38fbea743588e41290bea40830a486 · v8/v8

The official mirror of the V8 Git repository. Contribute to v8/v8 development by creating an account on GitHub.

通常的来说,我们对 V8 的认知便是性能优化极好的 JavaScript 运行引擎,但是我们可以来看一下这俩段代码。
hace 5 meses

ECMAScript 有三种严格(即不会执行类型转换)相等判断的语义,分别是:
- SameValue
- SameValueZero
- IsStrictEqual

对于这三种语义,它们都会对类型不同的值返回 false;对于非数字类型的值,都会执行 SameValueNonNumber 语义;而对于数字类型,它们的差别在于比较 NaN、+0 与 -0 有不同:
- SameValue 会视 NaN 与 NaN 为相等,+0 与 -0 不等;
- SameValueZero 会视 NaN 与 NaN 为相等,+0 与 -0 相等;
- IsStrictEqual 会视 NaN 与 NaN 为不等,+0 与 -0 相等。

下面是三种语义所被使用到的常见地方:

SameValue:
- Object.is
- WeakMap 的 keyWeakSet

SameValueZero:
- Array.prototype.includes
- %TypedArray%.prototype.includes
- Map 的 keySet

IsStrictEqual:
- === 比较运算符
- Array.prototype.indexOf
- Array.prototype.lastIndexOf
- %TypedArray%.prototype.indexOf
- %TypedArray%.prototype.lastIndexOf

感谢 @JackWorks

----------------

笔者根据规律想到一个辅助记忆办法:
1. === 与 indexOf/lastIndexOf 都是 ECMAScript 中很早就存在的,对于这类「古老」的都使用 IsStrictEqual 语义;
2. includes 与 Map/Set 是 ES2015 及更晚才出现的,对于这类「新兴」的使用 SameValueZero 语义;
3. 虽然 Object.is 也是新的,但它可以被认为有别于 === 的存在,所以特殊处理(Jest 等测试框架对于 toBe 断言就是使用 Object.is 去判断);
4. WeakMap 的 key 与 WeakSet 不允许是 primitive type,因此可以忽略。

hace 5 meses

位于全局的 isNaNNumber.isNaN 虽然函数名字一样,但具体行为是有差别的:
- isNaN 会对传入的参数执行类型转换,转换为数字类型后再去判断;
- Number.isNaN 则不会执行类型转换,对于数字类型以外的值均返回 false

请尽可能使用 Number.isNaN 以避免因类型转换而导致意外发生。

参考:
1. MDN 上的示例代码
2. ECMAScript 标准中关于 isNaN 的说明
3. ECMAScript 标准中关于 Number.isNaN 的说明

hace 5 meses

TypeScript 新特性抢先看:新的内置类型 NoInfer<T> 。它与 Uppercase 等类型都属于 marker type(即 lib.d.ts 里的实现只有一个 intrinsic 关键字),编译器对于这类 marker type 都会特殊对待。

正如其名, NoInfer<T> 类型用于防止类型被自动推断。也就是说,在某些地方(通常是函数泛型等),如果不希望该处的类型被自动推断,就可以使用。例如:(下面的例子由官方示例简化而来)

```
declare function test(a: T, b: NoInfer): void

test('a', 'b')

```

playground
在这个例子中,参数 a 的类型将被自动推断,此时 T 为 'a' ;而对于参数 b,因为我们使用 NoInfer 类型,那么它也就不会参与自动推断,由于前面 T 被推断为 'a' ,而此处的实际参数却是 'b' ,因此类型不兼容进而报错。
如果上面没有使用 NoInfer , T 将会被推断为 'a' | 'b' ,读者可以打开 playground 链接自行修改测试。

另外, NoInfer<T> 不会对 T 产生影响,例如:

```
type Result = NoInfer<'s'>

```

playground
类型 Result 仍为 's' 。

在参与类型计算时, NoInfer<T> 其实只是被替换为 unknown 。以上面的 test 函数为例,它相当于:

```
declare function test(a: T, b: unknown): void

```

这里 T 仍为 'a' ,只不过因为使用了 unknown 而无法对参数 b 进行约束。

值得注意的是,在使用 NoInfer<T> 时,一定要留意 T 在可被推断的地方被推断为了什么类型。例如:

```
declare function test2(a: T, b: NoInfer): void

test2('a', 'b')

```

playground
它跟上面的 test 函数相比, T 没有了 extends string 的泛型约束。这时,参数 a 将被推断为 string 而不是 'a' ,也就是 T 推断为 string 。但因为 'b' 满足 string 的要求,因此这段代码不会报错。

PR: https://github.com/microsoft/TypeScript/pull/56794

hace 5 meses

pnpm 有一个名为 resolution-mode 的配置项(在 .npmrc 文件中配置),但无论是 resolution-mode 这个名字还是配置项的值的名字,都相当的不直观,更不方便记忆。

背景:resolution-mode 影响的是 pnpm 的版本解析。适当的配置可以减少子依赖所带来的供应链攻击,并且在缓存的作用下可以加快安装速度。但请不要看到「安全」「快速」就盲目配置这个选项——阅读完下面的内容,并明确自己的意图再去动这个配置。

在解释之前,先做一些约定:
1. 不管在不同模式下,版本解析会有怎样的不同,它们都遵循语义化版本。这是大前提。
2. 下文的「子依赖」表示的是依赖的依赖,也可以被称为「间接依赖」。

目前 resolution-mode 允许设为下面三个值之一:
- highest(当前的默认值)这个模式下所有依赖(包括项目的直接依赖以及子依赖)都会被解析到最新版本;
- time-based 这个模式下项目的直接依赖会被解析到最老版本,而子依赖则会被解析到该直接依赖发布时间之前的最新版本;
- lowest-direct 这个模式下仅仅是项目的直接依赖会被解析到最老版本,子依赖会被解析到最新版本。

下面以这样的一个项目为例子:(测试时所使用的 pnpm 版本为 8.11.0)

```
{
"dependencies": {
"ora": "^6.2.0"
}
}

```

ora 库有多个依赖,但我们在这里只需要关注 ora 本身以及它的其中一个依赖 chalk 的版本,并通过 pnpm 生成的 lock file 来得知它们被解析到哪个版本。

- 当 resolution-mode 设为 highest 时:ora 的版本被解析为 6.3.1,chalk 的版本被解析为 5.3.0。两个库都被解析到最新版本。
- 当 resolution-mode 设为 time-based 时:ora 的版本被解析为 6.2.0,chalk 的版本被解析为 5.2.0。ora 能满足语义化版本的最老版本是 6.2.0,而 ora 6.2.0 的发布时间为 2023/3/19 18:13:22,在此时间之前 chalk 最新版本是 5.2.0。(尽管 ora 的 package.json 文件里声明的是 "chalk": "^5.0.0"
- 当 resolution-mode 设为 lowest-direct 时:ora 的版本被解析为 6.2.0,chalk 的版本被解析为 5.3.0。可以看到即使 ora 作为项目的直接依赖被解析为 6.2.0,但它的依赖 chalk 被解析到最新版本即 5.3.0。

参考:
1. pnpm 关于 resolution-mode 的文档
2. ora 的所有版本
3. chalk 的所有版本

hace 5 meses
hace 5 meses

Babel 和 SWC 都有 core-js 相关的选项,用于精确控制要注入的 polyfill。对于 Babel,它在 @babel/preset\-env 的选项下[1];对于 SWC,它在配置文件的 env.coreJs 下[2]。

不管是 Babel 还是 SWC,这个字段允许一个类型为数字和字符串的值,用于表示版本。如果是字符串,可以指定具体的版本,比如 "3.34" ,这没什么问题。

但如果指定的是数字,比如 23 ,以及没有具体版本的字符串,比如 "2""3" ,这时 core-js 的版本解析将是反直觉的:它指定的不是最新版本(比如本文撰写时最新是 3.34.0),而是 3.0.0。

这会导致一些新的 polyfill 不被会注入到代码中。以 Object.hasOwn 为例,它的 polyfill 是在 core-js 3.17.0 版本 中稳定的。如果我们在项目中给这个 core-js 选项指定了 3"3" ,那么将不包含这个 polyfill,从而导致出现意外。

由于 Babel 的 REPL 不允许以 JSON 方式任意修改 Babel 的配置,所以下面将以 SWC 为例。但这个行为对于 Babel 和 SWC 都是一样,也就是两边都存在这个问题:
- 指定为 3 时,输出代码不包含 polyfill 的 import 语句:playground
- 指定为 "3.16" 时,这个版本的 core-js 未稳定 Object.hasOwn 的 polyfill,所以还是没有它的 polyfill:playground
- 指定为 "3.17" 时就有它的 polyfill 了:playground

实际上,Babel 和 SWC 的文档都明确建议这个选项指定 semver-minor 以避免这个问题。

参考:
[1] Babel 文档
[2] SWC 文档

感谢 @Austaras

hace 5 meses, 1 semana

Deno 在仓库 readme 上补充了 "Deno" 一词的读音:/ˈdiːnoʊ/ 。

相关 PR:https://github.com/denoland/deno/pull/21341

We recommend to visit

Last updated 5 months, 1 week ago

唯一负责人: @hhhhub
吃瓜中心: @cgzx2

Last updated 1 month, 3 weeks ago

每日不停更新,点个关注吧

Last updated 6 months ago