前言

在开始本文之前,我假设你已经懂了什么是 npm、ts、且有了少许的 React 开发经验。那么在本文中,你将学到怎么将自己开发的 React 组件打包,发布到 npm 上,并在别的项目中下载引用。

文内的图片已经不可用,不想补

先介绍打包工具 rollup

如果你使用过 Webpack,那么你应该对打包工具有了初步的认识。不过在本文中,对于组件的打包我们不使用 Webpack,而是 rollup。虽然都是打包工具,但是也各有各的使用场景,rollup 更适合组件库的打包,它会使用 ES6 的模块系统,摇树优化掉不需要的代码,做到极致的压缩体积。

rollup 中文官网

虽然 rollup 可以使用命令行,但是配置的参数一多,命令行就不好用了,所以推荐使用配置文件的方式来运行 rollup。

示例组件

需要的配置是根据项目的需求来定的。本文将会使用 rollup 来打包一个 React 组件,会介绍相关的配置。

我写了一个简单的 React 组件,把它 clone 到本地,我将用它来掩饰如何使用 rollup 打包。

到这里 clone apple-box

组件的效果图如下:

image.png

clone 下来后,你会看到这样的文件结构:

image.png

首先看 package.json 文件里的 main 节点,指向了 src/index.tsx。在我们 install 这个组件后,这个节点指向的文件将成为导入的入口。导入组件就是导入这个文件:

//  导入这个组件,就是导入 main 节点的文件
import { AppleBox } from "dvorakchen-s-apple-box";

这份源码,我们已经可以直接发布到 npm 了。

第一次发布

发布有两个条件:

  1. 你需要拥有一个 npm 账号,自己去 npm 官网上注册一个
  2. 要发布的项目,package 下的 name 节点不能重复,这个节点的值是你的包名,不能和其他已有的 npm 包重复。

源码里的包名是 dvorakchen-s-apple-box,你要改成自己的名字,因为这个名字已经被我用了。

接着,你需要在项目根目录下启动终端,输入 npm login 登录你的 npm 账号,登录后再输入 npm publish 就能够发布到 npm 上了。你能够在你的 npm 库里找到你发布的库。

第一次发布的问题

先使用 npm i <package> 在导入你刚刚发布的包,然后在 node_modules 中找到这个包,此时的文件应该是像下面一样的:

image.png

在右侧还中打开了库的入口文件 index.tsx

能够看见文件夹下有个 images 文件夹,里面有一张不需要用到图片。我们使用这个组件的时候并不需要这个图片,所以我们希望发布到 npm 上的时候忽略掉不需要用到的文件,不然可能导致导入的库包含了许多无意义的文件,体积太大。

为了解决这个问题,只需要在组件库的根目录下新建一个 .npmignore 文件,将我们不需要的文件写进去即可。在示例组件的源码里,我已经写好了一个 .npmignore,打开看,内容如下:

image.png

写法跟 .gitignore 一样的,比如上面就是在发布的时候忽略 node_modules 文件夹,.babelrcrollup.config.jstsconfig.json 文件。你能够看到 images 文件夹不在其中,所以发布的时候把 images 也发布上去了。现在在 .npmignore 里加上 images/,然后修改 package.json 里的版本号为 "version": "1.0.1"。因为我们待会要发布更新后的库,必须更新版本号。

在终端里输入:npm publish 发布修改过后的库,这次因为已经登录过了,所以不需要再登录。

发布后在项目里 install 最新的你刚刚发布的组件,最新的版本号应该是刚刚修改后的 1.0.1。这个时候再看导入的组件文件,就没有了不需要的 images 文件夹:

image.png

README.md 文件和 package.json 文件是需要上传的。

第二次发布的问题

在第一次发布中,我们发现了不需要发布的文件,通过使用 .npmignore 忽略了这些不需要的文件,减少了发布的体积。但是如果仔细思考下,还能够发现我们发布上去的是源码,这些源码还可以再压缩,进一步减少发布的体积。所以,我们要再发布前压缩代码,将压缩过的代码发布上去。

