likes
comments
collection
share

速读《现代 JavaScript 库开发》,快速掌握前端基础库开发逻辑

作者站长头像
站长
· 阅读数 65

不想看文字?没有关系,博客提供视频版了!点击直接进入

这是一个专门讲解 前端库 开发的一本书,如果你想要开发一个属于自己的库,或者想要了解库开发的技术,那么这本书肯定可以帮助到你。

前言

Hello,各位小伙伴大家好,我是 Sunday

在现在的技术团队之中,我们普遍觉得,能够在 github 上开发和维护各种 的工程师都是 高手

速读《现代 JavaScript 库开发》,快速掌握前端基础库开发逻辑

速读《现代 JavaScript 库开发》,快速掌握前端基础库开发逻辑

速读《现代 JavaScript 库开发》,快速掌握前端基础库开发逻辑

毕竟能够对企业项目提供底层支持的人,在技术领域总会存在一定的优越感。

那么开发一个库真的很难吗?其实不是的。

只要我们掌握了一定的 “方式和技巧” ,那么任何一名开发者都可以开发出属于自己的库。

《现代 JavaScript 库开发》是今年 1月(2023 年 1 月),最新发布的一本教我们如何开发一个 前端库 的书籍,作者是 颜海镜、候策

作者在书中提到: “每一个开发者都拥有两个世界:1. 业务世界、 2. 开源世界。”

很多开发者非常熟悉业务世界,但是对开源世界却非常陌生。其实开源世界并没有那么神秘,我们只需要花费一点时间,就可以掌握进入开源世界大门的钥匙,甚至可以在里面自由翱翔。

那么下面,就让我们进入到 《现代 JavaScript 库开发》之中,一起来看看,开源世界是什么样子。

正文

对于整本书中的内容而言,我们先把第十二章排除在外。这样的话,整本书中内容共分为三个大部分,共十一个章节。

  • 首先是第一大部分 原理:这一部分包含第一到第五章的内容,主要是讲解了我们应该如何 从零到一开发一个库。在这一块内容里面,作者从一个 深拷贝的clone 开始,为我们讲解了一个库如何 开发、构建、测试、开源以及维护 的详细流程,以及注意事项。这一块内容,也是我们这次所讲解的一个重点。
  • 第二大部分 技术:这一部分主要包含 第六、第七 两个章节,在这两个章节中,作者为我们介绍了 JavaScript 库设计的最佳实践 以及 安全的最佳实践。整本书中内容也开始 从原理讲解逐步转化为实战操作
  • 第三大部分 实战:包含了从 第八章到第十一章 四个章节,这里就是一个纯实战环节,里面提供了 九个 不同类型的基础库构建代码,比如 jslib-basetemplate.js 等等。里面会涉及到大量的代码,所以不在咱们这次的重点讲解范围之内。

最后就是 第十二章 ,这一章其实可以理解为 后置的前言。为什么这么说呢?因为在十二章中,作者提供了 知识全景图技术全景图 这两个东西:

速读《现代 JavaScript 库开发》,快速掌握前端基础库开发逻辑

其中知识全景图,为我们描述了整本书中所涉及到的所有知识点。如图所示,我们可以知道整本书中所设计到的所有知识大体可以分为 4 类:

  • 最佳实践
  • 工程化
  • 技术方案
  • 开源

其中每一大类都分成了若干小类,而在每一个小类的前面都有一个数字,这个数字表示了 涉及到这一块知识点的章节。 比如:兼容性就分别在第二章和第六章中进行了涉猎。

速读《现代 JavaScript 库开发》,快速掌握前端基础库开发逻辑

接下来是技术全景图,在咱们的 脑图 中,我为每一个技术库都附上了对应的链接,大家可以直接点击链接跳转。整本书中涉及到的技术库也是分成了四大块:

  • 构建
  • 环境语言
  • 测试
  • 工具链

这些技术库在本书中会多次出现,所以我在这里截个图,把它钉在右上角位置。大家可以对照着来去看。

第一章:从零开发一个 JavaScript 库

那么明确好了,整个书中一个大体的逻辑之后,接下来咱们就来看一下 《第一章:从零开发一个 JavaScript 库》。

