如何构建一个 JavaScript 库(第一章)

61 阅读5分钟

前言

我们先来思考一个问题:什么是 JavaScript 库?

如下是我的理解:

JavaScript 库是预先编写的 JavaScript 代码,这部分代码可以被共享,以便更轻松地开发基于 JavaScript 的应用程序。

JavaScript 库的具体表现形式会随运行环境而变化:

  • 浏览器:JavaScript 库可以是一个 JavaScript 文件,通过 <script> 标签将其直接嵌入 HTML,从而将其纳入网站。
  • Node.js:JavaScript 库可以是一个 npm 包,按照 CommonJS 模块规范或 ECMAScript 模块规范导入。
  • Deno:JavaScript 库可以是一个目录,包含多个 JavaScript 模块(文件),按照 ECMAScript 模块规范导入。
  • ......

目前前端开发中,大多数开发者使用的运行时环境还是 Node.js。我们这次将以 npm 包的形式构建 JavaScript 库,并尝试探索如下问题:

如何兼容不同的运行时环境?

如何实现 tree shaking?

如何实现子路径导出?

如何处理样式文件?

持续集成的实现?

......

npm 介绍

npm 是一个软件注册中心,开发者可以使用 npm 共享和借用软件包。

npm 有三个不同的组成部分:

  • 网站

可以使用网站发现软件包、设置配置文件并管理 npm 体验的其他方面。例如,可以设置组织来管理对公共或私有软件包的访问。

npm 命令行界面,是 Node.js 的标准包管理器。我们可以通过 npm 下载和管理包。

注册表是一个包含 JavaScript 包及其元信息的大型公共数据库。开发者本地开发了 JavaScript 包后,可以将其在 npm 注册表上注册,这样便可以将 JavaScript 包共享给其它开发者。

npm 包

什么是 npm 包?

包是由 package.json 文件描述的文件或目录。一个包必须包含 package.json 文件,才能发布到 npm 注册表。package.json 文件存储着包的元信息,必须包含 "name""version" 字段。

如何创建 npm 包?

创建 npm 包之前,我们需要先简单理解一下 package.json 文件。

package.json 文件的扩展名为 .json,文件内容是 JSON。这个文件存储了包的元信息,接下来我们就来看看,必要的字段的含义:

  • "name":包的名称。
  • "version":包的版本,格式必须是 x.x.x,并遵循语义版本准则

建议软件包版本从 1.0.0 开始,并按以下方式递增:

代码状态阶段规则示例版本
首次发布新产品从 1.0.0 开始1.0.0
向后兼容的 bug 修复补丁发布递增第三位数字1.0.1
向后兼容的新功能次要发布递增中间数字并将最后一位数字重置为零1.1.0
破坏向后兼容性的更改主要发布递增第一位数字并将中间数字和最后一位数字重置为零2.0.0

一般创建 npm 包之前,会创建一个目录,这个目录就是包的根目录。之后在根目录下创建一个 package.json 文件。可以通过包管理工具来创建 package.json 文件。常见的包管理工具有 npm、yarnpnpm 等,这里以 pnpm 示例:

首先创建包的根目录:

mkdir <rootDir> # <rootDir> 为包的根目录

然后进入包的根目录:

cd <rootDir> # <rootDir> 为包的根目录

执行如下命令,会创建一个 package.json 文件。

pnpm init

pnpm init 会以当前目录的名称作为包名,然后创建一个具有默认内容的 package.json 文件。我们来看看如下示例中各个字段的含义。

{
  "name": "starter-lib",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo "Error: no test specified" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}
  • "description":包的描述。这有助于人们发现你的软件包,因为它会被列入 npm search 中。
  • "main":main 字段是一个模块 ID,是程序的主要入口。也就是说,如果你的软件包名为 foo,用户安装后执行 require("foo") 命令,就会返回主模块的导出的对象。这应该是一个相对于软件包文件夹根目录的模块。
  • "scripts":该属性是一个字典,包含在软件包生命周期的不同时间运行的脚本命令。键是生命周期事件,值是在该时刻运行的命令。
  • "keywords":包的关键字。这是一个字符串数组。这有助于人们在 npm search 中发现你的软件包。
  • "author":包作者信息,格式为 Your Name <``email@example.com``> (``http://example.com``),其中邮箱和个人网页是可选的
  • "license":软件包的许可证,以便人们知道他们可以如何使用该软件包,以及对其设置的任何限制。

这里我们可以根据自己想要创建的包做对应的修改,如下是一个示例:

{
  "name": "starter-lib",
  "version": "1.0.0",
  "description": "A bare-bones example of how to create a library.",
  "main": "index.js",
  "scripts": {
    "test": "echo "Error: no test specified" && exit 1"
  },
  "keywords": [
    "example"
  ],
  "author": "Junji Lu <lujunji4113@gmail.com> (https://github.com/lujunji4113)",
  "license": "MIT"
}

接下来我们创建程序的主要入口,在包的根目录下创建一个 index.js 文件,文件内容如下:

function sayHello() {
  console.log("Hello, world!");
}

module.exports.sayHello = sayHello;

现在一个简单的包就创建完成了。

如何发布 npm 包?

  1. 首先,你需要注册一个 npm 账户

如果注册时无法获取验证码,请确保能科学上网;如果验证码多次验证不通过,可以尝试在手机注册。

  1. 在终端中执行如下命令登录
npm login
  1. 在终端中执行如下命令发布 npm 包
npm publish

如果命令执行出现错误,提示没有权限:

可能是因为包名已存在:

总结

这一章主要介绍了 npm 包以及如何创建并发布 npm 包,下一章将会尝试接入前端构建工具,以优化开发体验并解决一些痛点问题。

附录

示例代码的 Github 仓库:github.com/lujunji4113…

示例 npm 包:www.npmjs.com/package/my-…