这个时候,就需要我们的打包工具:Rollup 了。

使用 Rollup

一开始就说过,Rollup 很适合用于打包库之类的项目,并且推荐使用配置文件来配置 Rollup 的行为。

首先安装,如果是在全局环境中使用,就要在全局环境下安装:npm install --global rollup,或者只要在当前项目下使用,就在当前项目的依赖下安装:npm install -D rollup

然后再组件库项目的根目录下新建 rollup.config.js 文件用于配置 Rollup 的行为。

写入如下代码:

export default {
  input: "src/index.tsx",
  output: [
    {
      file: pkg.main,
      format: "cjs",
    },
    {
      file: "dist/index.esm.js",
      format: "esm",
    },
  ],
  external: [pkg.peerDependencies, pkg.dependencies],
  plugins: [],
};

我们慢慢说,首先导出的对象就是 rollup 的配置。

  • input:节点是你要打包的入口文件,rollup 会从这个文件开始,打包一系列需要的依赖。
  • output:打包好后的文件输出路径,可以输出到多个文件里。上面指定了两个输出文件,节点 file 指定输出的文件名,format 指定输出的 js 文件是使用什么模块,上面例子中分别指定了使用 CommonJS 模块(cjs)和使用 ES6 模块(esm)的两个文件。
  • external:外链,表示这个库要引用的外部的包,不会被打包进去。可以通过这个,不打包需要的依赖,而是在使用的时候再一起安装。
  • plugins:插件。我们很快就会使用到。

所以,上面的配置的意思是,打包 src/index.tsx 文件,分别使用 CommonJS 模块(cjs)和使用 ES6 模块(esm)输出到两个文件。package.jsonpeerDependenciesdependencies 的依赖都不打包,而是作为外链依赖。

打包 React 组件需要的插件

但是只靠上面的配置还不足以打包 React 组件,因为 rollup 不认识 .tsx.ts 文件,所以需要一些插件来帮助他。

总的来说,我们需要以下插件:

  • rollup-plugin-postcss:用于处理 css
  • rollup-plugin-typescript2:用于转换 ts、tsx 语法
  • @rollup/plugin-node-resolve:可以告诉 Rollup 如何查找外部模块
  • @rollup/plugin-commonjs:用来将 CommonJS 转换成 ES2015 模块
  • @rollup/plugin-json:让 Rollup 从 JSON 文件中读取数据
  • rollup-plugin-terser:最后用于混淆代码

更详细的说明可以在这里看到:Rollup 与其他工具集成

然后,我们在 Rollup 里配置这些插件:

export default {
  plugins: [
    postcss(),
    typescript(),
    resolve(),
    commonjs(),
    json(),
    terser(),
  ],
};

注意插件的顺序也是有讲究的,从上到下就是处理的顺序:先处理 css,再转换语法,再查找外部模块,再将 CommonJS 转换成 ES2015 模块,再从 JSON 文件中读取数据,最后混淆代码。

然后执行命令:rollup -c,其中 -c 是告诉 rollup 使用配置文件。执行你应该能够看到根目录下的 dist 文件夹,里面就是打包后的代码。

由于我们要发布的代码都在 dist 文件夹里,那么 src 文件夹里的源码就不需要发布了,所以将 src/ 写入 .npmignore 文件,然后在 package.json 文件里将 main 指定的入口修改为打包后的入口:"main": "dist/index.js"。因为我们又修改了这个库,所以别忘了将版本更新为 1.0.2

再次执行 npm publish 发布,然后在别的项目里 install 导入。这时我们再看 node_modules 里我们的库文件,会发现是如下形式的:

image.png

文件里也是混淆后的代码。我们成功使用 rollup 将库打包,发布到 npm 上了。

总结

本文中,我们初步学会了如何发布 npm 包,并使用 rollup 工具打包。当然 rollup 也有其他更多用法和插件,在 rollup 官网上能够找到。

参考

rollup 中文官网 by rollup