中国有句古话,叫做万事开头难,所以如果大家想要开发一个自己的 JavaScript 库 的话,那么开始的时候是最难的。

为此,作者为我们指定了 4 个步骤,来告诉我们应该如何开始构建一个自己的库:

想法

首先第一步叫做 我有一个想法:我们回忆自己到目前为止的职场生涯,有没有出现过 “我有一个想法” 这样的场景。

速读《现代 JavaScript 库开发》,快速掌握前端基础库开发逻辑

我相信大多数的小伙伴应该都会时不时的冒出过各种各样的想法,只不过可能很多想法冒出来之后,又被放弃掉了。放弃掉的原因可能有很多,但是 一个好的想法就是一个好的开始

那么构建库同样如此,一个好的库一定是从一个好的想法开始的,所以当你有了一个好的想法之后,别着急放弃它,也许它可能帮助你走上职业的巅峰。

目标

当我们有了一个想法之后,那么我们其实就已经迈出了第一步了。接下来要做的就是 把这个想法,变成一个可以具体实现的目标。

这个目标并非要是 一成不变 的,它也并不一定要是一个多么宏大的目标。

它可以很小,也可以不断进行调整。就像 facebook 的创始人扎克伯克,在一开始创建 facebook(最初叫做 the facebook) 的时候,也只是想要做一个哈佛大学内部通讯系统。尤大(尤雨溪)在一开始构建 vue 的时候,也只是想做一个内部的小型视图渲染工具。

但是无论如何,这个目标一定要存在,因为只有有了目标之后,我们才可以有前进的动力。

设计

那么,当我们有了目标之后,接下来就是如何实现这个目标,也就是 设计

所谓的设计,指的是 把目标进行拆解多个可以实现的小目标,让我们可以一步一步的往前走。通过设计,我们可以把一个朦胧的大目标变成多个可以具体落地的小目标。

速读《现代 JavaScript 库开发》,快速掌握前端基础库开发逻辑

这样的小目标,不光可以让我们对今后要做的事情认知更加清晰,还可以增强我们的信心,让我们不至于轻易放弃。

编码

万事具备之后,最后剩下的就是 编写代码

很多小伙伴,因为没有库开发经验,所以可能会 以写业务代码的逻辑去编写库代码。那么编写库代码有什么不同的地方,和注意事项呢?

这正是咱们后面要做的内容。

开发一个深拷贝的库

那么现在让我们从一个 深拷贝的库 做实验。

大家假想一下,现在我们有了一个 想法: 要做一个深拷贝的工具库。

同时我们为这个想法指定了 目标: 该库可以完成复杂数据类型的深拷贝。

然后我们针对该目标,进行了对应的 设计: 第一步要创建一个 clone 的函数,接收一个复杂数据类型作为参数,返回深拷贝之后的数据。

那么根据我们的设计,得出了如下代码:

function type(data) {
    return Object.prototype.toString.call(data).slice(8, -1).toLowerCase()
}
​
function clone(source) {
    const t = type(source);
    if (t !== 'object' && t !== 'array') {
        return source;
    }
​
    let target ;
​
    if (t === 'object') {
        target = {};
        for(let i in source) {
            if (source.hasOwnProperty(i)) {
                target[i] = clone(source[i]); // 注意这里
            }
        }
    } else {
        target = [];
        for(let i = 0; i < source.length; i++) {
            target[i] = clone(source[i]); // 注意这里
        }
    }
​
    return target;
}

那么现在,代码已经有了,并且代码是完全可用的。

但是大家要记住,现在我们要开发的是一个基础工具库,而这个库是要给其他的开发者进行使用的。

所以,如果代码仅仅只是如此的话,那么很快我们就会遇到一些问题:

  • A 使用了 CommonJS 模块,但是不知道该如何引用这个库
  • B 说这个库在 IE 浏览器上面会报错

这就是我们在实际库开发中,经常会遇到的 issue

速读《现代 JavaScript 库开发》,快速掌握前端基础库开发逻辑

身为库的开发者,那么这样的 issue 是我们必须要解决的。但是具体应该怎么做呢?

第二章:构建

出现以上两个问题的原因,本质上是因为库的构建方式导致的。所以想要让我们的代码可以被开发者成功引用,那么我们必须要了解一定的构建方案。

