前言
我们先来思考一个问题:什么是 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、yarn、pnpm 等,这里以 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 包?
- 首先,你需要注册一个 npm 账户。
如果注册时无法获取验证码,请确保能科学上网;如果验证码多次验证不通过,可以尝试在手机注册。
- 在终端中执行如下命令登录
npm login
- 在终端中执行如下命令发布 npm 包
npm publish
如果命令执行出现错误,提示没有权限:
可能是因为包名已存在:
总结
这一章主要介绍了 npm 包以及如何创建并发布 npm 包,下一章将会尝试接入前端构建工具,以优化开发体验并解决一些痛点问题。
附录
示例代码的 Github 仓库:github.com/lujunji4113…
示例 npm 包:www.npmjs.com/package/my-…