作者在第二章中,描述了前端库构建必备的基础知识,让我们从 模块化 开始来看一下。

模块化

目前的前端模块化分为两大类:

  • UMDUMD 内部主要包含两种

    • AMD:异步模块定义,适用于 RequireJS 等模块加载器(用的已经不多了)
    • CJS:适用于 Node 环境和其他打包工具
  • ESM(ES Module):主要适用于浏览器端环境

通常情况下以上两大类的模块化方案,可以适用于大多数的模块化场景。

除此之外,还有一个叫做 iife 的,它主要用来构建自执行函数,可以适用于 <script> 标签 导入的形式。

打包体系

明确好了现在常用的几种前端模块化方案之后,那么下面咱们来看下如何把项目打包成对应的模块化代码,也就是 打包体系

现在常见的打包体系一共有三种 传统体系、Node 体系、工程化体系

对于这三种体系而言,作者给出了具体的对比图:

速读《现代 JavaScript 库开发》,快速掌握前端基础库开发逻辑

Rollup

在实际的库开发中,最常用的就是 Rollup 进行打包。

作者在书中列举出了使用 Rollup 进行打包的流程,但是因为 Rollup 这种库存在升级的情况。所以为了避免在未来出现 Rollup 打包方式变化的问题,我在脑图中放了官网的文档链接,大家可以根据文档链接来查看最新的 Rollup 打包方式。

对于 Rollup 而言,除了可以完成基础的打包功能之外,还可以实现其他的功能。

比如,添加 bannertreeshaking、以及 配合 babel 实现 ES5 兼容

以上四种书中提到的注意事项,我都为大家提供了对应的官方文档链接。大家可以按需进行查看。

第二章总结

那么到目前为止,我们已经把一个想法,变成了一个可以被开发者使用的基础库了。

但是大家需要注意的是,像我们这种基础库,将来可能会在很多的项目中被使用,所以为了自身的声誉考虑,我们必须要能够保证我们代码的严格质量。

那么这就要求,我们的代码需要通过多维度的单元测试才可以。那么单元测试怎么做呢?

第三章:测试

作者在第三章中提供了测试方案,其中主要以单元测试为主。内容大体为 如何设计测试用例、如何验证测试覆盖率、如何在浏览器环境中进行测试、已经如何进行自动化测试 这四部分。咱们来看一下。

首先,咱们先来了解下单元测试。单元测试可以被分为两大类:

  1. TDD(测试驱动开发):所谓测试驱动开发,指的 是一种软件开发过程中的应用方法。 以 “戴两顶帽子” 作为开发方式:先戴上实现功能的帽子,在测试的辅助下,快速实现其功能;再戴上重构的帽子,在测试的保护下,通过去除冗余的代码,提高代码品质。

速读《现代 JavaScript 库开发》,快速掌握前端基础库开发逻辑 3. BDD(行为驱动开发):而行为驱动开发指的 是一种敏捷软件开发的技术,它鼓励软件项目中的开发者、QA和非技术人员或商业参与者之间的协作。 BDD 的重点是 通过与利益相关者的讨论取得对预期的软件行为的清醒认识

而我们接下来要说的就是 BDD(行为驱动开发) 的方案。

要完成 BDD(行为驱动开发) 书中为我们介绍了两个依赖库 1. 测试库 Mocha@3.5.3 、2. 断言库 expect.js@0.3.1 ,为了避免库升级带来的不兼容性,我们在这里指定了对应的库版本。

Mocha 和 expect.js 基本使用流程,咱们这里不做过多介绍,官网和书上有详细的文档。

所以接下来咱们主要来看下保证质量的问题。作者在书中提到了测试质量保证的问题,主要分为 4 部分:

  1. 如何设计测试用例
  2. 如何验证测试覆盖率
  3. 如何在浏览器环境中进行测试
  4. 如何进行自动化测试

如何设计测试用例

测试用例的设计逻辑分为三部分:设计思路、编码方式、通过测试

首先咱们先来看设计思路。当我们去设计一个测试用例时,需要遵循 以参数为组进行测试 的方案。

比如下面这段代码:

速读《现代 JavaScript 库开发》,快速掌握前端基础库开发逻辑

这段代码中包含三个参数,所以我们在设计测试用例的时候,就可以分成三组来进行测试,每个参数一组,在对一个参数进行测试时,保证其他参数无影响

速读《现代 JavaScript 库开发》,快速掌握前端基础库开发逻辑

同样的道理,在我们之前的 clone 库 中,因为只包含一个参数,所以设计测试用例只需要分为一组即可:

速读《现代 JavaScript 库开发》,快速掌握前端基础库开发逻辑

明确好了设计思路之后,下面就可以写对应的编码内容:

var expect = require("expect.js");
var clone = require("../src/index.js").clone;
​
describe("function clone", function () {
    describe("param data", function () {
        it("正确用例", function () {
            // 基本数据类型
            expect(clone("abc")).to.equal("abc");
​
            // 数组
            var arr = [1, [2]];
            var cloneArr = clone(arr);
            expect(cloneArr).not.to.equal(arr);
            expect(cloneArr).to.eql(arr);
​
            // 对象
            var obj = { a: { b: 1 } };
            var cloneObj = clone(obj);
            expect(cloneObj).not.to.equal(obj);
            expect(cloneObj).to.eql(obj);
        });
​
        it("边界值用例", function () {
            expect(clone(1)).to.equal(undefined);
​
            expect(clone(undefined)).to.equal(undefined);
​
            expect(clone(null)).to.equal(null);
        });
    });
});
​

这个代码是我从随书代码中截取下来的,给大家作为参考,代码内容咱们这里不做讨论。

有了代码之后,最后执行测试代码逻辑就可以了。

如何验证测试覆盖率

在设计完基础的测试用例之后,接下来我们还需要做一件非常重要的事情,那就是验证 单元测试覆盖率。因为对于单元测试而言,它的目的是 测试代码的运行情况。 所以我们必须要尽量保证 项目中的每行代码最好都被测试过一次,即覆盖率尽量去靠近100%

那么想要实现这一点,作者给我们推荐了一个工具 nyc(Istanbul) ,利用它可以帮助我们完成代码覆盖率测试。

速读《现代 JavaScript 库开发》,快速掌握前端基础库开发逻辑

其中每个维度代表的含义:

  • File:文件
  • Stmts:语句覆盖率
  • Branch:分支覆盖率
  • Funcs:函数覆盖率
  • Line:行覆盖率
  • uncovered line:未覆盖的行号

如何在浏览器环境中进行测试

在前面的测试中主要是针对 Node.js 的环境进行的测试。但是很多时候我们可能需要借助浏览器环境来进行一些兼容性测试。

那么想要针对浏览器环境进行测试主要有两种方式:

  • 第一种是 模拟浏览器场景:想要模拟浏览器场景测试,那么可以通过 mocha-jsdom 来完成。

  • 第二章是 真实浏览器场景Mocha 支持在浏览器环境下运行,但是我们需要做一些事情才可以:

    • 首先,我们需要创建一个 index.html 文件,以方便在浏览器环境中运行
    • 其次,因为浏览器环境中不包含 CJSrequire 方法,所以我们需要手动加上这个 “垫子”,即:添加一个 require 函数,以防止出现 require is not defined 的错误

速读《现代 JavaScript 库开发》,快速掌握前端基础库开发逻辑

如何进行自动化测试

到目前为止,其实我们已经拥有了一个完善的测试方案,但是美中不足的是 目前我们仍需人工在浏览器中打开并查看结果

而对于 Chrome 浏览器而言,它提供了 Chrome Headless 的特性,我们可以在 Node 中借助 Puppeteer 工具,来直接启动 Chrome Headless,以实现 自动化测试 的效果。从而无需人工在浏览器中打开并查看结果。

第三章总结

这一章,主要讲解了测试相关的逻辑,里面涉及到了很多测试相关的库或者工具。

针对于目前的前端测试场景而言,除了作者所提到的工具之外,还是一些其他的工具也有了很高的使用率,比如 单元测试库:JestUI 自动化测试框架:Cypress 等等......

对于没有测试经验的同学来说,这一章的内容可能会有些晦涩难懂。但是好处在于我们并不需要一次性的掌握作者所提到的所有内容,只需要关注自己当下的测试用例场景即可。

第四章:开源

代码写好了,测试通过了。那么接下来就是:发布自己的库,也就是 开源

目前开源所指的主要有两部分:

  • 将你的代码发布到 Github 上,以供开发者查阅和贡献源代码
  • 将打包后的代码发布到 npm 上,以供开发者使用

但是当我们决定把代码进行开源时,也有一些坑,一个不慎可能也会给我们带来一些损失。作者在本章中,主要通过 4 个方面,来为我们介绍了开源的注意事项。

协议

首先第一个就是 开源协议。目前市面上常用的开源协议主要有三种 MIT、BSD、Apache,这三协议的对比如下:

速读《现代 JavaScript 库开发》,快速掌握前端基础库开发逻辑

目前这三种协议都有很多开源库在使用,下面是影响力比较大的项目以及它们的开源协议:

速读《现代 JavaScript 库开发》,快速掌握前端基础库开发逻辑

对于我们的库而言,通常情况下选择 MIT 协议即可。

文档

除了协议之外,第二个是文档,文档主要分为 4 类:

  • 首先是 README.mdREADME.md 文档应该是大家最为熟悉的了。每一个 Githubnpm 的库中,对当前库的介绍部分,就是 README.md 文档
  • 其次是 TODO.md 待办清单:它表示未来要添加的新功能和已经完成的新功能添加
  • 然后是 变更日志:CHANGELOG.md :它表示库更新的记录,每个版本的发布日期以及对应变化
  • 最后就是 API 文档:它介绍了当前库的一些基本用法。如果你的库比较简单,那么也可以把 API 文档 合并在 README.md

发布

当我们准备好协议、文档之后,下面我们就可以发布项目到 githubnpm 了。

把项目发布到 github 的流程和我们平时提交 git 其实是一样的,如果大家不知道如何提交 git 的话,那么可以搜索一下对应的文档,咱们这里就不去多说了。

第二个是 npm ,把项目发布到 npm 的流程可能有很多小伙伴没有操作过,所以我在这里给大家放了一个 链接,在书中作者也对这个发布进行了介绍。

统计

整个开源最后一块是统计。当我们发布了一个库之后,其实都会非常关心开发者对它的使用情况。就像我发布了一个视频之后,也会经常来看看播放量一样。

因为我们在发布的时候,其实是发布到了 githubnpm 两个不同的平台,所以在查看统计的时候,也需要根据不同的平台来进行查看。

首先是 github,在 github 不存在使用率这样的情况,衡量一个库好不好的指标只有一个,那就是 starstar 才是王道。

而对于 npm 而言,则存在下载量的概念。但是对于 npm 来说,它默认的统计只会统计从 npm i 的下载量。但是在国内很多小伙伴是使用淘宝镜像(cnpm)来下载的,这部分流量它是统计不上去的。

所以说如果想要统计一个准确的下载数据,那么作者为我们提供了一种方式,就是 自定义统计

npm 为每个命令都提供了两个钩子 prepost

比如,当我们使用 npm install 时,就存在 preinstallpostinstall 两个钩子,分别表示 install 之前和 install 之后。

那么我们就可以依据这个钩子,来实现自定义统计:

  1. postinstall 钩子中,指定执行文件

速读《现代 JavaScript 库开发》,快速掌握前端基础库开发逻辑 2. 在 postinstall.js 中通过 axios 完成统计

速读《现代 JavaScript 库开发》,快速掌握前端基础库开发逻辑 那么按照如上方式,当开发者 npm install 库 之后,我们就可以手动记录一次下载数据。

第四章总结

在这一章中,作者主要讲解了我们去开源项目时的一些注意事项。整体算是比较简单。

那么到现在为止,我们就已经完成了 开发、构建、测试、发布 这四步流程了,也就是说,现在我们已经拥有了一个属于自己的基础库。

但是开源库发布成功,并不代表就万事大吉了。库的开源并不是一个一劳永逸的事情,它需要我们持续的迭代和维护。

所以接下来我们就来看看,我们应该如何维护一个开源库。

第五章:维护

整个库的维护,作者从 4 个方面进行了阐述。

社区协作

首先是社区协作,这里的社区主要指的就是 github。而在 github 上的社区协作主要就是分为 3 种:

  • issue
  • 代码贡献
  • 捐赠

首先是 issue ,这个应该是大多数开发者最了解的一个东西了。它是 当前库的问题集合,大体可以分为三类 求助类:help wanted、故障类:bug、建议类:enhancement

身为库的开发者,对于 issue 必须要及时处理才可以。

当你的库在行业内拥有了一定的影响力之后,那么可能会有很多人为你的库贡献代码。贡献代码的人员可以大致被分为两类:非库开发人员库开发人员。 非库开发人员主要通过 Fork + Pull Request 的方式进行代码贡献。而库开发人员则不需要那么麻烦。

最后是捐赠,这个一般很少,大家最好不要寄予过高的希望。

编码规范

在刚才我们说过,当你的库拥有一定的影响力之后,可能会有很多人为你的库进行代码贡献。

那么一旦涉及到多人的合作开发,那么我们就需要控制编码规范。书中为我们提到了很多编码规范的处理方案,其中会涉及到大量的代码和逻辑。所以我们在这里就不去说了。

在这里顺道给我在慕课网上的课程打一个广告,我在慕课网上发布过 全新升级,基于Vue3新标准,打造后台综合解决方案 这样一门课程,在这门课程中也详细了编码规范的问题,大家可以根据需要进行查看。

持续集成

完全依靠 Git hook 进行编码规范处理,有的时候可能并没有那么可靠。所以作者也在书中提到了持续集成的概念。

目前在开源社区中常用的持续集成工具主要有三款 Github Actions、CircleCI、Travis CI。这三款都可以满足我们的开源需求,大家可以自行选择。

分支处理

最后就是 git 分支处理。

作者根据功能,把分支分为三类,分别是:

  • 主分支:稳定、没有 bug 的代码,并保证随时可以发布的状态
  • 功能分支:新功能开发时
  • 故障分支:出现 bug

除此之外,还有两种特殊情况:

  • 第一种是 Pull request:它表示其他人给开源项目提交的代码。 在 Github 上会提示我们如何进行操作,大多数时候确认无误,直接合并即可。
  • 第二种是 创建标签与历史:这个主要针对于发布新版本,或者特殊版本时的场景。主要用来记录当前的版本意义。

第五章总结

那么到这里为止,我们就已经讲完了从零开发一个库的流程以及注意事项,其中涉及到 开发、构建、测试、发布、维护 的一整套流程。

那么掌握到这里为止,其实大家就已经可以利用上述知识完成一个基础库的开发了。

但是如果你想要做的更好,并且可以及时规避一些风险的话,那么可以继续往下看。

第六章:设计更好的JavaScript库

从这一章开始,我们将会去讲解 开源库中的注意事项与风险点,以帮助大家更好地规避风险,从而设计更好的JavaScript 库,取得最大收益。

那么首先咱们来看一下,如何构建出一个更好地 JS 库。想要构建出一个更好的 JS 库,那么作者给出了 4 个方向 函数化、健壮性、兼容性、TS ,咱们一个一个来说。

函数很重要

其实我们在之前的时候说过很多次,函数在 JS 中被称之为第一公民。那么想要构建出一个可维护性更强的 JS 库,咱们就需要好好利用函数。

作者从两个维度对函数进行了介绍。

  • 首先是 命名:函数的命名以 见名知意 为第一要素,尽量不要使用 “少为人知”的缩写,如果不知道如何为函数命名,可以试用下 CodeIf (速度可能会有点慢)
  • 其次是 参数:作者在书中提到,参数的个数最好不要超过三个。如果你确实需要很多参数的话,那么可以使用 options 的模式,这种方式我们之前在 JavaScript 语言精粹 中也提到过

提高健壮性

开源库和业务代码的一个很大的不同在于 开源库会被很多人使用,会在各种各样业务场景中运行。根据使用者的不同,开源库的代码会比普通的业务代码存在更多的健壮性问题。

这个健壮性指的是:程序在遇到规范以外的输入,错误和异常时,仍能正常运行。

在这一小节中,作者分别从 参数防御、副作用处理、异常捕获 三个方面进行了描述。

参数防御

所谓参数防御指的是 使用者,未按照约定,传入了预料之外的参数。 那么在这种情况下,作为开源库的开发者就要通过 参数防御 的形式,保证程序不会出现崩溃的问题。

副作用处理

所谓副作用指的是:会引起副作用的代码。比如:

let name = '张三'
function setName (newName) {
  name = newName
}

在这段代码中,setName 方法的触发就会修改 全局变量 name 的值。此时的 setName 就被叫做会引起副作用的代码,也就是一个 副作用函数

而对于库中的代码而言,如果会引起大量的副作用,那么就会给使用者带来很大的麻烦。

异常捕获

程序在运行的过程中出现异常是非常正常的事情。但是这些异常的报错需要给用户明确的提示才可以。

浏览器兼容

再往后是浏览器兼容的问题。作者在这里给出了一个推荐的浏览器兼容目标,这个兼容目标是非常低的。大家可以根据自己的情况来选择。

速读《现代 JavaScript 库开发》,快速掌握前端基础库开发逻辑

TypeScript

最后就是 TypeScript 。在现在的库开发中,个人建议大家都应该使用 TypeScript,因为它可以在维护时,带来更高的可维护性。

第七章:安全防护

第七章主要介绍了安全防护的问题。这里的安全防护指的是 库代码的安全性

作者在这一章中,举了一个例子:

2019 年的时候 Lodash 库爆出过一个原型污染漏洞,叫做 CEV-2019-10744

这个漏洞主要存在于 LodashdefaultsDeep 方法中,这个方法会将第二个参数的可枚举属性合并到第一个参数的属性上。

但是如果我们按照这样的方式传递参数的话,就会出现原型污染的问题

速读《现代 JavaScript 库开发》,快速掌握前端基础库开发逻辑 而要想理解什么是原型污染,大家需要首先搞清楚 JS 中原型链的概念,我在这里截了一张图:

速读《现代 JavaScript 库开发》,快速掌握前端基础库开发逻辑

这张图描述了 JS 中原型链的逻辑。

由此可知一旦我们修改了顶层的原型对象,那么就会响应到所有的底层对象实例。

而如果想要避免这种问题的出现,那么作者给出了 4 种方案:

  1. 利用 Object.freeze 冻结 Object.prototype
  2. 规避不安全的递归
  3. 利用 Object.create(null) 规避,因为这样实例不会连接到 Object.prototype.
  4. 利用 Map 代替 {},从而避免原型链接的问题

除此之外,作者还在本章中提到了 依赖的安全性问题 的问题,所谓的依赖安全性指的是 你的库所依赖的其他库,是否是安全的。

作者给我们提供了 4 个维度,来尽量保证依赖安全性:

  • 首先第一点是:尽量选择 star 多issue 少,且处理及时 的库,进行依赖。
  • 第二是:对库依赖的区分,主要说明了 dependencies:生产与开发环境、devDependencies:开发环境、peerDependencies:库依赖于其他的库 三者之间的区别
  • 第三是版本区分:依赖库版本号和前缀的概念
  • 最后是一个安全检查的命令 安全检查:npm audit

最后在本章中,作者还介绍了一些 防护意外 的处理逻辑,所谓的意外防护指的是 避免使用者修改库内部的属性,大体分为三类:

  • 不相关的功能不应该对外暴露
  • 最小的参数设计
  • 属性冻结

第七章总结

那么到这里为止,库开发的注意事项与风险点,咱们就说的差不多了。

第八章 - 第十一章

在第八章到第十一章的内容中,作者主要介绍了 9 个基础库的实现,所以这 4 个章节可以被叫做 实战 环节。

实战环节中,涉及到了大量的代码内容,其中理论相关的东西就比较少了。

如果大家对这一块的代码比较感兴趣的话,那么可以看一下具体书中所写的内容。

总结

OK,那么到这里咱们整个的《现代 JavaScript 库开发》就已经全部说完了。

《现代 JavaScript 库开发》 是一个非常适合想要开发开源库的同学进行学习的书籍。里面涉及到的很多内容,会让刚进入该领域的同学少走很多的弯路。

转载自:https://juejin.cn/post/7206732474113409079
评论
请登录